#define _CHART_C
//----------------------------------------------------------------- 
// CHART.C - Chart 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			Chart_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_CHART;
	cls.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
	cls.lpfnWndProc = Chart_WndProc;
	cls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
	cls.cbWndExtra = sizeof(CHART*);
	cls.cbClsExtra = 0;

	if (!RegisterClass(&cls))
		return FALSE;

	return TRUE;
}



void			Chart_Terminate(APP * papp)
{
}




LRESULT CALLBACK _export Chart_WndProc(HWND hWnd,
									   UINT msg,
									   WPARAM wParam,
									   LPARAM lParam)
{
	CHART	*pchart = Chart_GetPtr(hWnd);

	if (pchart == NULL) {
		if (msg == WM_NCCREATE) {
			pchart = (CHART *) LocalAlloc(LPTR, sizeof(CHART));

			if (pchart == NULL)
				return 0L;

			pchart->hWnd = hWnd;
			Chart_SetPtr(hWnd, pchart);
		}
		else {
			return Chart_DefProc(hWnd, msg, wParam, lParam);
		}
	}


	if (msg == WM_NCDESTROY) {
		// DWORD result = HANDLE_MSG(hWnd, WM_NCDESTROY, Chart_OnNCDestroy); 

		if (pchart->hMenu != NULL)
			DestroyMenu(pchart->hMenu);

		LocalFree((HLOCAL) OFFSETOF(pchart));
		pchart = NULL;
		Chart_SetPtr(hWnd, NULL);

		// return result; 
	}


	switch (msg) {
		HANDLE_MSG(pchart, WM_CREATE, Chart_OnCreate);
		HANDLE_MSG(pchart, WM_MDIACTIVATE, Chart_OnMdiActivate);
		HANDLE_MSG(pchart, WM_MOUSEACTIVATE, Chart_OnMouseActivate);
		HANDLE_MSG(pchart, WM_ENTERIDLE, Chart_OnEnterIdle);
		HANDLE_MSG(pchart, WM_MENUSELECT, Chart_OnMenuSelect);
		HANDLE_MSG(pchart, WM_SETCURSOR, Chart_OnSetCursor);
		HANDLE_MSG(pchart, WM_LBUTTONDOWN, Chart_OnLButtonDown);
		HANDLE_MSG(pchart, WM_CLOSE, Chart_OnClose);
		HANDLE_MSG(pchart, WM_DESTROY, Chart_OnDestroy);
		HANDLE_MSG(pchart, WM_PAINT, Chart_OnPaint);
		HANDLE_MSG(pchart, WM_ERASEBKGND, Chart_OnEraseBkgnd);
		HANDLE_MSG(pchart, WM_QUERYENDSESSION, Chart_OnQueryEndSession);
		HANDLE_MSG(pchart, WM_ENDSESSION, Chart_OnEndSession);
		HANDLE_MSG(pchart, WM_COMMAND, Chart_OnCommand);

		// Application messages. 

		HANDLE_MSG(pchart, AC_PAINTSTATBAR, Chart_OnPaintStatBar);
		HANDLE_MSG(pchart, AW_PAINTMENUHELP, Chart_OnPaintMenuHelp);

	default:
		return Chart_DefProc(hWnd, msg, wParam, lParam);
	}
}



typedef struct {
	LPCSTR			lpszText;
	COLORREF		clrText;
}				CHART_INIT;




HWND			Chart_CreateWindow(HWND hWndParent, int x, int y, int cx, int cy, BOOL fVisible, COLORREF clrText, LPCSTR lpszText)
{
	CHART_INIT		init;

	init.lpszText = lpszText;
	init.clrText = clrText;

	return CreateWindowEx(
							 0L,		// extendedStyle 
							 CLASS_CHART,		// 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			Chart_OnCreate(CHART * pchart, CREATESTRUCT FAR * lpCreateStruct)
{
	CHART_INIT FAR *pinit = (CHART_INIT FAR *) lpCreateStruct->lpCreateParams;

	pchart->lpszText = pinit->lpszText;
	pchart->clrText = pinit->clrText;

	// If this window is first instance created of this class. 

	if (pchart->hMenu == NULL) {
		// Initialize the menu and accelerator handles for this class. 

		pchart->hMenu = LoadMenu(g_app.hinst, MAKEINTRESOURCE(IDR_CHARTMENU));
		pchart->hAccelTable = LoadAccelerators(g_app.hinst, MAKEINTRESOURCE(IDR_CHARTACCEL));
	}

	return TRUE;
}



void			Chart_OnMdiActivate(CHART * pchart, BOOL fBeingActivated, HWND hWndChild, HWND hWndPrevChild)
{
	if (fBeingActivated) {
		// Child is being activated. 

		pchart->hWndPrevChild = hWndPrevChild;

		// If this child is being activated and no other child exists, 
		// pretend that this child was the last activated child. 

		if (pchart->hWndPrevChild == NULL)
			pchart->hWndPrevChild = pchart->hWnd;

		// Set the menu bar and the accelerators to the appropriate ones 
		// for this window class. 

		Frame_ChangeMDIMenu(
							   GETFRAME(pchart->hWnd),
							   GetParent(pchart->hWnd),
							   pchart->hMenu,
							   CMD_WINDOWTILEVERT);

		g_app.hAccelTable = pchart->hAccelTable;

		// For the Status bar at the bottom of the Frame window to be  
		// updated for this child's information. 

		InvalidateRect(GETFRAME(pchart->hWnd), NULL, TRUE);
	}
	else {
		// Child is being deactivated. 
		// Reset the previous child so WM_MOUSEACTIVATE will work Ok. 

		pchart->hWndPrevChild = NULL;
	}
}




int				Chart_OnMouseActivate(CHART * pchart, 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) &&
			(pchart->hWnd != pchart->hWndPrevChild))
		return MA_ACTIVATEANDEAT;

	return MA_ACTIVATE;
}



