#define _SHEET_C
//----------------------------------------------------------------- 
// SHEET.C - Sheet window management. 
// 
// MAKEMDI adaptation of Windows 3.1 SDK MAKEAPP system. 
// 
// MDI application design based on Chapter 7 of	 
// "Windows 3: A Developer's Guide" by Jeffrey Richter. 
// 
// Adaptation developed with permission of the author by  
// John F. Holliday, Technisoft Corporation 
// Telephone: (515) 472-9803, CompuServe: 71271,634 
//
// [DMM]	25-Nov-1992: Fixed crashing on exit
//			Also tabified file to tabsize of 4
//
//			David M. Miller, Business Visions, Inc.
//			Telephone: (212) 747-6118
//			CompuServe: 72676,327
//			internet: dmiller@hera.sbi.com
//----------------------------------------------------------------- 
#include "makemdi.h"

BOOL Sheet_Initialize(APP * papp)
//----------------------------------------------------------------- 
// Initialize all MDI child window classes. 
//----------------------------------------------------------------- 
{
	WNDCLASS		cls;

	cls.hCursor = LoadCursor(NULL, IDC_ARROW);
	cls.hIcon = NULL;
	cls.lpszMenuName = NULL;
	cls.hInstance = papp->hinst;
	cls.lpszClassName = CLASS_SHEET;
	cls.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
	cls.lpfnWndProc = Sheet_WndProc;
	cls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
	cls.cbWndExtra = sizeof(SHEET*);
	cls.cbClsExtra = 0;

	if (!RegisterClass(&cls))
		return FALSE;

	return TRUE;
}

void Sheet_Terminate(APP * papp)
{
}

LRESULT CALLBACK _export Sheet_WndProc(HWND hWnd,
									   UINT msg,
									   WPARAM wParam,
									   LPARAM lParam)
{
	SHEET *psheet = Sheet_GetPtr(hWnd);

	if (psheet == NULL) {
		if (msg == WM_NCCREATE) {
			psheet = (SHEET *) LocalAlloc(
								   LMEM_FIXED | LMEM_ZEROINIT, sizeof(SHEET));

			if (psheet == NULL)
				return 0L;

			psheet->hWnd = hWnd;
			Sheet_SetPtr(hWnd, psheet);
		}
		else {
			return Sheet_DefProc(hWnd, msg, wParam, lParam);
		}
	}


	if (msg == WM_NCDESTROY) {
		// DWORD result = HANDLE_MSG(hWnd, WM_NCDESTROY, Sheet_OnNCDestroy); 

		if (psheet->hMenu != NULL)
			DestroyMenu(psheet->hMenu);

		LocalFree((HLOCAL) OFFSETOF(psheet));
		psheet = NULL;
		Sheet_SetPtr(hWnd, NULL);

		// return result; 
	}


	switch (msg) {
		HANDLE_MSG(psheet, WM_CREATE, Sheet_OnCreate);
		HANDLE_MSG(psheet, WM_MDIACTIVATE, Sheet_OnMdiActivate);
		HANDLE_MSG(psheet, WM_MOUSEACTIVATE, Sheet_OnMouseActivate);
		HANDLE_MSG(psheet, WM_ENTERIDLE, Sheet_OnEnterIdle);
		HANDLE_MSG(psheet, WM_MENUSELECT, Sheet_OnMenuSelect);
		HANDLE_MSG(psheet, WM_SETCURSOR, Sheet_OnSetCursor);
		HANDLE_MSG(psheet, WM_LBUTTONDOWN, Sheet_OnLButtonDown);
		HANDLE_MSG(psheet, WM_CLOSE, Sheet_OnClose);
		HANDLE_MSG(psheet, WM_DESTROY, Sheet_OnDestroy);
		HANDLE_MSG(psheet, WM_PAINT, Sheet_OnPaint);
		HANDLE_MSG(psheet, WM_ERASEBKGND, Sheet_OnEraseBkgnd);
		HANDLE_MSG(psheet, WM_QUERYENDSESSION, Sheet_OnQueryEndSession);
		HANDLE_MSG(psheet, WM_ENDSESSION, Sheet_OnEndSession);
		HANDLE_MSG(psheet, WM_COMMAND, Sheet_OnCommand);

		// Application messages. 

		HANDLE_MSG(psheet, AC_PAINTSTATBAR, Sheet_OnPaintStatBar);
		HANDLE_MSG(psheet, AW_PAINTMENUHELP, Sheet_OnPaintMenuHelp);

	default:
		return Sheet_DefProc(hWnd, msg, wParam, lParam);
	}
}

