#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)); }