// Win32++ Version 7.2 // Released: 5th AUgust 2011 // // David Nash // email: dnash@bigpond.net.au // url: https://sourceforge.net/projects/win32-framework // // // Copyright (c) 2005-2011 David Nash // // Permission is hereby granted, free of charge, to // any person obtaining a copy of this software and // associated documentation files (the "Software"), // to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, // merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom // the Software is furnished to do so, subject to the // following conditions: // // The above copyright notice and this permission notice // shall be included in all copies or substantial portions // of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE // OR OTHER DEALINGS IN THE SOFTWARE. // //////////////////////////////////////////////////////// //////////////////////////////////////////////////////// // frame.h // Declaration of the CFrame and CMenuBar classes // The classes declared in this file support SDI (Single Document Interface) // frames on Win32/Win64 operating systems (not Windows CE). For Windows CE, // use wceframe.h instead. SDI frames are a simple frame which supports a // single view window. Refer to mdi.h for frames that support several // child windows. // CFrame also includes each of the following classes as members: // * CReBar for managing the frame's rebar control. // * CMenuBar for managing the menu inside the rebar. // * CToolBar for managing the frame's toolbar. // * CStatusBar for managing the frame's status bar. // In each case these members are exposed by a GetXXX function, allowing // them to be accessed or sent messages. // CFrame is responsible for creating a "frame" window. This window has a // menu and and several child windows, including a toolbar (usualy hosted // within a rebar), a status bar, and a view positioned over the frame // window's non-client area. The "view" window is a seperate CWnd object // assigned to the frame with the SetView function. // When compiling an application with these classes, it will need to be linked // with Comctl32.lib. // To create a SDI frame application, inherit a CMainFrame class from CFrame. // Use the Frame sample application as the starting point for your own frame // applications. // Refer to the Notepad and Scribble samples for examples on how to use these // classes to create a frame application. #ifndef _WIN32XX_FRAME_H_ #define _WIN32XX_FRAME_H_ #include "wincore.h" #include "dialog.h" #include "gdi.h" #include "statusbar.h" #include "toolbar.h" #include "rebar.h" #include "default_resource.h" #ifndef RBN_MINMAX #define RBN_MINMAX (RBN_FIRST - 21) #endif namespace Win32xx { //////////////////////////////////////////////// // Declarations for structures for themes // struct MenuTheme { BOOL UseThemes; // TRUE if themes are used COLORREF clrHot1; // Colour 1 for top menu. Color of selected menu item COLORREF clrHot2; // Colour 2 for top menu. Color of checkbox COLORREF clrPressed1; // Colour 1 for pressed top menu and side bar COLORREF clrPressed2; // Colour 2 for pressed top menu and side bar COLORREF clrOutline; // Colour for border outline }; // Forward declaration of CFrame. Its defined later. class CFrame; //////////////////////////////////// // Declaration of the CMenuBar class // class CMenuBar : public CToolBar { friend class CFrame; public: CMenuBar(); virtual ~CMenuBar(); virtual void SetMenu(HMENU hMenu); virtual void SetMenuBarTheme(MenuTheme& Theme); HMENU GetMenu() const {return m_hTopMenu;} MenuTheme& GetMenuBarTheme() {return m_ThemeMenu;} protected: //Overridables virtual void OnCreate(); virtual LRESULT OnCustomDraw(NMHDR* pNMHDR); virtual void OnKeyDown(WPARAM wParam, LPARAM lParam); virtual void OnLButtonDown(WPARAM wParam, LPARAM lParam); virtual void OnLButtonUp(WPARAM wParam, LPARAM lParam); virtual void OnMenuChar(WPARAM wParam, LPARAM lParam); virtual BOOL OnMenuInput(UINT uMsg, WPARAM wParam, LPARAM lParam); virtual void OnMouseLeave(); virtual void OnMouseMove(WPARAM wParam, LPARAM lParam); virtual LRESULT OnNotifyReflect(WPARAM wParam, LPARAM lParam); virtual void OnSysCommand(WPARAM wParam, LPARAM lParam); virtual void OnWindowPosChanged(); virtual void PreCreate(CREATESTRUCT &cs); virtual void PreRegisterClass(WNDCLASS &wc); virtual LRESULT WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam); private: CMenuBar(const CMenuBar&); // Disable copy construction CMenuBar& operator = (const CMenuBar&); // Disable assignment operator void DoAltKey(WORD KeyCode); void DoPopupMenu(); void DrawAllMDIButtons(CDC& DrawDC); void DrawMDIButton(CDC& DrawDC, int iButton, UINT uState); void ExitMenu(); HWND GetActiveMDIChild(); void GrabFocus(); BOOL IsMDIChildMaxed() const; BOOL IsMDIFrame() const; void ReleaseFocus(); void SetHotItem(int nHot); static LRESULT CALLBACK StaticMsgHook(int nCode, WPARAM wParam, LPARAM lParam); enum MDIButtonType { MDI_MIN = 0, MDI_RESTORE = 1, MDI_CLOSE = 2, }; BOOL m_bExitAfter; // Exit after Popup menu ends BOOL m_bKeyMode; // keyboard navigation mode BOOL m_bMenuActive; // popup menu active BOOL m_bSelPopup; // a popup (cascade) menu is selected HMENU m_hPopupMenu; // handle to the popup menu HMENU m_hSelMenu; // handle to the casceded popup menu HMENU m_hTopMenu; // handle to the top level menu HWND m_hPrevFocus; // handle to window which had focus CRect m_MDIRect[3]; // array of CRect for MDI buttons int m_nHotItem; // hot item int m_nMDIButton; // the MDI button (MDIButtonType) pressed CPoint m_OldMousePos; // old Mouse position MenuTheme m_ThemeMenu; // Theme structure CFrame* m_pFrame; // Pointer to the frame }; // class CMenuBar ////////////////////////////////// // Declaration of the CFrame class // class CFrame : public CWnd { friend class CMenuBar; struct ItemData // Each Dropdown menu item has this data { HMENU hMenu; UINT nPos; UINT fType; std::vector vItemText; HMENU hSubMenu; ItemData() : hMenu(0), nPos(0), fType(0), hSubMenu(0) { vItemText.assign(MAX_MENU_STRING, _T('\0')); } LPTSTR GetItemText() {return &vItemText[0];} }; typedef Shared_Ptr ItemDataPtr; public: CFrame(); virtual ~CFrame(); // Override these functions as required virtual void AdjustFrameRect(RECT rcView) const; virtual CRect GetViewRect() const; virtual BOOL IsMDIFrame() const { return FALSE; } virtual void SetStatusIndicators(); virtual void SetStatusText(); virtual void RecalcLayout(); virtual MenuTheme& GetMenuTheme() const { return (MenuTheme&) m_ThemeMenu; } virtual ReBarTheme& GetReBarTheme() const { return (ReBarTheme&)GetReBar().GetReBarTheme(); } virtual ToolBarTheme& GetToolBarTheme() const { return (ToolBarTheme&)GetToolBar().GetToolBarTheme(); } // Virtual Attributes // If you need to modify the default behaviour of the menubar, rebar, // statusbar or toolbar, inherit from those classes, and override // the following attribute functions. virtual CMenuBar& GetMenuBar() const { return (CMenuBar&)m_MenuBar; } virtual CReBar& GetReBar() const { return (CReBar&)m_ReBar; } virtual CStatusBar& GetStatusBar() const { return (CStatusBar&)m_StatusBar; } virtual CToolBar& GetToolBar() const { return (CToolBar&)m_ToolBar; } // These functions aren't virtual, and shouldn't be overridden HACCEL GetFrameAccel() const { return m_hAccel; } CMenu& GetFrameMenu() const { return (CMenu&)m_Menu; } std::vector GetMRUEntries() const { return m_vMRUEntries; } tString GetRegistryKeyName() const { return m_tsKeyName; } CWnd* GetView() const { return m_pView; } tString GetMRUEntry(UINT nIndex); void SetFrameMenu(INT ID_MENU); void SetFrameMenu(HMENU hMenu); void SetMenuTheme(MenuTheme& Theme); void SetView(CWnd& wndView); BOOL IsMenuBarUsed() const { return (GetMenuBar() != 0); } BOOL IsReBarSupported() const { return (GetComCtlVersion() >= 470); } BOOL IsReBarUsed() const { return (GetReBar() != 0); } protected: // Override these functions as required virtual BOOL AddMenuIcon(int nID_MenuItem, HICON hIcon, int cx = 16, int cy = 16); virtual UINT AddMenuIcons(const std::vector& MenuData, COLORREF crMask, UINT ToolBarID, UINT ToolBarDisabledID); virtual void AddMenuBarBand(); virtual void AddMRUEntry(LPCTSTR szMRUEntry); virtual void AddToolBarBand(CToolBar& TB, DWORD dwStyle, UINT nID); virtual void AddToolBarButton(UINT nID, BOOL bEnabled = TRUE, LPCTSTR szText = 0); virtual void CreateToolBar(); virtual void DrawCheckmark(LPDRAWITEMSTRUCT pdis, CDC& DrawDC); virtual void DrawMenuIcon(LPDRAWITEMSTRUCT pdis, CDC& DrawDC, BOOL bDisabled); virtual void DrawMenuText(CDC& DrawDC, LPCTSTR ItemText, CRect& rc, COLORREF colorText); virtual int GetMenuItemPos(HMENU hMenu, LPCTSTR szItem); virtual BOOL LoadRegistrySettings(LPCTSTR szKeyName); virtual BOOL LoadRegistryMRUSettings(UINT nMaxMRU = 0); virtual void OnActivate(WPARAM wParam, LPARAM lParam); virtual void OnClose(); virtual void OnCreate(); virtual void OnDestroy(); virtual LRESULT OnDrawItem(WPARAM wParam, LPARAM lParam); virtual void OnExitMenuLoop(); virtual void OnHelp(); virtual void OnInitMenuPopup(WPARAM wParam, LPARAM lParam); virtual LRESULT OnMeasureItem(WPARAM wParam, LPARAM lParam); virtual LRESULT OnMenuChar(WPARAM wParam, LPARAM lParam); virtual void OnMenuSelect(WPARAM wParam, LPARAM lParam); virtual LRESULT OnNotify(WPARAM wParam, LPARAM lParam); virtual void OnSetFocus(); virtual void OnSysColorChange(); virtual LRESULT OnSysCommand(WPARAM wParam, LPARAM lParam); virtual void OnTimer(WPARAM wParam); virtual void OnViewStatusBar(); virtual void OnViewToolBar(); virtual void PreCreate(CREATESTRUCT& cs); virtual void PreRegisterClass(WNDCLASS &wc); virtual void RemoveMRUEntry(LPCTSTR szMRUEntry); virtual BOOL SaveRegistrySettings(); virtual void SetMenuBarBandSize(); virtual UINT SetMenuIcons(const std::vector& MenuData, COLORREF crMask, UINT ToolBarID, UINT ToolBarDisabledID); virtual void SetupToolBar(); virtual void SetTheme(); virtual void SetToolBarImages(COLORREF crMask, UINT ToolBarID, UINT ToolBarHotID, UINT ToolBarDisabledID); virtual void ShowMenu(BOOL bShow); virtual void ShowStatusBar(BOOL bShow); virtual void ShowToolBar(BOOL bShow); virtual void UpdateMRUMenu(); virtual LRESULT WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam); enum Constants { ID_STATUS_TIMER = 1, POST_TEXT_GAP = 16, // for owner draw menu item }; tString m_tsStatusText; // TCHAR std::string for status text BOOL m_bShowIndicatorStatus; // set to TRUE to see indicators in status bar BOOL m_bShowMenuStatus; // set to TRUE to see menu and toolbar updates in status bar BOOL m_bUseReBar; // set to TRUE if ReBars are to be used BOOL m_bUseThemes; // set to TRUE if themes are to be used BOOL m_bUpdateTheme; // set to TRUE to run SetThemes when theme changes BOOL m_bUseToolBar; // set to TRUE if the toolbar is used BOOL m_bUseCustomDraw; // set to TRUE to perform custom drawing on menu items BOOL m_bShowStatusBar; // A flag to indicate if the StatusBar should be displayed BOOL m_bShowToolBar; // A flag to indicate if the ToolBar should be displayed MenuTheme m_ThemeMenu; // Theme structure for popup menus HIMAGELIST m_himlMenu; // Imagelist of menu icons HIMAGELIST m_himlMenuDis; // Imagelist of disabled menu icons private: CFrame(const CFrame&); // Disable copy construction CFrame& operator = (const CFrame&); // Disable assignment operator void LoadCommonControls(); std::vector m_vMenuItemData;// vector of ItemData pointers std::vector m_vMenuIcons; // vector of menu icon resource IDs std::vector m_vMRUEntries; // Vector of tStrings for MRU entires CDialog m_AboutDialog; // Help about dialog CMenuBar m_MenuBar; // CMenuBar object CReBar m_ReBar; // CReBar object CStatusBar m_StatusBar; // CStatusBar object CToolBar m_ToolBar; // CToolBar object CMenu m_Menu; // handle to the frame menu HACCEL m_hAccel; // handle to the frame's accelerator table CWnd* m_pView; // pointer to the View CWnd object LPCTSTR m_OldStatus[3]; // Array of TCHAR pointers; tString m_tsKeyName; // TCHAR std::string for Registry key name tString m_tsTooltip; // TCHAR std::string for tool tips UINT m_nMaxMRU; // maximum number of MRU entries CRect m_rcPosition; // CRect of the starting window position HWND m_hOldFocus; // The window which had focus prior to the app'a deactivation int m_nOldID; // The previous ToolBar ID displayed in the statusbar }; // class CFrame } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ namespace Win32xx { ///////////////////////////////////// // Definitions for the CMenuBar class // inline CMenuBar::CMenuBar() { m_bExitAfter = FALSE; m_hTopMenu = NULL; m_nHotItem = -1; m_bSelPopup = FALSE; m_hSelMenu = NULL; m_bMenuActive = FALSE; m_bKeyMode = FALSE; m_hPrevFocus = NULL; m_nMDIButton = 0; m_hPopupMenu = 0; ZeroMemory(&m_ThemeMenu, sizeof(MenuTheme)); } inline CMenuBar::~CMenuBar() { } inline void CMenuBar::DoAltKey(WORD KeyCode) { //Handle key pressed with Alt held down UINT ID; if (SendMessage(TB_MAPACCELERATOR, KeyCode, (LPARAM) &ID)) { GrabFocus(); m_bKeyMode = TRUE; SetHotItem(ID); m_bMenuActive = TRUE; PostMessage(UWM_POPUPMENU, 0L, 0L); } else ::MessageBeep(MB_OK); } inline void CMenuBar::DoPopupMenu() { if (m_bKeyMode) // Simulate a down arrow key press PostMessage(WM_KEYDOWN, VK_DOWN, 0L); m_bKeyMode = FALSE; m_bExitAfter = FALSE; m_OldMousePos = GetCursorPos(); HWND hMaxMDIChild = NULL; if (IsMDIChildMaxed()) hMaxMDIChild = GetActiveMDIChild(); // Load the submenu int nMaxedOffset = IsMDIChildMaxed()? 1:0; m_hPopupMenu = ::GetSubMenu(m_hTopMenu, m_nHotItem - nMaxedOffset); if (IsMDIChildMaxed() && (0 == m_nHotItem) ) m_hPopupMenu = ::GetSystemMenu(hMaxMDIChild, FALSE); // Retrieve the bounding rectangle for the toolbar button CRect rc = GetItemRect(m_nHotItem); // convert rectangle to desktop coordinates ClientToScreen(rc); // Position popup above toolbar if it won't fit below TPMPARAMS tpm; tpm.cbSize = sizeof(TPMPARAMS); tpm.rcExclude = rc; // Set the hot button SendMessage(TB_SETHOTITEM, m_nHotItem, 0L); SendMessage(TB_PRESSBUTTON, m_nHotItem, MAKELONG(TRUE, 0)); m_bSelPopup = FALSE; m_hSelMenu = NULL; m_bMenuActive = TRUE; // We hook mouse input to process mouse and keyboard input during // the popup menu. Messages are sent to StaticMsgHook. // Remove any remaining hook first TLSData* pTLSData = (TLSData*)::TlsGetValue(GetApp()->GetTlsIndex()); pTLSData->pMenuBar = this; if (pTLSData->hHook != NULL) ::UnhookWindowsHookEx(pTLSData->hHook); // Hook messages about to be processed by the shortcut menu pTLSData->hHook = ::SetWindowsHookEx(WH_MSGFILTER, (HOOKPROC)StaticMsgHook, NULL, ::GetCurrentThreadId()); // Display the shortcut menu BOOL bRightToLeft = FALSE; #if defined(WINVER) && defined (WS_EX_LAYOUTRTL) && (WINVER >= 0x0500) bRightToLeft = ((GetAncestor()->GetWindowLongPtr(GWL_EXSTYLE)) & WS_EX_LAYOUTRTL); #endif int xPos = bRightToLeft? rc.right : rc.left; UINT nID = ::TrackPopupMenuEx(m_hPopupMenu, TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_VERTICAL, xPos, rc.bottom, m_hWnd, &tpm); // We get here once the TrackPopupMenuEx has ended m_bMenuActive = FALSE; // Remove the message hook ::UnhookWindowsHookEx(pTLSData->hHook); pTLSData->hHook = NULL; // Process MDI Child system menu if (IsMDIChildMaxed()) { if (::GetSystemMenu(hMaxMDIChild, FALSE) == m_hPopupMenu ) { if (nID) ::SendMessage(hMaxMDIChild, WM_SYSCOMMAND, nID, 0L); } } // Resestablish Focus if (m_bKeyMode) GrabFocus(); } inline void CMenuBar::DrawAllMDIButtons(CDC& DrawDC) { if (!IsMDIFrame()) return; if (IsMDIChildMaxed()) { int cx = GetSystemMetrics(SM_CXSMICON); int cy = GetSystemMetrics(SM_CYSMICON); CRect rc = GetClientRect(); int gap = 4; rc.right -= gap; // Assign values to each element of the CRect array for (int i = 0 ; i < 3 ; ++i) { int left = rc.right - (i+1)*cx - gap*(i+1); int top = rc.bottom/2 - cy/2; int right = rc.right - i*cx - gap*(i+1); int bottom = rc.bottom/2 + cy/2; ::SetRect(&m_MDIRect[2 - i], left, top, right, bottom); } // Hide the MDI button if it won't fit for (int k = 0 ; k <= 2 ; ++k) { if (m_MDIRect[k].left < GetMaxSize().cx) { ::SetRectEmpty(&m_MDIRect[k]); } } DrawMDIButton(DrawDC, MDI_MIN, 0); DrawMDIButton(DrawDC, MDI_RESTORE, 0); DrawMDIButton(DrawDC, MDI_CLOSE, 0); } } inline void CMenuBar::DrawMDIButton(CDC& DrawDC, int iButton, UINT uState) { if (!IsRectEmpty(&m_MDIRect[iButton])) { switch (uState) { case 0: { // Draw a grey outline DrawDC.CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNFACE)); DrawDC.MoveTo(m_MDIRect[iButton].left, m_MDIRect[iButton].bottom); DrawDC.LineTo(m_MDIRect[iButton].right, m_MDIRect[iButton].bottom); DrawDC.LineTo(m_MDIRect[iButton].right, m_MDIRect[iButton].top); DrawDC.LineTo(m_MDIRect[iButton].left, m_MDIRect[iButton].top); DrawDC.LineTo(m_MDIRect[iButton].left, m_MDIRect[iButton].bottom); } break; case 1: { // Draw outline, white at top, black on bottom DrawDC.CreatePen(PS_SOLID, 1, RGB(0, 0, 0)); DrawDC.MoveTo(m_MDIRect[iButton].left, m_MDIRect[iButton].bottom); DrawDC.LineTo(m_MDIRect[iButton].right, m_MDIRect[iButton].bottom); DrawDC.LineTo(m_MDIRect[iButton].right, m_MDIRect[iButton].top); DrawDC.CreatePen(PS_SOLID, 1, RGB(255, 255, 255)); DrawDC.LineTo(m_MDIRect[iButton].left, m_MDIRect[iButton].top); DrawDC.LineTo(m_MDIRect[iButton].left, m_MDIRect[iButton].bottom); } break; case 2: { // Draw outline, black on top, white on bottom DrawDC.CreatePen(PS_SOLID, 1, RGB(255, 255, 255)); DrawDC.MoveTo(m_MDIRect[iButton].left, m_MDIRect[iButton].bottom); DrawDC.LineTo(m_MDIRect[iButton].right, m_MDIRect[iButton].bottom); DrawDC.LineTo(m_MDIRect[iButton].right, m_MDIRect[iButton].top); DrawDC.CreatePen(PS_SOLID, 1, RGB(0, 0, 0)); DrawDC.LineTo(m_MDIRect[iButton].left, m_MDIRect[iButton].top); DrawDC.LineTo(m_MDIRect[iButton].left, m_MDIRect[iButton].bottom); } break; } DrawDC.CreatePen(PS_SOLID, 1, RGB(0, 0, 0)); switch (iButton) { case MDI_MIN: // Manually Draw Minimise button DrawDC.MoveTo(m_MDIRect[0].left + 4, m_MDIRect[0].bottom -4); DrawDC.LineTo(m_MDIRect[0].right - 4, m_MDIRect[0].bottom - 4); DrawDC.MoveTo(m_MDIRect[0].left + 4, m_MDIRect[0].bottom -5); DrawDC.LineTo(m_MDIRect[0].right - 4, m_MDIRect[0].bottom - 5); break; case MDI_RESTORE: // Manually Draw Restore Button DrawDC.MoveTo(m_MDIRect[1].left + 3, m_MDIRect[1].top + 7); DrawDC.LineTo(m_MDIRect[1].left + 3, m_MDIRect[1].bottom -4); DrawDC.LineTo(m_MDIRect[1].right - 6, m_MDIRect[1].bottom -4); DrawDC.LineTo(m_MDIRect[1].right - 6, m_MDIRect[1].top + 7); DrawDC.LineTo(m_MDIRect[1].left + 3, m_MDIRect[1].top + 7); DrawDC.MoveTo(m_MDIRect[1].left + 3, m_MDIRect[1].top + 8); DrawDC.LineTo(m_MDIRect[1].right - 6, m_MDIRect[1].top + 8); DrawDC.MoveTo(m_MDIRect[1].left + 5, m_MDIRect[1].top + 7); DrawDC.LineTo(m_MDIRect[1].left + 5, m_MDIRect[1].top + 4); DrawDC.LineTo(m_MDIRect[1].right - 4, m_MDIRect[1].top + 4); DrawDC.LineTo(m_MDIRect[1].right - 4, m_MDIRect[1].bottom -6); DrawDC.LineTo(m_MDIRect[1].right - 6, m_MDIRect[1].bottom -6); DrawDC.MoveTo(m_MDIRect[1].left + 5, m_MDIRect[1].top + 5); DrawDC.LineTo(m_MDIRect[1].right - 4, m_MDIRect[1].top + 5); break; case MDI_CLOSE: // Manually Draw Close Button DrawDC.MoveTo(m_MDIRect[2].left + 4, m_MDIRect[2].top +5); DrawDC.LineTo(m_MDIRect[2].right - 4, m_MDIRect[2].bottom -3); DrawDC.MoveTo(m_MDIRect[2].left + 5, m_MDIRect[2].top +5); DrawDC.LineTo(m_MDIRect[2].right - 4, m_MDIRect[2].bottom -4); DrawDC.MoveTo(m_MDIRect[2].left + 4, m_MDIRect[2].top +6); DrawDC.LineTo(m_MDIRect[2].right - 5, m_MDIRect[2].bottom -3); DrawDC.MoveTo(m_MDIRect[2].right -5, m_MDIRect[2].top +5); DrawDC.LineTo(m_MDIRect[2].left + 3, m_MDIRect[2].bottom -3); DrawDC.MoveTo(m_MDIRect[2].right -5, m_MDIRect[2].top +6); DrawDC.LineTo(m_MDIRect[2].left + 4, m_MDIRect[2].bottom -3); DrawDC.MoveTo(m_MDIRect[2].right -6, m_MDIRect[2].top +5); DrawDC.LineTo(m_MDIRect[2].left + 3, m_MDIRect[2].bottom -4); break; } } } inline void CMenuBar::ExitMenu() { ReleaseFocus(); m_bKeyMode = FALSE; m_bMenuActive = FALSE; SendMessage(TB_PRESSBUTTON, m_nHotItem, (LPARAM) MAKELONG (FALSE, 0)); SetHotItem(-1); CPoint pt = GetCursorPos(); ScreenToClient(pt); // Update mouse mouse position for hot tracking SendMessage(WM_MOUSEMOVE, 0L, MAKELONG(pt.x, pt.y)); } inline HWND CMenuBar::GetActiveMDIChild() { HWND hwndMDIChild = NULL; if (IsMDIFrame()) { hwndMDIChild = (HWND)::SendMessage(m_pFrame->GetView()->GetHwnd(), WM_MDIGETACTIVE, 0L, 0L); } return hwndMDIChild; } inline void CMenuBar::GrabFocus() { if (::GetFocus() != m_hWnd) m_hPrevFocus = ::SetFocus(m_hWnd); ::SetCapture(m_hWnd); ::SetCursor(::LoadCursor(NULL, IDC_ARROW)); } inline BOOL CMenuBar::IsMDIChildMaxed() const { BOOL bMaxed = FALSE; if (IsMDIFrame() && m_pFrame->GetView()->IsWindow()) { m_pFrame->GetView()->SendMessage(WM_MDIGETACTIVE, 0L, (LPARAM)&bMaxed); } return bMaxed; } inline BOOL CMenuBar::IsMDIFrame() const { return (m_pFrame->IsMDIFrame()); } inline void CMenuBar::OnMenuChar(WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); if (!m_bMenuActive) DoAltKey(LOWORD(wParam)); } inline void CMenuBar::OnCreate() { // We must send this message before sending the TB_ADDBITMAP or TB_ADDBUTTONS message SendMessage(TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0L); m_pFrame = (CFrame*)GetAncestor(); assert(m_pFrame); } inline LRESULT CMenuBar::OnCustomDraw(NMHDR* pNMHDR) // CustomDraw is used to render the MenuBar's toolbar buttons { if (m_ThemeMenu.UseThemes) { LPNMTBCUSTOMDRAW lpNMCustomDraw = (LPNMTBCUSTOMDRAW)pNMHDR; switch (lpNMCustomDraw->nmcd.dwDrawStage) { // Begin paint cycle case CDDS_PREPAINT: // Send NM_CUSTOMDRAW item draw, and post-paint notification messages. return CDRF_NOTIFYITEMDRAW | CDRF_NOTIFYPOSTPAINT ; // An item is about to be drawn case CDDS_ITEMPREPAINT: { CDC* pDrawDC = FromHandle(lpNMCustomDraw->nmcd.hdc); CRect rcRect = lpNMCustomDraw->nmcd.rc; int nState = lpNMCustomDraw->nmcd.uItemState; DWORD dwItem = (DWORD)lpNMCustomDraw->nmcd.dwItemSpec; // Leave a pixel gap above and below the drawn rectangle if (IsAeroThemed()) rcRect.InflateRect(0, -2); else rcRect.InflateRect(0, -1); if (IsMDIChildMaxed() && (0 == dwItem)) // Draw over MDI Max button { HICON hIcon = (HICON)::SendMessage(GetActiveMDIChild(), WM_GETICON, ICON_SMALL, 0L); if (NULL == hIcon) hIcon = ::LoadIcon(NULL, IDI_APPLICATION); int cx = ::GetSystemMetrics (SM_CXSMICON); int cy = ::GetSystemMetrics (SM_CYSMICON); int y = 1 + (GetWindowRect().Height() - cy)/2; int x = (rcRect.Width() - cx)/2; pDrawDC->DrawIconEx(x, y, hIcon, cx, cy, 0, NULL, DI_NORMAL); pDrawDC->Detach(); // Optional, deletes GDI objects sooner return CDRF_SKIPDEFAULT; // No further drawing } else if (nState & (CDIS_HOT | CDIS_SELECTED)) { if ((nState & CDIS_SELECTED) || (GetButtonState(dwItem) & TBSTATE_PRESSED)) { pDrawDC->GradientFill(m_ThemeMenu.clrPressed1, m_ThemeMenu.clrPressed2, rcRect, FALSE); } else if (nState & CDIS_HOT) { pDrawDC->GradientFill(m_ThemeMenu.clrHot1, m_ThemeMenu.clrHot2, rcRect, FALSE); } // Draw border pDrawDC->CreatePen(PS_SOLID, 1, m_ThemeMenu.clrOutline); pDrawDC->MoveTo(rcRect.left, rcRect.bottom); pDrawDC->LineTo(rcRect.left, rcRect.top); pDrawDC->LineTo(rcRect.right-1, rcRect.top); pDrawDC->LineTo(rcRect.right-1, rcRect.bottom); pDrawDC->MoveTo(rcRect.right-1, rcRect.bottom); pDrawDC->LineTo(rcRect.left, rcRect.bottom); TCHAR str[80] = _T(""); int nLength = (int)SendMessage(TB_GETBUTTONTEXT, lpNMCustomDraw->nmcd.dwItemSpec, 0L); if ((nLength > 0) && (nLength < 80)) SendMessage(TB_GETBUTTONTEXT, lpNMCustomDraw->nmcd.dwItemSpec, (LPARAM)str); // Draw highlight text pDrawDC->SelectObject(GetFont()); rcRect.bottom += 1; int iMode = pDrawDC->SetBkMode(TRANSPARENT); pDrawDC->DrawText(str, lstrlen(str), rcRect, DT_VCENTER | DT_CENTER | DT_SINGLELINE); pDrawDC->SetBkMode(iMode); pDrawDC->Detach(); // Optional, deletes GDI objects sooner return CDRF_SKIPDEFAULT; // No further drawing } } return CDRF_DODEFAULT ; // Do default drawing // Painting cycle has completed case CDDS_POSTPAINT: // Draw MDI Minimise, Restore and Close buttons { CDC* pDrawDC = FromHandle(lpNMCustomDraw->nmcd.hdc); DrawAllMDIButtons(*pDrawDC); pDrawDC->Detach(); // Optional, deletes GDI objects sooner } break; } } return 0L; } inline void CMenuBar::OnKeyDown(WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); switch (wParam) { case VK_ESCAPE: ExitMenu(); break; case VK_SPACE: ExitMenu(); // Bring up the system menu GetAncestor()->PostMessage(WM_SYSCOMMAND, SC_KEYMENU, VK_SPACE); break; // Handle VK_DOWN,VK_UP and VK_RETURN together case VK_DOWN: case VK_UP: case VK_RETURN: // Always use PostMessage for USER_POPUPMENU (not SendMessage) PostMessage(UWM_POPUPMENU, 0L, 0L); break; case VK_LEFT: // Move left to next topmenu item (m_nHotItem > 0)? SetHotItem(m_nHotItem -1) : SetHotItem(GetButtonCount()-1); break; case VK_RIGHT: // Move right to next topmenu item (m_nHotItem < GetButtonCount() -1)? SetHotItem(m_nHotItem +1) : SetHotItem(0); break; default: // Handle Accelerator keys with Alt toggled down if (m_bKeyMode) { UINT ID; if (SendMessage(TB_MAPACCELERATOR, wParam, (LPARAM) &ID)) { m_nHotItem = ID; PostMessage(UWM_POPUPMENU, 0L, 0L); } else ::MessageBeep(MB_OK); } break; } // switch (wParam) } inline void CMenuBar::OnLButtonDown(WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(wParam); GrabFocus(); m_nMDIButton = 0; CPoint pt; pt.x = GET_X_LPARAM(lParam); pt.y = GET_Y_LPARAM(lParam); if (IsMDIFrame()) { if (IsMDIChildMaxed()) { CClientDC MenuBarDC(this); m_nMDIButton = -1; if (m_MDIRect[0].PtInRect(pt)) m_nMDIButton = 0; if (m_MDIRect[1].PtInRect(pt)) m_nMDIButton = 1; if (m_MDIRect[2].PtInRect(pt)) m_nMDIButton = 2; if (m_nMDIButton >= 0) { DrawMDIButton(MenuBarDC, MDI_MIN, (0 == m_nMDIButton)? 2 : 0); DrawMDIButton(MenuBarDC, MDI_RESTORE, (1 == m_nMDIButton)? 2 : 0); DrawMDIButton(MenuBarDC, MDI_CLOSE, (2 == m_nMDIButton)? 2 : 0); } // Bring up the MDI Child window's system menu when the icon is pressed if (0 == HitTest()) { m_nHotItem = 0; PostMessage(UWM_POPUPMENU, 0L, 0L); } } } } inline void CMenuBar::OnLButtonUp(WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(wParam); CPoint pt; pt.x = GET_X_LPARAM(lParam); pt.y = GET_Y_LPARAM(lParam); if (IsMDIFrame()) { HWND MDIClient = m_pFrame->GetView()->GetHwnd(); HWND MDIChild = GetActiveMDIChild(); if (IsMDIChildMaxed()) { CPoint pt = GetCursorPos(); ScreenToClient(pt); // Process the MDI button action when the left mouse button is up if (m_MDIRect[0].PtInRect(pt)) { if (MDI_MIN == m_nMDIButton) ::ShowWindow(MDIChild, SW_MINIMIZE); } if (m_MDIRect[1].PtInRect(pt)) { if (MDI_RESTORE == m_nMDIButton) ::PostMessage(MDIClient, WM_MDIRESTORE, (WPARAM)MDIChild, 0L); } if (m_MDIRect[2].PtInRect(pt)) { if (MDI_CLOSE == m_nMDIButton) ::PostMessage(MDIChild, WM_CLOSE, 0L, 0L); } } } m_nMDIButton = 0; ExitMenu(); } inline BOOL CMenuBar::OnMenuInput(UINT uMsg, WPARAM wParam, LPARAM lParam) // When a popup menu is active, StaticMsgHook directs all menu messages here { switch(uMsg) { case WM_KEYDOWN: m_bExitAfter = FALSE; { switch (wParam) { case VK_ESCAPE: // Use default processing if inside a Sub Menu if ((m_hSelMenu) &&(m_hSelMenu != m_hPopupMenu)) return FALSE; m_bMenuActive = FALSE; m_bKeyMode = TRUE; SendMessage(WM_CANCELMODE, 0L, 0L); SendMessage(TB_PRESSBUTTON, m_nHotItem, MAKELONG(FALSE, 0)); SendMessage(TB_SETHOTITEM, m_nHotItem, 0L); break; case VK_LEFT: // Use default processing if inside a Sub Menu if ((m_hSelMenu) &&(m_hSelMenu != m_hPopupMenu)) return FALSE; SendMessage(TB_PRESSBUTTON, m_nHotItem, MAKELONG(FALSE, 0)); // Move left to next topmenu item (m_nHotItem > 0)? --m_nHotItem : m_nHotItem = GetButtonCount()-1; SendMessage(WM_CANCELMODE, 0L, 0L); // Always use PostMessage for USER_POPUPMENU (not SendMessage) PostMessage(UWM_POPUPMENU, 0L, 0L); PostMessage(WM_KEYDOWN, VK_DOWN, 0L); break; case VK_RIGHT: // Use default processing to open Sub Menu if (m_bSelPopup) return FALSE; SendMessage(TB_PRESSBUTTON, m_nHotItem, MAKELONG(FALSE, 0)); // Move right to next topmenu item (m_nHotItem < GetButtonCount()-1)? ++m_nHotItem : m_nHotItem = 0; SendMessage(WM_CANCELMODE, 0L, 0L); // Always use PostMessage for USER_POPUPMENU (not SendMessage) PostMessage(UWM_POPUPMENU, 0L, 0L); PostMessage(WM_KEYDOWN, VK_DOWN, 0L); break; case VK_RETURN: m_bExitAfter = TRUE; break; } // switch (wParam) } // case WM_KEYDOWN return FALSE; case WM_CHAR: m_bExitAfter = TRUE; return FALSE; case WM_LBUTTONDOWN: { m_bExitAfter = TRUE; if (HitTest() >= 0) { // Cancel popup when we hit a button a second time SendMessage(WM_CANCELMODE, 0L, 0L); return TRUE; } } return FALSE; case WM_LBUTTONDBLCLK: // Perform default action for DblClick on MDI Maxed icon if (IsMDIChildMaxed() && (0 == HitTest())) { CWnd* pMDIChild = FromHandle(GetActiveMDIChild()); CMenu* pChildMenu = pMDIChild->GetSystemMenu(FALSE); UINT nID = pChildMenu->GetDefaultItem(FALSE, 0); if (nID) pMDIChild->PostMessage(WM_SYSCOMMAND, nID, 0L); } m_bExitAfter = TRUE; return FALSE; case WM_MENUSELECT: { // store info about selected item m_hSelMenu = (HMENU)lParam; m_bSelPopup = ((HIWORD(wParam) & MF_POPUP) != 0); // Reflect message back to the frame window GetAncestor()->SendMessage(WM_MENUSELECT, wParam, lParam); } return TRUE; case WM_MOUSEMOVE: { CPoint pt; pt.x = GET_X_LPARAM(lParam); pt.y = GET_Y_LPARAM(lParam); // Skip if mouse hasn't moved if ((pt.x == m_OldMousePos.x) && (pt.y == m_OldMousePos.y)) return FALSE; m_OldMousePos.x = pt.x; m_OldMousePos.y = pt.y; ScreenToClient(pt); // Reflect messages back to the MenuBar for hot tracking SendMessage(WM_MOUSEMOVE, 0L, MAKELPARAM(pt.x, pt.y)); } break; } return FALSE; } inline void CMenuBar::OnMouseLeave() { if (IsMDIFrame()) { if (IsMDIChildMaxed()) { CClientDC MenuBarDC(this); DrawMDIButton(MenuBarDC, MDI_MIN, 0); DrawMDIButton(MenuBarDC, MDI_RESTORE, 0); DrawMDIButton(MenuBarDC, MDI_CLOSE, 0); } } } inline void CMenuBar::OnMouseMove(WPARAM wParam, LPARAM lParam) { CPoint pt; pt.x = GET_X_LPARAM(lParam); pt.y = GET_Y_LPARAM(lParam); if (IsMDIFrame()) { if (IsMDIChildMaxed()) { CClientDC MenuBarDC(this); int MDIButton = -1; if (m_MDIRect[0].PtInRect(pt)) MDIButton = 0; if (m_MDIRect[1].PtInRect(pt)) MDIButton = 1; if (m_MDIRect[2].PtInRect(pt)) MDIButton = 2; if (MK_LBUTTON == wParam) // mouse moved with left mouse button is held down { // toggle the MDI button image pressed/unpressed as required if (MDIButton >= 0) { DrawMDIButton(MenuBarDC, MDI_MIN, ((0 == MDIButton) && (0 == m_nMDIButton))? 2 : 0); DrawMDIButton(MenuBarDC, MDI_RESTORE, ((1 == MDIButton) && (1 == m_nMDIButton))? 2 : 0); DrawMDIButton(MenuBarDC, MDI_CLOSE, ((2 == MDIButton) && (2 == m_nMDIButton))? 2 : 0); } else { DrawMDIButton(MenuBarDC, MDI_MIN, 0); DrawMDIButton(MenuBarDC, MDI_RESTORE, 0); DrawMDIButton(MenuBarDC, MDI_CLOSE, 0); } } else // mouse moved without left mouse button held down { if (MDIButton >= 0) { DrawMDIButton(MenuBarDC, MDI_MIN, (0 == MDIButton)? 1 : 0); DrawMDIButton(MenuBarDC, MDI_RESTORE, (1 == MDIButton)? 1 : 0); DrawMDIButton(MenuBarDC, MDI_CLOSE, (2 == MDIButton)? 1 : 0); } else { DrawMDIButton(MenuBarDC, MDI_MIN, 0); DrawMDIButton(MenuBarDC, MDI_RESTORE, 0); DrawMDIButton(MenuBarDC, MDI_CLOSE, 0); } } } } } inline LRESULT CMenuBar::OnNotifyReflect(WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(wParam); switch (((LPNMHDR)lParam)->code) { case NM_CUSTOMDRAW: { return OnCustomDraw((LPNMHDR) lParam); } case TBN_DROPDOWN: // Always use PostMessage for USER_POPUPMENU (not SendMessage) PostMessage(UWM_POPUPMENU, 0L, 0L); break; case TBN_HOTITEMCHANGE: // This is the notification that a hot item change is about to occur // This is used to bring up a new popup menu when required { CPoint pt = GetCursorPos(); if (this == WindowFromPoint(pt)) // MenuBar window must be on top { DWORD flag = ((LPNMTBHOTITEM)lParam)->dwFlags; if ((flag & HICF_MOUSE) && !(flag & HICF_LEAVING)) { int nButton = HitTest(); if ((m_bMenuActive) && (nButton != m_nHotItem)) { SendMessage(TB_PRESSBUTTON, m_nHotItem, MAKELONG(FALSE, 0)); m_nHotItem = nButton; SendMessage(WM_CANCELMODE, 0L, 0L); //Always use PostMessage for USER_POPUPMENU (not SendMessage) PostMessage(UWM_POPUPMENU, 0L, 0L); } m_nHotItem = nButton; } // Handle escape from popup menu if ((flag & HICF_LEAVING) && m_bKeyMode) { m_nHotItem = ((LPNMTBHOTITEM)lParam)->idOld; PostMessage(TB_SETHOTITEM, m_nHotItem, 0L); } } break; } //case TBN_HOTITEMCHANGE: } // switch(((LPNMHDR)lParam)->code) return 0L; } // CMenuBar::OnNotify(...) inline void CMenuBar::OnWindowPosChanged() { InvalidateRect(&m_MDIRect[0], TRUE); InvalidateRect(&m_MDIRect[1], TRUE); InvalidateRect(&m_MDIRect[2], TRUE); { CClientDC MenuBarDC(this); DrawAllMDIButtons(MenuBarDC); } } inline void CMenuBar::PreCreate(CREATESTRUCT &cs) { cs.style = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | TBSTYLE_LIST | TBSTYLE_FLAT | CCS_NODIVIDER | CCS_NORESIZE; } inline void CMenuBar::PreRegisterClass(WNDCLASS &wc) { // Set the Window Class wc.lpszClassName = TOOLBARCLASSNAME; } inline void CMenuBar::ReleaseFocus() { if (m_hPrevFocus) ::SetFocus(m_hPrevFocus); m_hPrevFocus = NULL; ::ReleaseCapture(); } inline void CMenuBar::SetHotItem(int nHot) { m_nHotItem = nHot; SendMessage(TB_SETHOTITEM, m_nHotItem, 0L); } inline void CMenuBar::SetMenu(HMENU hMenu) { assert(::IsWindow(m_hWnd)); m_hTopMenu = hMenu; int nMaxedOffset = (IsMDIChildMaxed()? 1:0); // Remove any existing buttons while (SendMessage(TB_BUTTONCOUNT, 0L, 0L) > 0) { if(!SendMessage(TB_DELETEBUTTON, 0L, 0L)) break; } // Set the Bitmap size to zero SendMessage(TB_SETBITMAPSIZE, 0L, MAKELPARAM(0, 0)); if (IsMDIChildMaxed()) { // Create an extra button for the MDI child system menu // Later we will custom draw the window icon over this button TBBUTTON tbb = {0}; tbb.fsState = TBSTATE_ENABLED; tbb.fsStyle = TBSTYLE_BUTTON | TBSTYLE_AUTOSIZE ; tbb.iString = (INT_PTR)_T(" "); SendMessage(TB_ADDBUTTONS, 1, (WPARAM)&tbb); SetButtonText(0, _T(" ")); } for (int i = 0 ; i < ::GetMenuItemCount(hMenu); ++i) { // Assign the ToolBar Button struct TBBUTTON tbb = {0}; tbb.idCommand = i + nMaxedOffset; // Each button needs a unique ID tbb.fsState = TBSTATE_ENABLED; tbb.fsStyle = TBSTYLE_BUTTON | TBSTYLE_AUTOSIZE | TBSTYLE_DROPDOWN; tbb.iString = (INT_PTR)_T(" "); SendMessage(TB_ADDBUTTONS, 1, (WPARAM)&tbb); // Add the menu title to the string table std::vector vMenuName( MAX_MENU_STRING+1, _T('\0') ); TCHAR* szMenuName = &vMenuName[0]; GetMenuString(hMenu, i, szMenuName, MAX_MENU_STRING, MF_BYPOSITION); SetButtonText(i + nMaxedOffset, szMenuName); } } inline void CMenuBar::SetMenuBarTheme(MenuTheme& Theme) { m_ThemeMenu.UseThemes = Theme.UseThemes; m_ThemeMenu.clrHot1 = Theme.clrHot1; m_ThemeMenu.clrHot2 = Theme.clrHot2; m_ThemeMenu.clrPressed1 = Theme.clrPressed1; m_ThemeMenu.clrPressed2 = Theme.clrPressed2; m_ThemeMenu.clrOutline = Theme.clrOutline; if (IsWindow()) Invalidate(); } inline LRESULT CALLBACK CMenuBar::StaticMsgHook(int nCode, WPARAM wParam, LPARAM lParam) { assert(GetApp()); MSG* pMsg = (MSG*)lParam; TLSData* pTLSData = (TLSData*)TlsGetValue(GetApp()->GetTlsIndex()); assert(pTLSData); CMenuBar* pMenuBar = (CMenuBar*)pTLSData->pMenuBar; if (pMenuBar && (MSGF_MENU == nCode)) { // process menu message if (pMenuBar->OnMenuInput(pMsg->message, pMsg->wParam, pMsg->lParam)) { return TRUE; } } return CallNextHookEx(pTLSData->hHook, nCode, wParam, lParam); } inline void CMenuBar::OnSysCommand(WPARAM wParam, LPARAM lParam) { if (SC_KEYMENU == wParam) { if (0 == lParam) { // Alt/F10 key toggled GrabFocus(); m_bKeyMode = TRUE; int nMaxedOffset = (IsMDIChildMaxed()? 1:0); SetHotItem(nMaxedOffset); } else // Handle key pressed with Alt held down DoAltKey((WORD)lParam); } } inline LRESULT CMenuBar::WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_CHAR: return 0L; // Discard these messages case WM_DRAWITEM: m_pFrame->OnDrawItem(wParam, lParam); return TRUE; // handled case WM_EXITMENULOOP: if (m_bExitAfter) ExitMenu(); m_pFrame->OnExitMenuLoop(); break; case WM_INITMENUPOPUP: m_pFrame->OnInitMenuPopup(wParam, lParam); break; case WM_KEYDOWN: OnKeyDown(wParam, lParam); return 0L; // Discard these messages case WM_KILLFOCUS: ExitMenu(); return 0L; case WM_LBUTTONDOWN: // Do default processing first CallWindowProc(GetPrevWindowProc(), uMsg, wParam, lParam); OnLButtonDown(wParam, lParam); return 0L; case WM_LBUTTONUP: OnLButtonUp(wParam, lParam); break; case WM_MEASUREITEM: m_pFrame->OnMeasureItem(wParam, lParam); return TRUE; // handled case WM_MOUSELEAVE: OnMouseLeave(); break; case WM_MOUSEMOVE: OnMouseMove(wParam, lParam); break; case UWM_POPUPMENU: DoPopupMenu(); return 0L; case WM_SYSKEYDOWN: if ((VK_MENU == wParam) || (VK_F10 == wParam)) return 0L; break; case WM_SYSKEYUP: if ((VK_MENU == wParam) || (VK_F10 == wParam)) { ExitMenu(); return 0L; } break; case UWM_GETMENUTHEME: { MenuTheme& tm = GetMenuBarTheme(); return (LRESULT)&tm; } case WM_WINDOWPOSCHANGED: OnWindowPosChanged(); break; case WM_WINDOWPOSCHANGING: // Bypass CToolBar::WndProcDefault for this message return CWnd::WndProcDefault(uMsg, wParam, lParam); } // switch (uMsg) return CToolBar::WndProcDefault(uMsg, wParam, lParam); } // LRESULT CMenuBar::WndProcDefault(...) /////////////////////////////////// // Definitions for the CFrame class // inline CFrame::CFrame() : m_tsStatusText(_T("Ready")), m_bShowIndicatorStatus(TRUE), m_bShowMenuStatus(TRUE), m_bUseReBar(FALSE), m_bUseThemes(TRUE), m_bUpdateTheme(FALSE), m_bUseToolBar(TRUE), m_bUseCustomDraw(TRUE), m_bShowStatusBar(TRUE), m_bShowToolBar(TRUE), m_himlMenu(NULL), m_himlMenuDis(NULL), m_AboutDialog(IDW_ABOUT), m_pView(NULL), m_nMaxMRU(0), m_hOldFocus(0), m_nOldID(-1) { ZeroMemory(&m_ThemeMenu, sizeof(m_ThemeMenu)); // Do either InitCommonControls or InitCommonControlsEx LoadCommonControls(); // By default, we use the rebar if we can if (GetComCtlVersion() >= 470) m_bUseReBar = TRUE; for (int i = 0 ; i < 3 ; ++i) m_OldStatus[i] = _T('\0'); } inline CFrame::~CFrame() { if (m_himlMenu) ImageList_Destroy(m_himlMenu); if (m_himlMenuDis) ImageList_Destroy(m_himlMenuDis); } inline BOOL CFrame::AddMenuIcon(int nID_MenuItem, HICON hIcon, int cx /*= 16*/, int cy /*= 16*/) { // Get ImageList image size int cxOld = 0; int cyOld = 0; ImageList_GetIconSize(m_himlMenu, &cxOld, &cyOld ); // Create a new ImageList if required if ((cx != cxOld) || (cy != cyOld) || (NULL == m_himlMenu)) { if (m_himlMenu) ImageList_Destroy(m_himlMenu); m_himlMenu = ImageList_Create(cx, cy, ILC_COLOR32 | ILC_MASK, 1, 0); m_vMenuIcons.clear(); } if (ImageList_AddIcon(m_himlMenu, hIcon) != -1) { m_vMenuIcons.push_back(nID_MenuItem); // Recreate the Disabled imagelist if (m_himlMenuDis) ImageList_Destroy(m_himlMenuDis); m_himlMenuDis = NULL; m_himlMenuDis = CreateDisabledImageList(m_himlMenu); return TRUE; } return FALSE; } inline UINT CFrame::AddMenuIcons(const std::vector& MenuData, COLORREF crMask, UINT ToolBarID, UINT ToolBarDisabledID) // Adds the icons from a bitmap resouce to an internal ImageList for use with popup menu items. // Note: If existing are a different size to the new ones, the old ones will be removed! // The ToolBarDisabledID is ignored unless ToolBarID and ToolBarDisabledID bitmaps are the same size. { // Count the MenuData entries excluding seperators int iImages = 0; for (UINT i = 0 ; i < MenuData.size(); ++i) { if (MenuData[i] != 0) // Don't count seperators { ++iImages; } } // Load the button images from Resouce ID CBitmap Bitmap(ToolBarID); if ((0 == iImages) || (!Bitmap)) return (UINT)m_vMenuIcons.size(); // No valid images, so nothing to do! BITMAP bm = Bitmap.GetBitmapData(); int iImageWidth = bm.bmWidth / iImages; int iImageHeight = bm.bmHeight; // Create the ImageList if required if (NULL == m_himlMenu) { m_himlMenu = ImageList_Create(iImageWidth, iImageHeight, ILC_COLOR32 | ILC_MASK, iImages, 0); m_vMenuIcons.clear(); } else { int Oldcx; int Oldcy; ImageList_GetIconSize(m_himlMenu, &Oldcx, &Oldcy); if (iImageHeight != Oldcy) { TRACE(_T("Unable to add icons. The new icons are a different size to the old ones\n")); return (UINT)m_vMenuIcons.size(); } } // Add the resource IDs to the m_vMenuIcons vector for (UINT j = 0 ; j < MenuData.size(); ++j) { if (MenuData[j] != 0) { m_vMenuIcons.push_back(MenuData[j]); } } // Add the images to the ImageList ImageList_AddMasked(m_himlMenu, Bitmap, crMask); // Create the Disabled imagelist if (ToolBarDisabledID) { if (0 != m_himlMenuDis) m_himlMenuDis = ImageList_Create(iImageWidth, iImageHeight, ILC_COLOR32 | ILC_MASK, iImages, 0); CBitmap BitmapDisabled(ToolBarDisabledID); BITMAP bmDis = BitmapDisabled.GetBitmapData(); int iImageWidthDis = bmDis.bmWidth / iImages; int iImageHeightDis = bmDis.bmHeight; // Normal and Disabled icons must be the same size if ((iImageWidthDis == iImageWidth) && (iImageHeightDis == iImageHeight)) { ImageList_AddMasked(m_himlMenu, BitmapDisabled, crMask); } else { ImageList_Destroy(m_himlMenuDis); m_himlMenuDis = CreateDisabledImageList(m_himlMenu); } } else { if (m_himlMenuDis) ImageList_Destroy(m_himlMenuDis); m_himlMenuDis = CreateDisabledImageList(m_himlMenu); } // return the number of menu icons return (UINT)m_vMenuIcons.size(); } inline void CFrame::AddMenuBarBand() { // Adds a MenuBar to the rebar control REBARBANDINFO rbbi = {0}; CSize sz = GetMenuBar().GetMaxSize(); // Calculate the MenuBar height from the menu font CSize csMenuBar; CClientDC dcMenuBar(&GetMenuBar()); dcMenuBar.SelectObject(GetMenuBar().GetFont()); csMenuBar = dcMenuBar.GetTextExtentPoint32(_T("\tSomeText"), lstrlen(_T("\tSomeText"))); int MenuBar_Height = csMenuBar.cy + 6; rbbi.fMask = RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_CHILD | RBBIM_SIZE | RBBIM_ID; rbbi.cxMinChild = sz.cx; rbbi.cx = sz.cx; rbbi.cyMinChild = MenuBar_Height; rbbi.cyMaxChild = MenuBar_Height; rbbi.fStyle = RBBS_BREAK | RBBS_VARIABLEHEIGHT | RBBS_GRIPPERALWAYS ; rbbi.hwndChild = GetMenuBar(); rbbi.wID = IDW_MENUBAR; // Note: rbbi.cbSize is set inside the InsertBand function GetReBar().InsertBand(-1, rbbi); SetMenuBarBandSize(); GetReBar().SetMenuBar(GetMenuBar()); if (GetReBar().GetReBarTheme().LockMenuBand) GetReBar().ShowGripper(GetReBar().GetBand(GetMenuBar()), FALSE); } inline void CFrame::AddMRUEntry(LPCTSTR szMRUEntry) { // Erase possible duplicate entries from vector RemoveMRUEntry(szMRUEntry); // Insert the entry at the beginning of the vector m_vMRUEntries.insert(m_vMRUEntries.begin(), szMRUEntry); // Delete excessive MRU entries if (m_vMRUEntries.size() > m_nMaxMRU) m_vMRUEntries.erase(m_vMRUEntries.begin() + m_nMaxMRU, m_vMRUEntries.end()); UpdateMRUMenu(); } inline void CFrame::AddToolBarBand(CToolBar& TB, DWORD dwStyle, UINT nID) { // Adds a ToolBar to the rebar control // Create the ToolBar Window TB.Create(&GetReBar()); // Fill the REBARBAND structure REBARBANDINFO rbbi = {0}; CSize sz = TB.GetMaxSize(); rbbi.fMask = RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_CHILD | RBBIM_SIZE | RBBIM_ID; rbbi.cyMinChild = sz.cy; rbbi.cyMaxChild = sz.cy; rbbi.cx = sz.cx +2; rbbi.cxMinChild = sz.cx +2; rbbi.fStyle = dwStyle; rbbi.hwndChild = TB; rbbi.wID = nID; // Note: rbbi.cbSize is set inside the InsertBand function GetReBar().InsertBand(-1, rbbi); } inline void CFrame::AddToolBarButton(UINT nID, BOOL bEnabled /* = TRUE*/, LPCTSTR szText) // Adds Resource IDs to toolbar buttons. // A resource ID of 0 is a separator { GetToolBar().AddButton(nID, bEnabled); if(0 != szText) GetToolBar().SetButtonText(nID, szText); if (!IsWindow()) TRACE(_T("Warning ... Resource IDs for toolbars should be added in SetupToolBar\n")); } inline void CFrame::AdjustFrameRect(RECT rcView) const // Adjust the size of the frame to accommodate the View window's dimensions { // Adjust for the view styles CRect rc = rcView; DWORD dwStyle = (DWORD)GetView()->GetWindowLongPtr(GWL_STYLE); DWORD dwExStyle = (DWORD)GetView()->GetWindowLongPtr(GWL_EXSTYLE); AdjustWindowRectEx(&rc, dwStyle, FALSE, dwExStyle); // Calculate the new frame height CRect rcFrameBefore = GetWindowRect(); CRect rcViewBefore = GetViewRect(); int Height = rc.Height() + rcFrameBefore.Height() - rcViewBefore.Height(); // Adjust for the frame styles dwStyle = (DWORD)GetWindowLongPtr(GWL_STYLE); dwExStyle = (DWORD)GetWindowLongPtr(GWL_EXSTYLE); AdjustWindowRectEx(&rc, dwStyle, FALSE, dwExStyle); // Calculate final rect size, and reposition frame SetWindowPos(NULL, 0, 0, rc.Width(), Height, SWP_NOMOVE); } inline void CFrame::CreateToolBar() { if (IsReBarSupported() && m_bUseReBar) AddToolBarBand(GetToolBar(), RBBS_BREAK, IDW_TOOLBAR); // Create the toolbar inside rebar else GetToolBar().Create(this); // Create the toolbar without a rebar SetupToolBar(); if (IsReBarSupported() && m_bUseReBar) { if (GetReBar().GetReBarTheme().UseThemes && GetReBar().GetReBarTheme().LockMenuBand) { // Hide gripper for single toolbar if (GetReBar().GetBandCount() <= 2) GetReBar().ShowGripper(GetReBar().GetBand(GetToolBar()), FALSE); } } if (GetToolBar().GetToolBarData().size() > 0) { // Set the toolbar images (if not already set in SetupToolBar) // A mask of 192,192,192 is compatible with AddBitmap (for Win95) if (!GetToolBar().SendMessage(TB_GETIMAGELIST, 0L, 0L)) SetToolBarImages(RGB(192,192,192), IDW_MAIN, 0, 0); // Add the icons for popup menu AddMenuIcons(GetToolBar().GetToolBarData(), RGB(192, 192, 192), IDW_MAIN, 0); } else { TRACE(_T("Warning ... No resource IDs assigned to the toolbar\n")); } } inline void CFrame::DrawCheckmark(LPDRAWITEMSTRUCT pdis, CDC& DrawDC) // Draws the checkmark or radiocheck transparently { CRect rc = pdis->rcItem; UINT fType = ((ItemData*)pdis->itemData)->fType; MenuTheme tm = GetMenuTheme(); CRect rcBk; // Draw the checkmark's background rectangle first int Iconx = 16, Icony = 16; if (m_himlMenu) ImageList_GetIconSize(m_himlMenu, &Iconx, &Icony); int BarWidth = Iconx + 8; int left = (BarWidth - Iconx)/2; int top = rc.top + (rc.Height() - Icony)/2; rcBk.SetRect(left, top, left + Iconx, top + Icony); if (tm.UseThemes) { DrawDC.CreateSolidBrush(tm.clrHot2); DrawDC.CreatePen(PS_SOLID, 1, tm.clrOutline); // Draw the checkmark's background rectangle DrawDC.Rectangle(rcBk.left, rcBk.top, rcBk.right, rcBk.bottom); } CMemDC MemDC(FromHandle(pdis->hDC)); int cxCheck = ::GetSystemMetrics(SM_CXMENUCHECK); int cyCheck = ::GetSystemMetrics(SM_CYMENUCHECK); MemDC.CreateBitmap(cxCheck, cyCheck, 1, 1, NULL); CRect rcCheck( 0, 0, cxCheck, cyCheck); // Copy the check mark bitmap to hdcMem if (MFT_RADIOCHECK == fType) MemDC.DrawFrameControl(rcCheck, DFC_MENU, DFCS_MENUBULLET); else MemDC.DrawFrameControl(rcCheck, DFC_MENU, DFCS_MENUCHECK); int xoffset = (rcBk.Width() - rcCheck.Width()-1)/2; int yoffset = (rcBk.Height() - rcCheck.Height()-1)/2; if (tm.UseThemes) xoffset += 2; // Draw a white or black check mark as required // Unfortunately MaskBlt isn't supported on Win95, 98 or ME, so we do it the hard way CMemDC MaskDC(FromHandle(pdis->hDC)); MaskDC.CreateCompatibleBitmap(FromHandle(pdis->hDC), cxCheck, cyCheck); MaskDC.BitBlt(0, 0, cxCheck, cyCheck, &MaskDC, 0, 0, WHITENESS); if ((pdis->itemState & ODS_SELECTED) && (!tm.UseThemes)) { // Draw a white checkmark MemDC.BitBlt(0, 0, cxCheck, cyCheck, &MemDC, 0, 0, DSTINVERT); MaskDC.BitBlt(0, 0, cxCheck, cyCheck, &MemDC, 0, 0, SRCAND); DrawDC.BitBlt(rcBk.left + xoffset, rcBk.top + yoffset, cxCheck, cyCheck, &MaskDC, 0, 0, SRCPAINT); } else { // Draw a black checkmark int BullitOffset = ((MFT_RADIOCHECK == fType) && tm.UseThemes)? 1 : 0; MaskDC.BitBlt( -BullitOffset, BullitOffset, cxCheck, cyCheck, &MemDC, 0, 0, SRCAND); DrawDC.BitBlt(rcBk.left + xoffset, rcBk.top + yoffset, cxCheck, cyCheck, &MaskDC, 0, 0, SRCAND); } } inline void CFrame::DrawMenuIcon(LPDRAWITEMSTRUCT pdis, CDC& DrawDC, BOOL bDisabled) { if (!m_himlMenu) return; // Get icon size int Iconx; int Icony; ImageList_GetIconSize(m_himlMenu, &Iconx, &Icony); int BarWidth = Iconx + 8; // get the drawing rectangle CRect rc = pdis->rcItem; int left = (BarWidth - Iconx)/2; int top = rc.top + (rc.Height() - Icony)/2; rc.SetRect(left, top, left + Iconx, top + Icony); // get the icon's location in the imagelist int iImage = -1; for (int i = 0 ; i < (int)m_vMenuIcons.size(); ++i) { if (pdis->itemID == m_vMenuIcons[i]) iImage = i; } // draw the image if (iImage >= 0 ) { if ((bDisabled) && (m_himlMenuDis)) ImageList_Draw(m_himlMenuDis, iImage, DrawDC, rc.left, rc.top, ILD_TRANSPARENT); else ImageList_Draw(m_himlMenu, iImage, DrawDC, rc.left, rc.top, ILD_TRANSPARENT); } } inline void CFrame::DrawMenuText(CDC& DrawDC, LPCTSTR ItemText, CRect& rc, COLORREF colorText) { // find the position of tab character int nTab = -1; for(int i = 0; i < lstrlen(ItemText); ++i) { if(_T('\t') == ItemText[i]) { nTab = i; break; } } // Draw the item text DrawDC.SetTextColor(colorText); DrawDC.DrawText(ItemText, nTab, rc, DT_SINGLELINE | DT_LEFT | DT_VCENTER); // Draw text after tab, right aligned if(nTab != -1) DrawDC.DrawText( &ItemText[nTab + 1], -1, rc, DT_SINGLELINE | DT_RIGHT | DT_VCENTER); } inline int CFrame::GetMenuItemPos(HMENU hMenu, LPCTSTR szItem) // Returns the position of the menu item, given it's name { int nMenuItemCount = GetMenuItemCount(hMenu); MENUITEMINFO mii = {0}; mii.cbSize = GetSizeofMenuItemInfo(); for (int nItem = 0 ; nItem < nMenuItemCount; ++nItem) { std::vector vTChar( MAX_MENU_STRING+1, _T('\0') ); TCHAR* szStr = &vTChar[0]; std::vector vStripped( MAX_MENU_STRING+1, _T('\0') ); TCHAR* szStripped = &vStripped[0]; mii.fMask = MIIM_TYPE; mii.fType = MFT_STRING; mii.dwTypeData = szStr; mii.cch = MAX_MENU_STRING; // Fill the contents of szStr from the menu item if (::GetMenuItemInfo(hMenu, nItem, TRUE, &mii) && (lstrlen(szStr) <= MAX_MENU_STRING)) { // Strip out any & characters int j = 0; for (int i = 0; i < lstrlen(szStr); ++i) { if (szStr[i] != _T('&')) szStripped[j++] = szStr[i]; } szStripped[j] = _T('\0'); // Append null tchar // Compare the strings if (0 == lstrcmp(szStripped, szItem)) return nItem; } } return -1; } inline tString CFrame::GetMRUEntry(UINT nIndex) { tString tsPathName; if (nIndex < m_vMRUEntries.size()) { tsPathName = m_vMRUEntries[nIndex]; // Now put the selected entry at Index 0 AddMRUEntry(tsPathName.c_str()); } return tsPathName; } inline CRect CFrame::GetViewRect() const { // Get the frame's client area CRect rcFrame = GetClientRect(); // Get the statusbar's window area CRect rcStatus; if (GetStatusBar().IsWindowVisible() || !IsWindowVisible()) rcStatus = GetStatusBar().GetWindowRect(); // Get the top rebar or toolbar's window area CRect rcTop; if (IsReBarSupported() && m_bUseReBar) rcTop = GetReBar().GetWindowRect(); else if (GetToolBar().IsWindow() && GetToolBar().IsWindowVisible()) rcTop = GetToolBar().GetWindowRect(); // Return client size less the rebar and status windows int top = rcFrame.top + rcTop.Height(); int left = rcFrame.left; int right = rcFrame.right; int bottom = rcFrame.Height() - (rcStatus.Height()); if ((bottom <= top) ||( right <= left)) top = left = right = bottom = 0; CRect rcView(left, top, right, bottom); return rcView; } inline void CFrame::LoadCommonControls() { HMODULE hComCtl; try { // Load the Common Controls DLL hComCtl = ::LoadLibrary(_T("COMCTL32.DLL")); if (!hComCtl) throw CWinException(_T("Failed to load COMCTL32.DLL")); if (GetComCtlVersion() > 470) { // Declare a pointer to the InItCommonControlsEx function typedef BOOL WINAPI INIT_EX(INITCOMMONCONTROLSEX*); INIT_EX* pfnInit = (INIT_EX*)::GetProcAddress(hComCtl, "InitCommonControlsEx"); // Load the full set of common controls INITCOMMONCONTROLSEX InitStruct = {0}; InitStruct.dwSize = sizeof(INITCOMMONCONTROLSEX); InitStruct.dwICC = ICC_COOL_CLASSES|ICC_DATE_CLASSES|ICC_INTERNET_CLASSES|ICC_NATIVEFNTCTL_CLASS| ICC_PAGESCROLLER_CLASS|ICC_USEREX_CLASSES|ICC_WIN95_CLASSES; // Call InitCommonControlsEx if(!((*pfnInit)(&InitStruct))) throw CWinException(_T("InitCommonControlsEx failed")); } else { ::InitCommonControls(); } ::FreeLibrary(hComCtl); } catch (const CWinException &e) { e.what(); if (hComCtl) ::FreeLibrary(hComCtl); throw; } } inline BOOL CFrame::LoadRegistryMRUSettings(UINT nMaxMRU /*= 0*/) { // Load the MRU list from the registry assert(!m_tsKeyName.empty()); // KeyName must be set before calling LoadRegistryMRUSettings HKEY hKey = NULL; BOOL bRet = FALSE; try { m_nMaxMRU = MIN(nMaxMRU, 16); std::vector vMRUEntries; tString tsKey = _T("Software\\") + m_tsKeyName + _T("\\Recent Files"); if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, tsKey.c_str(), 0, KEY_READ, &hKey)) { for (UINT i = 0; i < m_nMaxMRU; ++i) { DWORD dwType = REG_SZ; DWORD dwBufferSize = 0; TCHAR szSubKey[10] = _T(""); wsprintf(szSubKey, _T("File %d\0"), i+1); if (ERROR_SUCCESS != RegQueryValueEx(hKey, szSubKey, NULL, &dwType, NULL, &dwBufferSize)) throw CWinException(_T("RegQueryValueEx failed\n")); std::vector PathName( dwBufferSize, _T('\0') ); TCHAR* pTCharArray = &PathName[0]; // load the entry from the registry if (ERROR_SUCCESS != RegQueryValueEx(hKey, szSubKey, NULL, &dwType, (LPBYTE)pTCharArray, &dwBufferSize)) throw CWinException(_T("RegQueryValueEx failed\n")); if ( lstrlen( pTCharArray ) ) vMRUEntries.push_back( pTCharArray ); } // successfully loaded all MRU values, so store them m_vMRUEntries = vMRUEntries; RegCloseKey(hKey); bRet = TRUE; } } catch(const CWinException& e) { TRACE(_T("Failed to load MRU values from registry\n")); e.what(); if (hKey) RegCloseKey(hKey); } return bRet; } inline BOOL CFrame::LoadRegistrySettings(LPCTSTR szKeyName) { assert (NULL != szKeyName); m_tsKeyName = szKeyName; tString tsKey = _T("Software\\") + m_tsKeyName + _T("\\Frame Settings"); HKEY hKey = 0; BOOL bRet = FALSE; try { if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, tsKey.c_str(), 0, KEY_READ, &hKey)) { DWORD dwType = REG_BINARY; DWORD BufferSize = sizeof(DWORD); DWORD dwTop, dwLeft, dwWidth, dwHeight, dwStatusBar, dwToolBar; if (ERROR_SUCCESS != RegQueryValueEx(hKey, _T("Top"), NULL, &dwType, (LPBYTE)&dwTop, &BufferSize)) throw CWinException(_T("RegQueryValueEx Failed")); if (ERROR_SUCCESS != RegQueryValueEx(hKey, _T("Left"), NULL, &dwType, (LPBYTE)&dwLeft, &BufferSize)) throw CWinException(_T("RegQueryValueEx Failed")); if (ERROR_SUCCESS != RegQueryValueEx(hKey, _T("Width"), NULL, &dwType, (LPBYTE)&dwWidth, &BufferSize)) throw CWinException(_T("RegQueryValueEx Failed")); if (ERROR_SUCCESS != RegQueryValueEx(hKey, _T("Height"), NULL, &dwType, (LPBYTE)&dwHeight, &BufferSize)) throw CWinException(_T("RegQueryValueEx Failed")); if (ERROR_SUCCESS != RegQueryValueEx(hKey, _T("StatusBar"), NULL, &dwType, (LPBYTE)&dwStatusBar, &BufferSize)) throw CWinException(_T("RegQueryValueEx Failed")); if (ERROR_SUCCESS != RegQueryValueEx(hKey, _T("ToolBar"), NULL, &dwType, (LPBYTE)&dwToolBar, &BufferSize)) throw CWinException(_T("RegQueryValueEx Failed")); m_rcPosition.top = dwTop; m_rcPosition.left = dwLeft; m_rcPosition.bottom = m_rcPosition.top + dwHeight; m_rcPosition.right = m_rcPosition.left + dwWidth; m_bShowStatusBar = dwStatusBar & 1; m_bShowToolBar = dwToolBar & 1; RegCloseKey(hKey); bRet = TRUE; } } catch (const CWinException& e) { TRACE(_T("Failed to load values from registry, using defaults!\n")); e.what(); if (hKey) RegCloseKey(hKey); } return bRet; } inline void CFrame::OnActivate(WPARAM wParam, LPARAM lParam) { // Do default processing first DefWindowProc(WM_ACTIVATE, wParam, lParam); if (LOWORD(wParam) == WA_INACTIVE) { // Save the hwnd of the window which currently has focus // (this must be CFrame window itself or a child window if (!IsIconic()) m_hOldFocus = ::GetFocus(); // Send a notification to the view window int idCtrl = ::GetDlgCtrlID(m_hOldFocus); NMHDR nhdr={0}; nhdr.hwndFrom = m_hOldFocus; nhdr.idFrom = idCtrl; nhdr.code = UWM_FRAMELOSTFOCUS; if (GetView()->IsWindow()) GetView()->SendMessage(WM_NOTIFY, (WPARAM)idCtrl, (LPARAM)&nhdr); } else { // Now set the focus to the appropriate child window if (m_hOldFocus) ::SetFocus(m_hOldFocus); // Send a notification to the view window int idCtrl = ::GetDlgCtrlID(m_hOldFocus); NMHDR nhdr={0}; nhdr.hwndFrom = m_hOldFocus; nhdr.idFrom = idCtrl; nhdr.code = UWM_FRAMEGOTFOCUS; if (GetView()->IsWindow()) GetView()->SendMessage(WM_NOTIFY, (WPARAM)idCtrl, (LPARAM)&nhdr); } } inline void CFrame::OnClose() { // Called in response to a WM_CLOSE message for the frame. ShowWindow(SW_HIDE); SaveRegistrySettings(); GetMenuBar().Destroy(); GetToolBar().Destroy(); GetReBar().Destroy(); GetStatusBar().Destroy(); GetView()->Destroy(); } inline void CFrame::OnCreate() { // This is called when the frame window is being created. // Override this in CMainFrame if you wish to modify what happens here // Set the icon SetIconLarge(IDW_MAIN); SetIconSmall(IDW_MAIN); // Set the keyboard accelerators m_hAccel = LoadAccelerators(GetApp()->GetResourceHandle(), MAKEINTRESOURCE(IDW_MAIN)); GetApp()->SetAccelerators(m_hAccel, this); // Set the Caption SetWindowText(LoadString(IDW_MAIN)); // Set the theme for the frame elements SetTheme(); // Create the rebar and menubar if (IsReBarSupported() && m_bUseReBar) { // Create the rebar GetReBar().Create(this); // Create the menu inside rebar GetMenuBar().Create(&GetReBar()); AddMenuBarBand(); } // Setup the menu SetFrameMenu(IDW_MAIN); UpdateMRUMenu(); // Create the ToolBar if (m_bUseToolBar) { CreateToolBar(); ShowToolBar(m_bShowToolBar); } else { ::CheckMenuItem(GetFrameMenu(), IDW_VIEW_TOOLBAR, MF_UNCHECKED); ::EnableMenuItem(GetFrameMenu(), IDW_VIEW_TOOLBAR, MF_GRAYED); } // Create the status bar GetStatusBar().Create(this); ShowStatusBar(m_bShowStatusBar); // Create the view window assert(GetView()); // Use SetView in CMainFrame's constructor to set the view window GetView()->Create(this); // Disable XP themes for the menubar if ( m_bUseThemes || (GetWinVersion() < 2600) ) // themes or WinVersion < Vista GetMenuBar().SetWindowTheme(L" ", L" "); // Start timer for Status updates if (m_bShowIndicatorStatus || m_bShowMenuStatus) SetTimer(ID_STATUS_TIMER, 200, NULL); // Reposition the child windows RecalcLayout(); } inline void CFrame::OnDestroy() { SetMenu(NULL); KillTimer(ID_STATUS_TIMER); ::PostQuitMessage(0); // Terminates the application } inline LRESULT CFrame::OnDrawItem(WPARAM wParam, LPARAM lParam) // OwnerDraw is used to render the popup menu items { LPDRAWITEMSTRUCT pdis = (LPDRAWITEMSTRUCT) lParam; if (pdis->CtlType != ODT_MENU) return CWnd::WndProcDefault(WM_DRAWITEM, wParam, lParam); CRect rc = pdis->rcItem; ItemData* pmd = (ItemData*)pdis->itemData; CDC* pDrawDC = FromHandle(pdis->hDC); MenuTheme tm = GetMenuTheme(); int Iconx = 16; int Icony = 16; if (m_himlMenu) ImageList_GetIconSize(m_himlMenu, &Iconx, &Icony); int BarWidth = tm.UseThemes? Iconx + 8 : 0; // Draw the side bar if (tm.UseThemes) { CRect rcBar = rc; rcBar.right = BarWidth; pDrawDC->GradientFill(tm.clrPressed1, tm.clrPressed2, rcBar, TRUE); } if (pmd->fType & MFT_SEPARATOR) { // draw separator CRect rcSep = rc; rcSep.left = BarWidth; if (tm.UseThemes) pDrawDC->SolidFill(RGB(255,255,255), rcSep); else pDrawDC->SolidFill(GetSysColor(COLOR_MENU), rcSep); rcSep.top += (rc.bottom - rc.top)/2; rcSep.left = BarWidth + 2; pDrawDC->DrawEdge(rcSep, EDGE_ETCHED, BF_TOP); } else { // draw menu item BOOL bDisabled = pdis->itemState & ODS_GRAYED; BOOL bSelected = pdis->itemState & ODS_SELECTED; BOOL bChecked = pdis->itemState & ODS_CHECKED; CRect rcDraw = rc; if ((bSelected) && (!bDisabled)) { // draw selected item background if (tm.UseThemes) { pDrawDC->CreateSolidBrush(tm.clrHot1); pDrawDC->CreatePen(PS_SOLID, 1, tm.clrOutline); pDrawDC->Rectangle(rcDraw.left, rcDraw.top, rcDraw.right, rcDraw.bottom); } else pDrawDC->SolidFill(GetSysColor(COLOR_HIGHLIGHT), rcDraw); } else { // draw non-selected item background rcDraw.left = BarWidth; if (tm.UseThemes) pDrawDC->SolidFill(RGB(255,255,255), rcDraw); else pDrawDC->SolidFill(GetSysColor(COLOR_MENU), rcDraw); } if (bChecked) DrawCheckmark(pdis, *pDrawDC); else DrawMenuIcon(pdis, *pDrawDC, bDisabled); // Calculate the text rect size rc.left = rc.bottom - rc.top + 2; if (_tcschr(pmd->GetItemText(), _T('\t'))) rc.right -= POST_TEXT_GAP; // Add POST_TEXT_GAP if the text includes a tab // Draw the text int iMode = pDrawDC->SetBkMode(TRANSPARENT); COLORREF colorText; if (tm.UseThemes) { rc.left += 8; colorText = GetSysColor(bDisabled ? COLOR_GRAYTEXT : COLOR_MENUTEXT); } else colorText = GetSysColor(bDisabled ? COLOR_GRAYTEXT : bSelected ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT); DrawMenuText(*pDrawDC, pmd->GetItemText(), rc, colorText); pDrawDC->SetBkMode(iMode); } pDrawDC->Detach(); // Optional, deletes GDI objects sooner return TRUE; } inline void CFrame::OnExitMenuLoop() { if (m_bUseCustomDraw) { for (UINT nItem = 0; nItem < m_vMenuItemData.size(); ++nItem) { // Undo OwnerDraw and put the text back MENUITEMINFO mii = {0}; mii.cbSize = GetSizeofMenuItemInfo(); mii.fMask = MIIM_TYPE | MIIM_DATA; mii.fType = m_vMenuItemData[nItem]->fType; mii.dwTypeData = m_vMenuItemData[nItem]->GetItemText(); mii.cch = lstrlen(m_vMenuItemData[nItem]->GetItemText()); mii.dwItemData = 0; ::SetMenuItemInfo(m_vMenuItemData[nItem]->hMenu, m_vMenuItemData[nItem]->nPos, TRUE, &mii); } m_vMenuItemData.clear(); } } inline void CFrame::OnHelp() { // Ensure only one dialog displayed even for multiple hits of the F1 button if (!m_AboutDialog.IsWindow()) { // Store the window handle that currently has keyboard focus HWND hPrevFocus = ::GetFocus(); if (hPrevFocus == GetMenuBar()) hPrevFocus = m_hWnd; m_AboutDialog.SetDlgParent(this); m_AboutDialog.DoModal(); ::SetFocus(hPrevFocus); } } inline void CFrame::OnInitMenuPopup(WPARAM wParam, LPARAM lParam) { // The system menu shouldn't be owner drawn if (HIWORD(lParam)) return; if (m_bUseCustomDraw) { CMenu* pMenu = FromHandle((HMENU)wParam); for (UINT i = 0; i < pMenu->GetMenuItemCount(); ++i) { MENUITEMINFO mii = {0}; mii.cbSize = GetSizeofMenuItemInfo(); TCHAR szMenuItem[MAX_MENU_STRING] = _T(""); // Use old fashioned MIIM_TYPE instead of MIIM_FTYPE for MS VC6 compatibility mii.fMask = MIIM_TYPE | MIIM_DATA | MIIM_SUBMENU; mii.dwTypeData = szMenuItem; mii.cch = MAX_MENU_STRING -1; // Send message for menu updates UINT menuItem = pMenu->GetMenuItemID(i); SendMessage(UWM_UPDATE_COMMAND, (WPARAM)menuItem, 0); // Specify owner-draw for the menu item type if (pMenu->GetMenuItemInfo(i, &mii, TRUE)) { if (0 == mii.dwItemData) { ItemData* pItem = new ItemData; // deleted in OnExitMenuLoop pItem->hMenu = *pMenu; pItem->nPos = i; pItem->fType = mii.fType; pItem->hSubMenu = mii.hSubMenu; mii.fType |= MFT_OWNERDRAW; lstrcpyn(pItem->GetItemText(), szMenuItem, MAX_MENU_STRING); mii.dwItemData = (DWORD_PTR)pItem; m_vMenuItemData.push_back(ItemDataPtr(pItem)); // Store pItem in m_vMenuItemData pMenu->SetMenuItemInfo(i, &mii, TRUE); // Store pItem in mii } } } } } inline LRESULT CFrame::OnMeasureItem(WPARAM wParam, LPARAM lParam) // Called before the Popup menu is displayed, so that the MEASUREITEMSTRUCT // values can be assigned with the menu item's dimensions. { LPMEASUREITEMSTRUCT pmis = (LPMEASUREITEMSTRUCT) lParam; if (pmis->CtlType != ODT_MENU) return CWnd::WndProcDefault(WM_MEASUREITEM, wParam, lParam); ItemData* pmd = (ItemData *) pmis->itemData; assert(::IsMenu(pmd->hMenu)); // Does itemData contain a valid ItemData struct? MenuTheme tm = GetMenuTheme(); if (pmd->fType & MFT_SEPARATOR) { pmis->itemHeight = 7; pmis->itemWidth = 0; } else { CClientDC DesktopDC(NULL); // Get the font used in menu items NONCLIENTMETRICS nm = {0}; nm.cbSize = GetSizeofNonClientMetrics(); SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(nm), &nm, 0); // Default menu items are bold, so take this into account if ((int)::GetMenuDefaultItem(pmd->hMenu, TRUE, GMDI_USEDISABLED) != -1) nm.lfMenuFont.lfWeight = FW_BOLD; TCHAR* pItemText = &(pmd->vItemText[0]); DesktopDC.CreateFontIndirect(&nm.lfMenuFont); // Calculate the size of the text CSize size = DesktopDC.GetTextExtentPoint32(pItemText, lstrlen(pItemText)); // Calculate the size of the icon int Iconx = 16; int Icony = 16; if (m_himlMenu) ImageList_GetIconSize(m_himlMenu, &Iconx, &Icony); pmis->itemHeight = 2+ MAX(MAX(size.cy, GetSystemMetrics(SM_CYMENU)-2), Icony+2); pmis->itemWidth = size.cx + MAX(::GetSystemMetrics(SM_CXMENUSIZE), Iconx+2); // Allow extra width if the text includes a tab if (_tcschr(pItemText, _T('\t'))) pmis->itemWidth += POST_TEXT_GAP; // Allow extra width if the menu item has a sub menu if (pmd->hSubMenu) pmis->itemWidth += 10; // Allow extra width for themed menu if (tm.UseThemes) pmis->itemWidth += 8; } return TRUE; } inline LRESULT CFrame::OnMenuChar(WPARAM wParam, LPARAM lParam) { if ((IsMenuBarUsed()) && (LOWORD(wParam)!= VK_SPACE)) { // Activate MenuBar for key pressed with Alt key held down GetMenuBar().OnMenuChar(wParam, lParam); return -1L; } return CWnd::WndProcDefault(WM_MENUCHAR, wParam, lParam); } inline void CFrame::OnMenuSelect(WPARAM wParam, LPARAM lParam) { // Set the StatusBar text when we hover over a menu // Only popup submenus have status strings if (m_bShowMenuStatus) { int nID = LOWORD (wParam); CMenu* pMenu = FromHandle((HMENU) lParam); if ((pMenu != GetMenu()) && (nID != 0) && !(HIWORD(wParam) & MF_POPUP)) m_tsStatusText = LoadString(nID); else m_tsStatusText = _T("Ready"); SetStatusText(); } } inline LRESULT CFrame::OnNotify(WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(wParam); switch (((LPNMHDR)lParam)->code) { case UWM_UNDOCKED: m_hOldFocus = 0; break; case RBN_HEIGHTCHANGE: RecalcLayout(); Invalidate(); break; // case RBN_LAYOUTCHANGED: // if (GetReBar().GetReBarTheme().UseThemes && GetReBar().GetReBarTheme().BandsLeft) // GetReBar().MoveBandsLeft(); // break; case RBN_MINMAX: if (GetReBar().GetReBarTheme().UseThemes && GetReBar().GetReBarTheme().ShortBands) return 1L; // Supress maximise or minimise rebar band break; // Display tooltips for the toolbar case TTN_GETDISPINFO: if (GetToolBar().IsWindow()) { CToolBar* pToolBar = 0; if (IsReBarUsed()) { // Get the ToolBar's CWnd CWnd* pWnd = FromHandle(GetReBar().HitTest(GetCursorPos())); if (pWnd && (lstrcmp(pWnd->GetClassName(), _T("ToolbarWindow32")) == 0)) { pToolBar = (CToolBar*)pWnd; } } if (pToolBar) { LPNMTTDISPINFO lpDispInfo = (LPNMTTDISPINFO)lParam; int iIndex = pToolBar->HitTest(); if (iIndex >= 0) { int nID = pToolBar->GetCommandID(iIndex); if (nID > 0) { m_tsTooltip = LoadString(nID); lpDispInfo->lpszText = (LPTSTR)m_tsTooltip.c_str(); } else m_tsTooltip = _T(""); } } } break; } // switch LPNMHDR return 0L; } // CFrame::Onotify(...) inline void CFrame::OnSetFocus() { SetStatusText(); } inline void CFrame::OnSysColorChange() { // Honour theme color changes for (int nBand = 0; nBand <= GetReBar().GetBandCount(); ++nBand) { GetReBar().SetBandColor(nBand, GetSysColor(COLOR_BTNTEXT), GetSysColor(COLOR_BTNFACE)); } // Update the status bar font and text NONCLIENTMETRICS nm = {0}; nm.cbSize = GetSizeofNonClientMetrics(); SystemParametersInfo (SPI_GETNONCLIENTMETRICS, 0, &nm, 0); LOGFONT lf = nm.lfStatusFont; CFont* pFont = FromHandle(CreateFontIndirect(&lf)); GetStatusBar().SetFont(pFont, FALSE); SetStatusText(); if ((m_bUpdateTheme) && (m_bUseThemes)) SetTheme(); // Reposition and redraw everything RecalcLayout(); RedrawWindow(NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN); // Forward the message to the view window m_pView->PostMessage(WM_SYSCOLORCHANGE, 0L, 0L); } inline LRESULT CFrame::OnSysCommand(WPARAM wParam, LPARAM lParam) { if ((SC_KEYMENU == wParam) && (VK_SPACE != lParam) && IsMenuBarUsed()) { GetMenuBar().OnSysCommand(wParam, lParam); return 0L; } if (SC_MINIMIZE == wParam) m_hOldFocus = ::GetFocus(); return CWnd::WndProcDefault(WM_SYSCOMMAND, wParam, lParam); } inline void CFrame::OnTimer(WPARAM wParam) { if (ID_STATUS_TIMER == wParam) { if (m_bShowMenuStatus) { // Get the toolbar the point is over CToolBar* pToolBar = 0; if (IsReBarUsed()) { // Get the ToolBar's CWnd CWnd* pWnd = FromHandle(GetReBar().HitTest(GetCursorPos())); if (pWnd && (dynamic_cast(pWnd)) && !(dynamic_cast(pWnd))) pToolBar = (CToolBar*)pWnd; } else { CPoint pt = GetCursorPos(); CWnd* pWnd = WindowFromPoint(GetCursorPos()); if (pWnd && (dynamic_cast(pWnd))) pToolBar = (CToolBar*)pWnd; } if ((pToolBar) && (WindowFromPoint(GetCursorPos()) == pToolBar)) { // Which toolbar button is the mouse cursor hovering over? int nButton = pToolBar->HitTest(); if (nButton >= 0) { int nID = pToolBar->GetCommandID(nButton); // Only update the statusbar if things have changed if (nID != m_nOldID) { if (nID != 0) m_tsStatusText = LoadString(nID); else m_tsStatusText = _T("Ready"); if (GetStatusBar().IsWindow()) SetStatusText(); } m_nOldID = nID; } } else { if (m_nOldID != -1) { m_tsStatusText = _T("Ready"); SetStatusText(); } m_nOldID = -1; } } if (m_bShowIndicatorStatus) SetStatusIndicators(); } } inline void CFrame::OnViewStatusBar() { m_bShowStatusBar = !m_bShowStatusBar; ShowStatusBar(m_bShowStatusBar); } inline void CFrame::OnViewToolBar() { m_bShowToolBar = !m_bShowToolBar; ShowToolBar(m_bShowToolBar); } inline void CFrame::PreCreate(CREATESTRUCT& cs) { // Set the frame window styles cs.style = WS_OVERLAPPEDWINDOW | WS_VISIBLE; // Set the original window position cs.x = m_rcPosition.left; cs.y = m_rcPosition.top; cs.cx = m_rcPosition.Width(); cs.cy = m_rcPosition.Height(); } inline void CFrame::PreRegisterClass(WNDCLASS &wc) { // Set the Window Class wc.lpszClassName = _T("Win32++ Frame"); } inline void CFrame::RecalcLayout() { CWnd* pView = GetView(); if ((!pView) || (!pView->GetHwnd())) return; // Resize the status bar if (GetStatusBar().IsWindow() && m_bShowStatusBar) { GetStatusBar().SetWindowPos(NULL, 0, 0, 0, 0, SWP_SHOWWINDOW); GetStatusBar().Invalidate(); SetStatusText(); } // Resize the rebar or toolbar if (IsReBarUsed()) { GetReBar().SendMessage(WM_SIZE, 0L, 0L); GetReBar().Invalidate(); } else if (m_bUseToolBar && m_bShowToolBar) GetToolBar().SendMessage(TB_AUTOSIZE, 0L, 0L); // Resize the View window CRect rClient = GetViewRect(); if ((rClient.bottom - rClient.top) >= 0) { int x = rClient.left; int y = rClient.top; int cx = rClient.Width(); int cy = rClient.Height(); pView->SetWindowPos( NULL, x, y, cx, cy, SWP_SHOWWINDOW|SWP_ASYNCWINDOWPOS ); } // Adjust rebar bands if (IsReBarUsed()) { if (GetReBar().GetReBarTheme().UseThemes && GetReBar().GetReBarTheme().BandsLeft) GetReBar().MoveBandsLeft(); if (IsMenuBarUsed()) SetMenuBarBandSize(); } } inline void CFrame::RemoveMRUEntry(LPCTSTR szMRUEntry) { std::vector::iterator it; for (it = m_vMRUEntries.begin(); it != m_vMRUEntries.end(); ++it) { if ((*it) == szMRUEntry) { m_vMRUEntries.erase(it); break; } } UpdateMRUMenu(); } inline BOOL CFrame::SaveRegistrySettings() { // Store the window position in the registry if (!m_tsKeyName.empty()) { tString tsKeyName = _T("Software\\") + m_tsKeyName + _T("\\Frame Settings"); HKEY hKey = NULL; try { if (ERROR_SUCCESS != RegCreateKeyEx(HKEY_CURRENT_USER, tsKeyName.c_str(), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL)) throw CWinException(_T("RegCreateKeyEx failed")); WINDOWPLACEMENT Wndpl = {0}; Wndpl.length = sizeof(WINDOWPLACEMENT); if (GetWindowPlacement(Wndpl)) { // Get the Frame's window position CRect rc = Wndpl.rcNormalPosition; DWORD dwTop = MAX(rc.top, 0); DWORD dwLeft = MAX(rc.left, 0); DWORD dwWidth = MAX(rc.Width(), 100); DWORD dwHeight = MAX(rc.Height(), 50); if (ERROR_SUCCESS != RegSetValueEx(hKey, _T("Top"), 0, REG_DWORD, (LPBYTE)&dwTop, sizeof(DWORD))) throw CWinException(_T("RegSetValueEx failed")); if (ERROR_SUCCESS != RegSetValueEx(hKey, _T("Left"), 0, REG_DWORD, (LPBYTE)&dwLeft, sizeof(DWORD))) throw CWinException(_T("RegSetValueEx failed")); if (ERROR_SUCCESS != RegSetValueEx(hKey, _T("Width"), 0, REG_DWORD, (LPBYTE)&dwWidth, sizeof(DWORD))) throw CWinException(_T("RegSetValueEx failed")); if (ERROR_SUCCESS != RegSetValueEx(hKey, _T("Height"), 0, REG_DWORD, (LPBYTE)&dwHeight, sizeof(DWORD))) throw CWinException(_T("RegSetValueEx failed")); } // Store the ToolBar and statusbar states DWORD dwShowToolBar = m_bShowToolBar; DWORD dwShowStatusBar = m_bShowStatusBar; if (ERROR_SUCCESS != RegSetValueEx(hKey, _T("ToolBar"), 0, REG_DWORD, (LPBYTE)&dwShowToolBar, sizeof(DWORD))) throw CWinException(_T("RegSetValueEx failed")); if (ERROR_SUCCESS != RegSetValueEx(hKey, _T("StatusBar"), 0, REG_DWORD, (LPBYTE)&dwShowStatusBar, sizeof(DWORD))) throw CWinException(_T("RegSetValueEx failed")); RegCloseKey(hKey); } catch (const CWinException& e) { TRACE(_T("Failed to save registry settings\n")); if (hKey) { // Roll back the registry changes by deleting this subkey RegDeleteKey(HKEY_CURRENT_USER ,tsKeyName.c_str()); RegCloseKey(hKey); } e.what(); return FALSE; } // Store the MRU entries in the registry if (m_nMaxMRU > 0) { tString tsKeyName = _T("Software\\") + m_tsKeyName + _T("\\Recent Files"); HKEY hKey = NULL; try { if (ERROR_SUCCESS != RegCreateKeyEx(HKEY_CURRENT_USER, tsKeyName.c_str(), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL)) throw CWinException(_T("RegCreateKeyEx failed")); for (UINT i = 0; i < m_nMaxMRU; ++i) { TCHAR szSubKey[10]; wsprintf(szSubKey, _T("File %d\0"), i+1); tString tsPathName; if (i < m_vMRUEntries.size()) tsPathName = m_vMRUEntries[i]; if (ERROR_SUCCESS != RegSetValueEx(hKey, szSubKey, 0, REG_SZ, (LPBYTE)tsPathName.c_str(), (1 + lstrlen(tsPathName.c_str()))*sizeof(TCHAR))) throw CWinException(_T("RegSetValueEx failed")); } RegCloseKey(hKey); } catch (const CWinException& e) { TRACE(_T("Failed to save registry MRU settings\n")); if (hKey) { // Roll back the registry changes by deleting this subkey RegDeleteKey(HKEY_CURRENT_USER ,tsKeyName.c_str()); RegCloseKey(hKey); } e.what(); return FALSE; } } } return TRUE; } inline void CFrame::SetFrameMenu(INT ID_MENU) { // Sets the frame's menu from a Resouce ID. // A resource ID of 0 removes the menu from the frame. HMENU hMenu = 0; if (ID_MENU != 0) { // Sets the frame's menu from a resource ID. hMenu = ::LoadMenu(GetApp()->GetResourceHandle(), MAKEINTRESOURCE(ID_MENU)); assert (hMenu); } SetFrameMenu(hMenu); } inline void CFrame::SetFrameMenu(HMENU hMenu) { // Sets the frame's menu from a HMENU. m_Menu.Attach(hMenu); if (IsMenuBarUsed()) { GetMenuBar().SetMenu(GetFrameMenu()); BOOL bShow = (hMenu != NULL); // boolean expression ShowMenu(bShow); } else SetMenu(&m_Menu); } inline UINT CFrame::SetMenuIcons(const std::vector& MenuData, COLORREF crMask, UINT ToolBarID, UINT ToolBarDisabledID) { // Remove any existing menu icons if (m_himlMenu) ImageList_Destroy(m_himlMenu); if (m_himlMenuDis) ImageList_Destroy(m_himlMenuDis); m_himlMenu = NULL; m_himlMenuDis = NULL; m_vMenuIcons.clear(); // Exit if no ToolBarID is specified if (ToolBarID == 0) return 0; // Add the menu icons from the bitmap IDs return AddMenuIcons(MenuData, crMask, ToolBarID, ToolBarDisabledID); } inline void CFrame::SetMenuBarBandSize() { // Sets the minimum width of the MenuBar band to the width of the rebar // This prevents other bands from moving to this MenuBar's row. CRect rcClient = GetClientRect(); CReBar& RB = GetReBar(); int nBand = RB.GetBand(GetMenuBar()); CRect rcBorder = RB.GetBandBorders(nBand); REBARBANDINFO rbbi = {0}; rbbi.fMask = RBBIM_CHILDSIZE | RBBIM_SIZE; RB.GetBandInfo(nBand, rbbi); int Width; if ((GetReBar().GetReBarTheme().UseThemes) && (GetReBar().GetReBarTheme().LockMenuBand)) Width = rcClient.Width() - rcBorder.Width() - 2; else Width = GetMenuBar().GetMaxSize().cx; rbbi.cxMinChild = Width; rbbi.cx = Width; RB.SetBandInfo(nBand, rbbi); } inline void CFrame::SetMenuTheme(MenuTheme& Theme) { m_ThemeMenu.UseThemes = Theme.UseThemes; m_ThemeMenu.clrHot1 = Theme.clrHot1; m_ThemeMenu.clrHot2 = Theme.clrHot2; m_ThemeMenu.clrPressed1 = Theme.clrPressed1; m_ThemeMenu.clrPressed2 = Theme.clrPressed2; m_ThemeMenu.clrOutline = Theme.clrOutline; GetMenuBar().SetMenuBarTheme(Theme); // Sets the theme for MenuBar buttons Invalidate(); } inline void CFrame::SetStatusIndicators() { if (::IsWindow(GetStatusBar())) { LPCTSTR Status1 = (::GetKeyState(VK_CAPITAL) & 0x0001)? _T("\tCAP") : _T(""); LPCTSTR Status2 = (::GetKeyState(VK_NUMLOCK) & 0x0001)? _T("\tNUM") : _T(""); LPCTSTR Status3 = (::GetKeyState(VK_SCROLL) & 0x0001)? _T("\tSCRL"): _T(""); // Only update indictors if the text has changed if (Status1 != m_OldStatus[0]) GetStatusBar().SetPartText(1, (Status1)); if (Status2 != m_OldStatus[1]) GetStatusBar().SetPartText(2, (Status2)); if (Status3 != m_OldStatus[2]) GetStatusBar().SetPartText(3, (Status3)); m_OldStatus[0] = Status1; m_OldStatus[1] = Status2; m_OldStatus[2] = Status3; } } inline void CFrame::SetStatusText() { if (::IsWindow(GetStatusBar())) { // Calculate the width of the text indicators CClientDC dcStatus(&GetStatusBar()); CSize csCAP = dcStatus.GetTextExtentPoint32(_T("\tCAP"), lstrlen(_T("\tCAP"))); CSize csNUM = dcStatus.GetTextExtentPoint32(_T("\tNUM"), lstrlen(_T("\tNUM"))); CSize csSCRL = dcStatus.GetTextExtentPoint32(_T("\tSCRL "), lstrlen(_T("\tSCRL "))); // Get the coordinates of the parent window's client area. CRect rcClient = GetClientRect(); int width = MAX(300, rcClient.right); if (m_bShowIndicatorStatus) { // Create 4 panes GetStatusBar().SetPartWidth(0, width - (csCAP.cx+csNUM.cx+csSCRL.cx+20)); GetStatusBar().SetPartWidth(1, csCAP.cx); GetStatusBar().SetPartWidth(2, csNUM.cx); GetStatusBar().SetPartWidth(3, csSCRL.cx); SetStatusIndicators(); } // Place text in the 1st pane GetStatusBar().SetPartText(0, m_tsStatusText.c_str()); } } inline void CFrame::SetTheme() { // Note: To modify theme colors, override this function in CMainframe, // and make any modifications there. // Avoid themes if using less than 16 bit colors CClientDC DesktopDC(NULL); if (DesktopDC.GetDeviceCaps(BITSPIXEL) < 16) m_bUseThemes = FALSE; BOOL T = TRUE; BOOL F = FALSE; if (m_bUseThemes) { // Set a flag redo SetTheme when the theme changes m_bUpdateTheme = TRUE; // Detect the XP theme name WCHAR Name[30] = L""; HMODULE hMod = ::LoadLibrary(_T("uxtheme.dll")); if(hMod) { typedef HRESULT (__stdcall *PFNGETCURRENTTHEMENAME)(LPWSTR pszThemeFileName, int cchMaxNameChars, LPWSTR pszColorBuff, int cchMaxColorChars, LPWSTR pszSizeBuff, int cchMaxSizeChars); PFNGETCURRENTTHEMENAME pfn = (PFNGETCURRENTTHEMENAME)GetProcAddress(hMod, "GetCurrentThemeName"); (*pfn)(0, 0, Name, 30, 0, 0); ::FreeLibrary(hMod); } enum Themetype{ Modern, Grey, Blue, Silver, Olive }; int Theme = Grey; if (GetWinVersion() < 2600) // Not for Vista and above { if (0 == wcscmp(L"NormalColor", Name)) Theme = Blue; if (0 == wcscmp(L"Metallic", Name)) Theme = Silver; if (0 == wcscmp(L"HomeStead", Name)) Theme = Olive; } else Theme = Modern; switch (Theme) { case Modern: { ToolBarTheme tt = {T, RGB(180, 250, 255), RGB(140, 190, 255), RGB(150, 220, 255), RGB(80, 100, 255), RGB(127, 127, 255)}; ReBarTheme tr = {T, RGB(220, 225, 250), RGB(240, 242, 250), RGB(240, 240, 250), RGB(180, 200, 230), F, T, T, T, T, F}; MenuTheme tm = {T, RGB(180, 250, 255), RGB(140, 190, 255), RGB(240, 250, 255), RGB(120, 170, 220), RGB(127, 127, 255)}; GetToolBar().SetToolBarTheme(tt); SetMenuTheme(tm); // Sets the theme for popup menus and MenuBar GetReBar().SetReBarTheme(tr); } break; case Grey: // A color scheme suitable for 16 bit colors. Suitable for Windows older than XP. { ToolBarTheme tt = {T, RGB(182, 189, 210), RGB(182, 189, 210), RGB(133, 146, 181), RGB(133, 146, 181), RGB(10, 36, 106)}; ReBarTheme tr = {T, RGB(212, 208, 200), RGB(212, 208, 200), RGB(230, 226, 222), RGB(220, 218, 208), F, T, T, T, T, F}; MenuTheme tm = {T, RGB(182, 189, 210), RGB( 182, 189, 210), RGB(200, 196, 190), RGB(200, 196, 190), RGB(100, 100, 100)}; GetToolBar().SetToolBarTheme(tt); SetMenuTheme(tm); // Sets the theme for popup menus and MenuBar GetReBar().SetReBarTheme(tr); } break; case Blue: { // Used for XP default (blue) color scheme ToolBarTheme tt = {T, RGB(255, 230, 190), RGB(255, 190, 100), RGB(255, 140, 40), RGB(255, 180, 80), RGB(192, 128, 255)}; ReBarTheme tr = {T, RGB(150,190,245), RGB(196,215,250), RGB(220,230,250), RGB( 70,130,220), F, T, T, T, T, F}; MenuTheme tm = {T, RGB(255, 230, 190), RGB(255, 190, 100), RGB(220,230,250), RGB(150,190,245), RGB(128, 128, 200)}; GetToolBar().SetToolBarTheme(tt); SetMenuTheme(tm); // Sets the theme for popup menus and MenuBar GetReBar().SetReBarTheme(tr); } break; case Silver: { // Used for XP Silver color scheme ToolBarTheme tt = {T, RGB(192, 210, 238), RGB(192, 210, 238), RGB(152, 181, 226), RGB(152, 181, 226), RGB(49, 106, 197)}; ReBarTheme tr = {T, RGB(225, 220, 240), RGB(240, 240, 245), RGB(245, 240, 255), RGB(160, 155, 180), F, T, T, T, T, F}; MenuTheme tm = {T, RGB(196, 215, 250), RGB( 120, 180, 220), RGB(240, 240, 245), RGB(170, 165, 185), RGB(128, 128, 150)}; GetToolBar().SetToolBarTheme(tt); SetMenuTheme(tm); // Sets the theme for popup menus and MenuBar GetReBar().SetReBarTheme(tr); } break; case Olive: { // Used for XP Olive color scheme ReBarTheme tr = {T, RGB(215, 216, 182), RGB(242, 242, 230), RGB(249, 255, 227), RGB(178, 191, 145), F, T, T, T, T, F}; ToolBarTheme tt = {T, RGB(255, 230, 190), RGB(255, 190, 100), RGB(255, 140, 40), RGB(255, 180, 80), RGB(200, 128, 128)}; MenuTheme tm = {T, RGB(255, 230, 190), RGB(255, 190, 100), RGB(249, 255, 227), RGB(178, 191, 145), RGB(128, 128, 128)}; GetToolBar().SetToolBarTheme(tt); SetMenuTheme(tm); // Sets the theme for popup menus and MenuBar GetReBar().SetReBarTheme(tr); } break; } } else { // Use a classic style by default ReBarTheme tr = {T, 0, 0, 0, 0, F, T, T, F, F, F}; GetReBar().SetReBarTheme(tr); } RecalcLayout(); } inline void CFrame::SetToolBarImages(COLORREF crMask, UINT ToolBarID, UINT ToolBarHotID, UINT ToolBarDisabledID) // Either sets the imagelist or adds/replaces bitmap depending on ComCtl32.dll version // Assumes the width of the button image = bitmap_size / buttons // Assumes buttons have been already been added via AdddToolBarButton // The colour mask is ignored for 32bit bitmaps, but is required for 24bit bitmaps // The colour mask is often grey RGB(192,192,192) or magenta (255,0,255) // The color mask is ignored for 32bit bitmap resources // The Hot and disabled bitmap resources can be 0 { GetToolBar().SetImages(crMask, ToolBarID, ToolBarHotID, ToolBarDisabledID); } inline void CFrame::SetupToolBar() { // Use this function to set the Resource IDs for the toolbar(s). /* // Set the Resource IDs for the toolbar buttons AddToolBarButton( IDM_FILE_NEW ); AddToolBarButton( IDM_FILE_OPEN ); AddToolBarButton( IDM_FILE_SAVE ); AddToolBarButton( 0 ); // Separator AddToolBarButton( IDM_EDIT_CUT ); AddToolBarButton( IDM_EDIT_COPY ); AddToolBarButton( IDM_EDIT_PASTE ); AddToolBarButton( 0 ); // Separator AddToolBarButton( IDM_FILE_PRINT ); AddToolBarButton( 0 ); // Separator AddToolBarButton( IDM_HELP_ABOUT ); */ } inline void CFrame::SetView(CWnd& wndView) // Sets or changes the View window displayed within the frame { if (m_pView != &wndView) { // Destroy the existing view window (if any) if (m_pView) m_pView->Destroy(); // Assign the view window m_pView = &wndView; if (m_hWnd) { // The frame is already created, so create and position the new view too assert(GetView()); // Use SetView in CMainFrame's constructor to set the view window GetView()->Create(this); RecalcLayout(); } } } inline void CFrame::ShowMenu(BOOL bShow) { if (bShow) { if (IsReBarUsed()) GetReBar().SendMessage(RB_SHOWBAND, GetReBar().GetBand(GetMenuBar()), TRUE); else SetMenu(&m_Menu); } else { if (IsReBarUsed()) GetReBar().SendMessage(RB_SHOWBAND, GetReBar().GetBand(GetMenuBar()), FALSE); else SetMenu(NULL); } if (GetReBar().IsWindow()) { if (GetReBar().GetReBarTheme().UseThemes && GetReBar().GetReBarTheme().BandsLeft) GetReBar().MoveBandsLeft(); } // Reposition the Windows RecalcLayout(); } inline void CFrame::ShowStatusBar(BOOL bShow) { if (bShow) { m_Menu.CheckMenuItem(IDW_VIEW_STATUSBAR, MF_CHECKED); GetStatusBar().ShowWindow(SW_SHOW); } else { m_Menu.CheckMenuItem(IDW_VIEW_STATUSBAR, MF_UNCHECKED); GetStatusBar().ShowWindow(SW_HIDE); } // Reposition the Windows RecalcLayout(); } inline void CFrame::ShowToolBar(BOOL bShow) { if (bShow) { m_Menu.CheckMenuItem(IDW_VIEW_TOOLBAR, MF_CHECKED); if (IsReBarUsed()) GetReBar().SendMessage(RB_SHOWBAND, GetReBar().GetBand(GetToolBar()), TRUE); else GetToolBar().ShowWindow(SW_SHOW); } else { m_Menu.CheckMenuItem(IDW_VIEW_TOOLBAR, MF_UNCHECKED); if (IsReBarUsed()) GetReBar().SendMessage(RB_SHOWBAND, GetReBar().GetBand(GetToolBar()), FALSE); else GetToolBar().ShowWindow(SW_HIDE); } if (GetReBar().IsWindow()) { if (GetReBar().GetReBarTheme().UseThemes && GetReBar().GetReBarTheme().BandsLeft) GetReBar().MoveBandsLeft(); } // Reposition the Windows RecalcLayout(); } inline void CFrame::UpdateMRUMenu() { if (0 >= m_nMaxMRU) return; // Set the text for the MRU Menu tString tsMRUArray[16]; UINT MaxMRUArrayIndex = 0; if (m_vMRUEntries.size() > 0) { for (UINT n = 0; ((n < m_vMRUEntries.size()) && (n <= m_nMaxMRU)); ++n) { tsMRUArray[n] = m_vMRUEntries[n]; if (tsMRUArray[n].length() > MAX_MENU_STRING - 10) { // Truncate the string if its too long tsMRUArray[n].erase(0, tsMRUArray[n].length() - MAX_MENU_STRING +10); tsMRUArray[n] = _T("... ") + tsMRUArray[n]; } // Prefix the string with its number TCHAR tVal[5]; wsprintf(tVal, _T("%d "), n+1); tsMRUArray[n] = tVal + tsMRUArray[n]; MaxMRUArrayIndex = n; } } else { tsMRUArray[0] = _T("Recent Files"); } // Set MRU menu items MENUITEMINFO mii = {0}; mii.cbSize = GetSizeofMenuItemInfo(); int nFileItem = 0; // We place the MRU items under the left most menu item CMenu* pFileMenu = GetFrameMenu().GetSubMenu(nFileItem); if (pFileMenu) { // Remove all but the first MRU Menu entry for (UINT u = IDW_FILE_MRU_FILE2; u <= IDW_FILE_MRU_FILE1 +16; ++u) { pFileMenu->DeleteMenu(u, MF_BYCOMMAND); } int MaxMRUIndex = (int)MIN(MaxMRUArrayIndex, m_nMaxMRU); for (int index = MaxMRUIndex; index >= 0; --index) { mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE; mii.fState = (0 == m_vMRUEntries.size())? MFS_GRAYED : 0; mii.fType = MFT_STRING; mii.wID = IDW_FILE_MRU_FILE1 + index; mii.dwTypeData = (LPTSTR)tsMRUArray[index].c_str(); BOOL bResult; if (index == MaxMRUIndex) // Replace the last MRU entry first bResult = pFileMenu->SetMenuItemInfo(IDW_FILE_MRU_FILE1, &mii, FALSE); else // Insert the other MRU entries next bResult = pFileMenu->InsertMenuItem(IDW_FILE_MRU_FILE1 + index + 1, &mii, FALSE); if (!bResult) { TRACE(_T("Failed to set MRU menu item\n")); break; } } } DrawMenuBar(); } inline LRESULT CFrame::WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_ACTIVATE: OnActivate(wParam, lParam); return 0L; case WM_CLOSE: OnClose(); break; case WM_DESTROY: OnDestroy(); return 0L; case WM_ERASEBKGND: return 0L; case WM_HELP: OnHelp(); return 0L; case WM_MENUCHAR: return OnMenuChar(wParam, lParam); case WM_MENUSELECT: OnMenuSelect(wParam, lParam); return 0L; case WM_SETFOCUS: OnSetFocus(); break; case WM_SIZE: RecalcLayout(); return 0L; case WM_SYSCOLORCHANGE: // Changing themes trigger this OnSysColorChange(); return 0L; case WM_SYSCOMMAND: return OnSysCommand(wParam, lParam); case WM_TIMER: OnTimer(wParam); return 0L; case WM_DRAWITEM: // Owner draw menu items return OnDrawItem(wParam, lParam); case WM_INITMENUPOPUP: OnInitMenuPopup(wParam, lParam); break; case WM_MEASUREITEM: return OnMeasureItem(wParam, lParam); case WM_EXITMENULOOP: OnExitMenuLoop(); break; case UWM_GETMENUTHEME: { MenuTheme& tm = GetMenuTheme(); return (LRESULT)&tm; } case UWM_GETREBARTHEME: { ReBarTheme& rm = GetReBarTheme(); return (LRESULT)&rm; } case UWM_GETTOOLBARTHEME: { ToolBarTheme& tt = GetToolBarTheme(); return (LRESULT)&tt; } } // switch uMsg return CWnd::WndProcDefault(uMsg, wParam, lParam); } // LRESULT CFrame::WndProcDefault(...) } // namespace Win32xx #endif // _WIN32XX_FRAME_H_