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