typedef struct {
	LPCSTR			lpszText;
	COLORREF		clrText;
}
SHEET_INIT;

HWND Sheet_CreateWindow(HWND hWndParent, int x, int y, int cx, int cy, BOOL fVisible, COLORREF clrText, LPCSTR lpszText)
{
	SHEET_INIT		init;

	init.lpszText = lpszText;
	init.clrText = clrText;

	return CreateWindowEx(
							 0L,		// extendedStyle 
							 CLASS_SHEET,		// class name 
							 NULL,		// text 
							 (fVisible ? (WS_CHILD | WS_VISIBLE) : WS_CHILD),
							 x, y, cx, cy,		// x, y, cx, cy 
							 hWndParent,// hWndParent 
							 NULL,		// hmenu 
							 g_app.hinst,		// hInstance 
							 &init);	// lpCreateParams 
}

BOOL Sheet_OnCreate(SHEET * psheet, CREATESTRUCT FAR * lpCreateStruct)
{
	SHEET_INIT FAR *pinit = (SHEET_INIT FAR *) lpCreateStruct->lpCreateParams;

	psheet->lpszText = pinit->lpszText;
	psheet->clrText = pinit->clrText;

	// If this window is first instance created of this class. 

	if (psheet->hMenu == NULL) {
		// Initialize the menu and accelerator handles for this class. 

		psheet->hMenu = LoadMenu(g_app.hinst, MAKEINTRESOURCE(IDR_SHEETMENU));
		psheet->hAccelTable = LoadAccelerators(g_app.hinst, MAKEINTRESOURCE(IDR_SHEETACCEL));
	}

	return TRUE;
}

void Sheet_OnMdiActivate(SHEET * psheet, BOOL fBeingActivated, HWND hWndChild, HWND hWndPrevChild)
{
	if (fBeingActivated) {
		// Child is being activated. 

		psheet->hWndPrevChild = hWndPrevChild;

		// If this child is being activated and no other child exists, 
		// pretend that this child was the last activated child. 

		if (psheet->hWndPrevChild == NULL)
			psheet->hWndPrevChild = psheet->hWnd;

		// Set the menu bar and the accelerators to the appropriate ones 
		// for this window class. 

		Frame_ChangeMDIMenu(
							   GETFRAME(psheet->hWnd),
							   GetParent(psheet->hWnd),
							   psheet->hMenu,
							   CMD_WINDOWTILEVERT);

		g_app.hAccelTable = psheet->hAccelTable;

		// For the Status bar at the bottom of the Frame window to be  
		// updated for this child's information. 

		InvalidateRect(GETFRAME(psheet->hWnd), NULL, TRUE);
	}
	else {
		// Child is being deactivated. 
		// Reset the previous child so WM_MOUSEACTIVATE will work Ok. 

		psheet->hWndPrevChild = NULL;
	}
}

int Sheet_OnMouseActivate(SHEET * psheet, HWND hWndTopLevel, UINT codeHitTest, UINT msg)
//----------------------------------------------------------------- 
// User clicked the mouse of the Child window. 
// If the mouse is clicked in the window's client area and	
// the previously active child was NOT this child, the 
// mouse message should be eaten. 
//----------------------------------------------------------------- 
{
	if ((codeHitTest == HTCLIENT) &&
			(psheet->hWnd != psheet->hWndPrevChild))
		return MA_ACTIVATEANDEAT;

	return MA_ACTIVATE;
}

void Sheet_OnEnterIdle(SHEET * psheet, UINT source, HWND hWndSource)
//----------------------------------------------------------------- 
// User stopped moving around in the help system, make the Frame 
// believe that it received this message directly. 
//----------------------------------------------------------------- 
{
	FORWARD_WM_ENTERIDLE(GETFRAME(psheet->hWnd), source, hWndSource, SendMessage);
}