void			Chart_OnEnterIdle(CHART * pchart, 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(pchart->hWnd), source, hWndSource, SendMessage);
}



void			Chart_OnMenuSelect(CHART * pchart, 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(pchart->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_CHARTMENUID + item;
		break;

	case MF_POPUP:
		// Calculate the index of the top-level menu. 

		hMenuFrame = GetMenu(GETFRAME(pchart->hWnd));
		wTemp = GetMenuItemCount(hMenuFrame);

		while (wTemp--)
			if (GetSubMenu(hMenuFrame, wTemp) == hMenuPopup)
				break;

		wTemp += IDS_CHARTPOPUPID;

		if (!IsZoomed(pchart->hWnd))
			wTemp++;
		break;

	case MF_SYSMENU:
		// Item is menu item ID from MDI Child's system menu. 

		wTemp = IDS_CHARTMENUID + ((item & 0x0FFF) >> 4);
		break;

	case MF_POPUP | MF_SYSMENU:
		// Item is handle to MDI Child's sys menu. 

		wTemp = IDS_CHARTPOPUPID;
		break;
	}

	// Tell the Frame that this window should display the help 
	// text and the identifier for the help text. 

	SendMessage(GETFRAME(pchart->hWnd), FW_SETMENUHELP,
				(WPARAM) pchart->hWnd, (LPARAM) wTemp);
}




BOOL			Chart_OnSetCursor(CHART * pchart, 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. 
//----------------------------------------------------------------- 
{
	pchart->hWndPrevChild = pchart->hWnd;
	return FORWARD_WM_SETCURSOR(pchart->hWnd, hWndCursor, codeHitTest, msg, Chart_DefProc);
}



void			Chart_OnLButtonDown(CHART * pchart, BOOL fDoubleClick, int x, int y, UINT keyFlags)
//----------------------------------------------------------------- 
// Just to let you know when the WM_LBUTTONDOWN message is received. 
//----------------------------------------------------------------- 
{
	MessageBox(pchart->hWnd, "WM_LBUTTONDOWN", "Chart", MB_OK);
}



void			Chart_OnClose(CHART * pchart)
//----------------------------------------------------------------- 
// Make sure that it is OK to close this child window. 
//----------------------------------------------------------------- 
{
	if ((BOOL) SendMessage(pchart->hWnd, WM_QUERYENDSESSION, 0, 0)) {
		SendMessage(pchart->hWnd, WM_ENDSESSION, TRUE, 0);
		FORWARD_WM_CLOSE(pchart->hWnd, Chart_DefProc);
	}
}




void			Chart_OnDestroy(CHART * pchart)
//----------------------------------------------------------------- 
// 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(pchart->hWnd), FW_MDICHILDDESTROY, (WPARAM) pchart->hWnd, 0);
	FORWARD_WM_DESTROY(pchart->hWnd, Chart_DefProc);
}




void			Chart_OnPaint(CHART * pchart)
//----------------------------------------------------------------- 
//----------------------------------------------------------------- 
{
	PAINTSTRUCT		ps;
	HDC				hdc;
	RECT			rc;

	hdc = BeginPaint(pchart->hWnd, &ps);

	GetClientRect(pchart->hWnd, &rc);
	FillRect(hdc, &rc, GetStockBrush(WHITE_BRUSH));
	InflateRect(&rc, -4, -4);
	FrameRect(hdc, &rc, GetStockBrush(BLACK_BRUSH));

	if (pchart->lpszText) {
		int				cch = lstrlen(pchart->lpszText);
		int				x;
		int				y;
		SIZE			size;

		GetTextExtentPoint(hdc, pchart->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, pchart->clrText);
		TextOut(hdc, x, y, pchart->lpszText, cch);
	}

	EndPaint(pchart->hWnd, &ps);
}





BOOL			Chart_OnEraseBkgnd(CHART * pchart, HDC hdc)
//----------------------------------------------------------------- 
// Let DefWindowProc erase the background 
//----------------------------------------------------------------- 
{
	return FORWARD_WM_ERASEBKGND(pchart->hWnd, hdc, DefWindowProc);
}




BOOL			Chart_OnQueryEndSession(CHART * pchart)
//----------------------------------------------------------------- 
//----------------------------------------------------------------- 
{
	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(pchart->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(
							 pchart->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			Chart_OnEndSession(CHART * pchart, BOOL fEnding)
//----------------------------------------------------------------- 
// Do any last minute cleanup during this message. 
//----------------------------------------------------------------- 
{
}




void			Chart_OnCommand(CHART * pchart, int id, HWND hWndCtl, UINT codeNotify)
//----------------------------------------------------------------- 
// Any menu options NOT processed by the Frame are passed to the 
// active child. 
//----------------------------------------------------------------- 
{
	MessageBox(pchart->hWnd, "Option not implemented.", g_app.szName, MB_OK);
}




void			Chart_OnPaintStatBar(CHART * pchart, 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_CHARTSTATUSBAR, 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(pchart->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			Chart_OnPaintMenuHelp(CHART * pchart, 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(pchart->hWnd), FW_GETMENUHELP, 0, 0);

	// Draw the horizontal dividing line separating the Status bar 
	// from the MDICLIENT window. 

	psStatus->rcPaint.top += (int)
			SendMessage(GETFRAME(pchart->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(pchart->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));
}