void Sheet_OnMenuSelect(SHEET * psheet, HMENU hMenu, int item, HMENU hMenuPopup, UINT flags)
//----------------------------------------------------------------- 
// Normally, only MDI Child system menu options could appear 
// in this message.	 But the Frame window forces WM_MENUSELECT 
// messages to appear here whenever a menu selection occurs. 
//----------------------------------------------------------------- 
{
	WORD			wTemp;
	HMENU			hMenuFrame;

	if (flags == -1 && (hMenu == (HMENU) 0)) {
		// User has stopped using the menu system.	Notify Frame window 
		// so that the status bar will be invalidated. 

		SendMessage(GETFRAME(psheet->hWnd), FW_SETMENUHELP, 0, 0);
		return;
	}

	switch (flags & (MF_POPUP | MF_SYSMENU)) {
	case 0:
		// Item is a menu item ID NOT on the Child's system menu. 
		// If item is any of the MDI Children listed in the	 
		// "Window" menu, display the same help text. 

		if ((item > CMD_WINDOWCHILD) && (item <= CMD_WINDOWCHILD + 9))
			item = CMD_WINDOWCHILD;

		wTemp = IDS_SHEETMENUID + item;
		break;

	case MF_POPUP:
		// Calculate the index of the top-level menu. 

		hMenuFrame = GetMenu(GETFRAME(psheet->hWnd));
		wTemp = GetMenuItemCount(hMenuFrame);

		while (wTemp--)
			if (GetSubMenu(hMenuFrame, wTemp) == hMenuPopup)
				break;

		wTemp += IDS_SHEETPOPUPID;

		if (!IsZoomed(psheet->hWnd))
			wTemp++;
		break;

	case MF_SYSMENU:
		// Item is menu item ID from MDI Child's system menu. 

		wTemp = IDS_SHEETMENUID + ((item & 0x0FFF) >> 4);
		break;

	case MF_POPUP | MF_SYSMENU:
		// Item is handle to MDI Child's sys menu. 

		wTemp = IDS_SHEETPOPUPID;
		break;
	}

	// Tell the Frame that this window should display the help 
	// text and the identifier for the help text. 

	SendMessage(GETFRAME(psheet->hWnd), FW_SETMENUHELP,
				(WPARAM) psheet->hWnd, (LPARAM) wTemp);
}

BOOL Sheet_OnSetCursor(SHEET * psheet, HWND hWndCursor, UINT codeHitTest, UINT msg)
//----------------------------------------------------------------- 
// After an MDI Child becomes active, set the previously active 
// child to this window so that mouse messages will NOT be eaten. 
//----------------------------------------------------------------- 
{
	psheet->hWndPrevChild = psheet->hWnd;
	return FORWARD_WM_SETCURSOR(psheet->hWnd, hWndCursor, codeHitTest, msg, Sheet_DefProc);
}

void Sheet_OnLButtonDown(SHEET * psheet, BOOL fDoubleClick, int x, int y, UINT keyFlags)
//----------------------------------------------------------------- 
// Just to let you know when the WM_LBUTTONDOWN message is received. 
//----------------------------------------------------------------- 
{
	MessageBox(psheet->hWnd, "WM_LBUTTONDOWN", "Sheet", MB_OK);
}

void Sheet_OnClose(SHEET * psheet)
//----------------------------------------------------------------- 
// Make sure that it is OK to close this child window. 
//----------------------------------------------------------------- 
{
	if ((BOOL) SendMessage(psheet->hWnd, WM_QUERYENDSESSION, 0, 0)) {
		SendMessage(psheet->hWnd, WM_ENDSESSION, TRUE, 0);
		FORWARD_WM_CLOSE(psheet->hWnd, Sheet_DefProc);
	}
}

void Sheet_OnDestroy(SHEET * psheet)
//----------------------------------------------------------------- 
// Notify the Frame window that a child has been destroyed after  
// the child is actually destroyed.	 (That's why we use 
// PostMessage instead of SendMessage here). 
//----------------------------------------------------------------- 
{
	PostMessage(GETFRAME(psheet->hWnd), FW_MDICHILDDESTROY, (WPARAM) psheet->hWnd, 0);
	FORWARD_WM_DESTROY(psheet->hWnd, Sheet_DefProc);
}

void Sheet_OnPaint(SHEET * psheet)
//----------------------------------------------------------------- 
//----------------------------------------------------------------- 
{
	PAINTSTRUCT		ps;
	HDC				hdc;
	RECT			rc;

	hdc = BeginPaint(psheet->hWnd, &ps);

	GetClientRect(psheet->hWnd, &rc);
	FillRect(hdc, &rc, GetStockBrush(WHITE_BRUSH));
	InflateRect(&rc, -4, -4);
	FrameRect(hdc, &rc, GetStockBrush(BLACK_BRUSH));

	if (psheet->lpszText) {
		int				cch = lstrlen(psheet->lpszText);
		int				x;
		int				y;
		SIZE			size;

		GetTextExtentPoint(hdc, psheet->lpszText, cch, &size);

		x = rc.left + (rc.right - rc.left - size.cx) / 2;
		y = rc.top + (rc.bottom - rc.top - size.cy) / 2;

		SetTextColor(hdc, psheet->clrText);
		TextOut(hdc, x, y, psheet->lpszText, cch);
	}

	EndPaint(psheet->hWnd, &ps);
}

BOOL Sheet_OnEraseBkgnd(SHEET * psheet, HDC hdc)
//----------------------------------------------------------------- 
// Let DefWindowProc erase the background 
//----------------------------------------------------------------- 
{
	return FORWARD_WM_ERASEBKGND(psheet->hWnd, hdc, DefWindowProc);
}

BOOL Sheet_OnQueryEndSession(SHEET * psheet)
//----------------------------------------------------------------- 
//----------------------------------------------------------------- 
{
	WORD			wTemp;
	BOOL			fOkToQuit = FALSE;

	// Prompt user whether to save changes to this document. 
	// Usually, a dirty flag (stored in the window's extra bytes 
	// is used to determine if it is necessary to ask this question). 

	// Construct string including the document's name. 

	lstrcpy(g_app.szBuf, "Save changes to ");
	wTemp = lstrlen(g_app.szBuf);
	GetWindowText(psheet->hWnd, g_app.szBuf + wTemp,
				  sizeof(g_app.szBuf) - wTemp);
	lstrcat(g_app.szBuf, "?");

	// Display message box to user.	 The message box should	 
	// be system modal if the entire Windows session is being  
	// terminated. (wParam is FALSE). 

	switch (
			   MessageBox(
							 psheet->hWnd,
							 g_app.szBuf,
							 g_app.szName,
							 MB_ICONQUESTION | MB_YESNOCANCEL |
							 MB_APPLMODAL)) {
	case IDYES:
		// Save the document and it's OK to quit. 
		fOkToQuit = TRUE;
		break;

	case IDNO:
		// Don't save the document and it's OK to quit. 
		fOkToQuit = TRUE;
		break;
	}

	return fOkToQuit;
}

void Sheet_OnEndSession(SHEET * psheet, BOOL fEnding)
//----------------------------------------------------------------- 
// Do any last minute cleanup during this message. 
//----------------------------------------------------------------- 
{
}

void Sheet_OnCommand(SHEET * psheet, int id, HWND hWndCtl, UINT codeNotify)
//----------------------------------------------------------------- 
// Any menu options NOT processed by the Frame are passed to the 
// active child. 
//----------------------------------------------------------------- 
{
	MessageBox(psheet->hWnd, "Option not implemented.", g_app.szName, MB_OK);
}

void Sheet_OnPaintStatBar(SHEET * psheet, HDC hdc, LPPAINTSTRUCT psStatus)
//----------------------------------------------------------------- 
// Message sent by the Frame window when the status bar needs to  
// be repainted. 
//----------------------------------------------------------------- 
{
	// Construct status bar string for display. 

	LoadString(g_app.hinst, IDS_SHEETSTATUSBAR, g_app.szBuf, sizeof(g_app.szBuf));

	// Draw the horizontal dividing line separating the Status bar 
	// from the MDICLIENT window. 

	psStatus->rcPaint.top += (int)
			SendMessage(GETFRAME(psheet->hWnd), FW_DRAWSTATUSDIVIDE, 0,
						(LPARAM) psStatus);

	// Paint the text in the status bar. 

	TextOut(hdc, 0, psStatus->rcPaint.top, g_app.szBuf, lstrlen(g_app.szBuf));
}

void Sheet_OnPaintMenuHelp(SHEET * psheet, LPPAINTSTRUCT psStatus)
//----------------------------------------------------------------- 
// Message sent from Frame window to notify child that it should 
// paint the status bar text for the last highlighted menu item. 
// lParam = LPPAINTSTRUCT of Frame's status bar. 
//----------------------------------------------------------------- 
{
	LRESULT			lResult;

	// Ask the Frame window what the last selected menu ID was. 
	// This value was sent to the frame by this window during the  
	// processing for the WM_MENUSELECT message. 

	lResult = SendMessage(GETFRAME(psheet->hWnd), FW_GETMENUHELP, 0, 0);

	// Draw the horizontal dividing line separating the Status bar 
	// from the MDICLIENT window. 

	psStatus->rcPaint.top += (int)
			SendMessage(GETFRAME(psheet->hWnd), FW_DRAWSTATUSDIVIDE, 0,
						(LPARAM) psStatus);

	// Construct the string that is to be displayed. 

	LoadString(g_app.hinst, LOWORD(lResult), g_app.szFmt, sizeof(g_app.szFmt));
	GetWindowText(psheet->hWnd, g_app.szCap, sizeof(g_app.szCap));
	wsprintf(g_app.szBuf, g_app.szFmt, (LPSTR) g_app.szCap);

	// Paint the menu help text in the status bar. 

	TextOut(psStatus->hdc,
			0, psStatus->rcPaint.top, g_app.szBuf, lstrlen(g_app.szBuf));
}
