MENUBAR.CPP
上传用户:lvjun8202
上传日期:2013-04-30
资源大小:797k
文件大小:22k
- ////////////////////////////////////////////////////////////////
- // Copyright 1998 Paul DiLascia
- // If this code works, it was written by Paul DiLascia.
- // If not, I don't know who wrote it.
- //
- // CMenuBar implements menu bar for MFC. See MenuBar.h for how
- // to use, and also the MBTest sample application.
- //
- #include "StdAfx.h"
- #include "MenuBar.h"
- #include "ModulVer.h"
- #include "Globals.h"
- const UINT MB_SET_MENU_NULL = WM_USER + 1100;
- #ifdef _DEBUG
- #define new DEBUG_NEW
- #undef THIS_FILE
- static char THIS_FILE[] = __FILE__;
- #endif
- // if you want to see extra TRACE diagnostics, set CMenuBar::bTRACE = TRUE
- BOOL CMenuBar::bTRACE = FALSE;
- #ifdef _DEBUG
- #define MBTRACEFN
- CTraceFn __fooble;
- if (CMenuBar::bTRACE)
- TRACE
- #define MBTRACE
- if (CMenuBar::bTRACE)
- TRACE
- #else
- #define MBTRACEFN TRACE
- #define MBTRACE TRACE
- #endif
- IMPLEMENT_DYNAMIC(CMenuBar, COAMToolBar)
- BEGIN_MESSAGE_MAP(CMenuBar, COAMToolBar)
- //{{AFX_MSG_MAP(CMenuBar)
- ON_WM_CREATE()
- ON_WM_LBUTTONDOWN()
- ON_WM_MOUSEMOVE()
- ON_WM_SIZE()
- //}}AFX_MSG_MAP
- ON_UPDATE_COMMAND_UI_RANGE(0, 256, OnUpdateMenuButton)
- ON_MESSAGE(MB_SET_MENU_NULL, OnSetMenuNull)
- END_MESSAGE_MAP()
- static int GetVerComCtl32()
- {
- CModuleVersion ver;
- DLLVERSIONINFO dvi;
- VERIFY(ver.DllGetVersion(_T("comctl32.dll"), dvi));
- return dvi.dwMajorVersion*100 + dvi.dwMinorVersion;
- //return 1;
- }
- CMenuBar::CMenuBar()
- {
- // if (GetVerComCtl32() <= 470)
- // AfxMessageBox(_T("Warning: This program requires comctl32.dll version 4.71 or greater."));
- m_iTrackingState = TRACK_NONE; // initial state: not tracking
- m_iPopupTracking = m_iNewPopup = -1; // invalid
- m_hmenu = NULL;
- m_bAutoRemoveFrameMenu = TRUE; // set frame's menu to NULL
- }
- CMenuBar::~CMenuBar()
- {
- }
- //////////////////
- // Menu bar was created: install hook into owner window
- //
- int CMenuBar::OnCreate(LPCREATESTRUCT lpCreateStruct)
- {
- if (COAMToolBar::OnCreate(lpCreateStruct)==-1)
- return -1;
- UpdateFont();
- CWnd* pFrame = GetOwner();
- //ASSERT_VALID(pFrame);
- m_frameHook.Install(this, *pFrame);
- return 0; // OK
- }
- //////////////////
- // Set menu bar font from current system menu font
- //
- void CMenuBar::UpdateFont()
- {
- static CFont font;
- NONCLIENTMETRICS info;
- info.cbSize = sizeof(info);
- SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0);
- if ((HFONT)font)
- font.DeleteObject();
- VERIFY(font.CreateFontIndirect(&info.lfMenuFont));
- SetFont(&font);
- }
- //////////////////
- // The reason for having this is so MFC won't automatically disable
- // the menu buttons. Assumes < 256 top-level menu items. The ID of
- // the ith menu button is i. IOW, the index and ID are the same.
- //
- void CMenuBar::OnUpdateMenuButton(CCmdUI* pCmdUI)
- {
- //ASSERT_VALID(this);
- if (IsValidButton(pCmdUI->m_nID))
- pCmdUI->Enable(TRUE);
- }
- //////////////////
- // Recompute layout of menu bar
- //
- void CMenuBar::RecomputeMenuLayout()
- {
- SetWindowPos(NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE |
- SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
- }
- //////////////////
- // Make frame recalculate control bar sizes after menu change
- //
- void CMenuBar::RecomputeToolbarSize()
- {
- // Force toolbar to recompute size
- CFrameWnd* pFrame = (CFrameWnd*)GetOwner();
- //ASSERT_VALID(pFrame);
- //SERT(pFrame->IsFrameWnd());
- pFrame->RecalcLayout();
- // floating frame
- pFrame = GetParentFrame();
- if (pFrame->IsKindOf(RUNTIME_CLASS(CMiniFrameWnd)))
- pFrame->RecalcLayout();
-
- }
- //////////////////
- // Set tracking state: none, button, or popup
- //
- void CMenuBar::SetTrackingState(TRACKINGSTATE iState, int iButton)
- {
- //SERT_VALID(this);
- if (iState != m_iTrackingState) {
- if (iState == TRACK_NONE)
- iButton = -1;
- #ifdef _DEBUG
- static LPCTSTR StateName[] = { _T("NONE"), _T("BUTTON"), _T("POPUP") };
- MBTRACE(_T("CMenuBar::SetTrackingState to %s, button=%dn"),
- StateName[iState], iButton);
- #endif
- GetToolBarCtrl().SetHotItem(iButton); // could be none (-1)
- if (iState==TRACK_POPUP) {
- // set related state stuff
- m_bEscapeWasPressed = FALSE; // assume Esc key not pressed
- m_bProcessRightArrow = // assume left/right arrow..
- m_bProcessLeftArrow = TRUE; // ..will move to prev/next popup
- m_iPopupTracking = iButton; // which popup I'm tracking
- }
- m_iTrackingState = iState;
- }
- }
- //////////////////
- // Toggle state from home state to button-tracking and back
- //
- void CMenuBar::ToggleTrackButtonMode()
- {
- //SERT_VALID(this);
- if (m_iTrackingState == TRACK_NONE || m_iTrackingState == TRACK_BUTTON) {
- SetTrackingState(m_iTrackingState == TRACK_NONE ?
- TRACK_BUTTON : TRACK_NONE, 0);
- }
- }
- //////////////////
- // Get button index before/after a given button
- //
- int CMenuBar::GetNextOrPrevButton(int iButton, BOOL bPrev)
- {
- //SERT_VALID(this);
- if (bPrev) {
- iButton--;
- if (iButton <0)
- iButton = GetToolBarCtrl().GetButtonCount() - 1;
- } else {
- iButton++;
- if (iButton >= GetToolBarCtrl().GetButtonCount())
- iButton = 0;
- }
- return iButton;
- }
- /////////////////
- // This is to correct a bug in the system toolbar control: TB_HITTEST only
- // looks at the buttons, not the size of the window. So it returns a button
- // hit even if that button is totally outside the size of the window!
- //
- int CMenuBar::HitTest(CPoint p) const
- {
- int iHit = GetToolBarCtrl().HitTest(&p);
- if (iHit>0) {
- CRect rc;
- GetClientRect(&rc);
- if (!rc.PtInRect(p)) // if point is outside window
- iHit = -1; // can't be a hit!
- }
- return iHit;
- }
- //////////////////
- // Load a different menu. The HMENU must not belong to any CMenu,
- // and you must free it when you're done. Returns old menu.
- //
- HMENU CMenuBar::LoadMenu(HMENU hmenu)
- {
- MBTRACEFN(_T("CMenuBar::LoadMenun"));
- UINT iPrevID=(UINT)-1;
- //ASSERT(::IsMenu(hmenu));
- //ASSERT_VALID(this);
- if (m_bAutoRemoveFrameMenu) {
- CFrameWnd* pFrame = GetParentFrame();
- if (::GetMenu(*pFrame)!=NULL) {
- // I would like to set the frame's menu to NULL now, but if I do, MFC
- // gets all upset: it calls GetMenu and expects to have a real menu.
- // So Instead, I post a message to myself. Because the message is
- // posted, not sent, I won't process it until MFC is done with all its
- // initialization stuff. (MFC needs to set CFrameWnd::m_hMenuDefault
- // to the menu, which it gets by calling GetMenu.)
- //
- PostMessage(MB_SET_MENU_NULL, (WPARAM)pFrame->GetSafeHwnd());
- }
- }
- HMENU hOldMenu = m_hmenu;
- m_hmenu = hmenu;
- // delete existing buttons
- int nCount = GetToolBarCtrl().GetButtonCount();
- while (nCount--) {
- VERIFY(GetToolBarCtrl().DeleteButton(0));
- }
- GetToolBarCtrl().SetImageList(NULL);
- // SetButtonSize(CSize(0,0)); // This barfs in VC 6.0
- DWORD dwStyle = GetStyle();
- BOOL bModifyStyle = ModifyStyle(0, TBSTYLE_FLAT|TBSTYLE_TRANSPARENT);
- // add text buttons
- UINT nMenuItems = hmenu ? ::GetMenuItemCount(hmenu) : 0;
- for (UINT i=0; i < nMenuItems; i++) {
- TCHAR name[64];
- memset(name, 0, sizeof(name)); // guarantees double-0 at end
- if (::GetMenuString(hmenu, i, name, countof(name)-1, MF_BYPOSITION)) {
- TBBUTTON tbb;
- memset(&tbb, 0, sizeof(tbb));
- tbb.idCommand = ::GetMenuItemID(hmenu, i);
- // Because the toolbar is too brain-damaged to know if it already has
- // a string, and is also too brain-dead to even let you delete strings,
- // I have to determine if each string has been added already. Otherwise
- // in a MDI app, as the menus are repeatedly switched between doc and
- // no-doc menus, I will keep adding strings until somebody runs out of
- // memory. Sheesh!
- //
- int iString = -1;
- for (int j=0; j<m_arStrings.GetSize(); j++) {
- if (m_arStrings[j] == name) {
- iString = j; // found it
- break;
- }
- }
- if (iString <0) {
- // string not found: add it
- iString = GetToolBarCtrl().AddStrings(name);
- m_arStrings.SetAtGrow(iString, name);
- }
- tbb.iString = iString;
- tbb.fsState = TBSTATE_ENABLED;
- tbb.fsStyle = TBSTYLE_AUTOSIZE;
- tbb.iBitmap = -1;
- tbb.idCommand = i;
- VERIFY(GetToolBarCtrl().AddButtons(1, &tbb));
- }
- }
- if (bModifyStyle)
- SetWindowLong(m_hWnd, GWL_STYLE, dwStyle);
-
- if (hmenu) {
- GetToolBarCtrl().AutoSize(); // size buttons
- RecomputeToolbarSize(); // and menubar itself
- }
- return hOldMenu;
- }
- //////////////////
- // Load menu from resource
- //
- HMENU CMenuBar::LoadMenu(LPCSTR lpszMenuName)
- {
- return LoadMenu(::LoadMenu(AfxGetResourceHandle(), lpszMenuName));
- }
- //////////////////
- // Set the frame's menu to NULL. WPARAM is HWND of frame.
- //
- LRESULT CMenuBar::OnSetMenuNull(WPARAM wp, LPARAM lp)
- {
- HWND hwnd = (HWND)wp;
- //ASSERT(::IsWindow(hwnd));
- ::SetMenu(hwnd, NULL);
- return 0;
- }
- //////////////////
- // Handle mouse click: if clicked on button, press it
- // and go into main menu loop.
- //
- void CMenuBar::OnLButtonDown(UINT nFlags, CPoint pt)
- {
- MBTRACEFN(_T("CMenuBar::OnLButtonDownn"));
- //ASSERT_VALID(this);
- int iButton = HitTest(pt);
- if (iButton >= 0 && iButton<GetToolBarCtrl().GetButtonCount()) // if mouse is over a button:
- TrackPopup(iButton); // track it
- else // otherwise:
- COAMToolBar::OnLButtonDown(nFlags, pt); // pass it on...
- }
- //////////////////
- // Handle mouse movement
- //
- void CMenuBar::OnMouseMove(UINT nFlags, CPoint pt)
- {
- //ASSERT_VALID(this);
- if (m_iTrackingState==TRACK_BUTTON) {
- // In button-tracking state, ignore mouse-over to non-button area.
- // Normally, the toolbar would de-select the hot item in this case.
- //
- // Only change the hot item if the mouse has actually moved.
- // This is necessary to avoid a bug where the user moves to a different
- // button from the one the mouse is over, and presses arrow-down to get
- // the menu, then Esc to cancel it. Without this code, the button will
- // jump to wherever the mouse is--not right.
- int iHot = HitTest(pt);
- if (IsValidButton(iHot) && pt != m_ptMouse)
- GetToolBarCtrl().SetHotItem(iHot);
- return; // don't let toolbar get it
- }
- m_ptMouse = pt; // remember point
- COAMToolBar::OnMouseMove(nFlags, pt);
- }
- //////////////////
- // Window was resized: need to recompute layout
- //
- void CMenuBar::OnSize(UINT nType, int cx, int cy)
- {
- COAMToolBar::OnSize(nType, cx, cy);
- RecomputeMenuLayout();
- }
- //////////////////
- // Bar style changed: eg, moved from left to right dock or floating
- //
- void CMenuBar::OnBarStyleChange(DWORD dwOldStyle, DWORD dwNewStyle)
- {
- COAMToolBar::OnBarStyleChange(dwOldStyle, dwNewStyle);
- RecomputeMenuLayout();
- }
- /////////////////
- // When user selects a new menu item, note whether it has a submenu
- // and/or parent menu, so I know whether right/left arrow should
- // move to the next popup.
- //
- void CMenuBar::OnMenuSelect(HMENU hmenu, UINT iItem)
- {
- if (m_iTrackingState > 0) {
- // process right-arrow iff item is NOT a submenu
- m_bProcessRightArrow = (::GetSubMenu(hmenu, iItem) == NULL);
- // process left-arrow iff curent menu is one I'm tracking
- m_bProcessLeftArrow = hmenu==m_hMenuTracking;
- }
- }
- // globals--yuk! But no other way using windows hooks.
- //
- static CMenuBar* g_pMenuBar = NULL;
- static HHOOK g_hMsgHook = NULL;
- ////////////////
- // Menu filter hook just passes to virtual CMenuBar function
- //
- LRESULT CALLBACK
- CMenuBar::MenuInputFilter(int code, WPARAM wp, LPARAM lp)
- {
- return (code==MSGF_MENU && g_pMenuBar &&
- g_pMenuBar->OnMenuInput(*((MSG*)lp))) ? TRUE
- : CallNextHookEx(g_hMsgHook, code, wp, lp);
- }
- //////////////////
- // Handle menu input event: Look for left/right to change popup menu,
- // mouse movement over over a different menu button for "hot" popup effect.
- // Returns TRUE if message handled (to eat it).
- //
- BOOL CMenuBar::OnMenuInput(MSG& m)
- {
- //ASSERT_VALID(this);
- //ASSERT(m_iTrackingState == TRACK_POPUP); // sanity check
- int msg = m.message;
- if (msg==WM_KEYDOWN) {
- // handle left/right-arow.
- TCHAR vkey = m.wParam;
- if ((vkey == VK_LEFT && m_bProcessLeftArrow) ||
- (vkey == VK_RIGHT && m_bProcessRightArrow)) {
- MBTRACE(_T("CMenuBar::OnMenuInput: handle VK_LEFT/RIGHTn"));
- CancelMenuAndTrackNewOne(
- GetNextOrPrevButton(m_iPopupTracking, vkey==VK_LEFT));
- return TRUE; // eat it
- } else if (vkey == VK_ESCAPE) {
- m_bEscapeWasPressed = TRUE; // (menu will abort itself)
- }
- } else if (msg==WM_MOUSEMOVE || msg==WM_LBUTTONDOWN) {
- // handle mouse move or click
- CPoint pt = m.lParam;
- ScreenToClient(&pt);
- if (msg == WM_MOUSEMOVE) {
- if (pt != m_ptMouse) {
- int iButton = HitTest(pt);
- if (IsValidButton(iButton) && iButton != m_iPopupTracking) {
- // user moved mouse over a different button: track its popup
- CancelMenuAndTrackNewOne(iButton);
- }
- m_ptMouse = pt;
- }
- } else if (msg == WM_LBUTTONDOWN) {
- if (HitTest(pt) == m_iPopupTracking) {
- // user clicked on same button I am tracking: cancel menu
- MBTRACE(_T("CMenuBar:OnMenuInput: handle mouse click to exit popupn"));
- CancelMenuAndTrackNewOne(-1);
- return TRUE; // eat it
- }
- }
- }
- return FALSE; // not handled
- }
- //////////////////
- // Cancel the current popup menu by posting WM_CANCELMODE, and track a new
- // menu. iNewPopup is which new popup to track (-1 to quit).
- //
- void CMenuBar::CancelMenuAndTrackNewOne(int iNewPopup)
- {
- MBTRACE(_T("CMenuBar::CancelMenuAndTrackNewOne: %dn"), iNewPopup);
- //ASSERT_VALID(this);
- if (iNewPopup != m_iPopupTracking) {
- GetOwner()->PostMessage(WM_CANCELMODE); // quit menu loop
- m_iNewPopup = iNewPopup; // go to this popup (-1 = quit)
- }
- }
- //////////////////
- // Track the popup submenu associated with the i'th button in the menu bar.
- // This fn actually goes into a loop, tracking different menus until the user
- // selects a command or exits the menu.
- //
- void CMenuBar::TrackPopup(int iButton)
- {
- MBTRACE(_T("CMenuBar::TrackPopup %dn"), iButton);
- //ASSERT_VALID(this);
- //ASSERT(m_hmenu);
- CMenu menu;
- menu.Attach(m_hmenu);
- int nMenuItems = menu.GetMenuItemCount();
- while (iButton >= 0) { // while user selects another menu
- m_iNewPopup = -1; // assume quit after this
- GetToolBarCtrl().PressButton(iButton, TRUE); // press the button
- UpdateWindow(); // and force repaint now
- // post a simulated arrow-down into the message stream
- // so TrackPopupMenu will read it and move to the first item
- GetOwner()->PostMessage(WM_KEYDOWN, VK_DOWN, 1);
- GetOwner()->PostMessage(WM_KEYUP, VK_DOWN, 1);
- SetTrackingState(TRACK_POPUP, iButton); // enter tracking state
- // Need to install a hook to trap menu input in order to make
- // left/right-arrow keys and "hot" mouse tracking work.
- //
- //ASSERT(g_pMenuBar == NULL);
- g_pMenuBar = this;
- //ASSERT(g_hMsgHook == NULL);
- g_hMsgHook = SetWindowsHookEx(WH_MSGFILTER,
- MenuInputFilter, NULL, ::GetCurrentThreadId());
- // get submenu and display it beneath button
- TPMPARAMS tpm;
- CRect rcButton;
- GetToolBarCtrl().GetRect(iButton, rcButton);
- ClientToScreen(&rcButton);
- CPoint pt = ComputeMenuTrackPoint(rcButton, tpm);
- HMENU hMenuPopup = ::GetSubMenu(m_hmenu, iButton);
- //ASSERT(hMenuPopup);
- BOOL bRet = TrackPopupMenuEx(hMenuPopup,
- TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_VERTICAL,
- pt.x, pt.y, GetOwner()->GetSafeHwnd(), &tpm);
- // uninstall hook.
- ::UnhookWindowsHookEx(g_hMsgHook);
- g_hMsgHook = NULL;
- g_pMenuBar = NULL;
- GetToolBarCtrl().PressButton(iButton, FALSE); // un-press button
- UpdateWindow(); // and force repaint now
- // If the user exited the menu loop by pressing Escape,
- // return to track-button state; otherwise normal non-tracking state.
- SetTrackingState(m_bEscapeWasPressed ?
- TRACK_BUTTON : TRACK_NONE, iButton);
- // If the user moved mouse to a new top-level popup (eg from File to
- // Edit button), I will have posted a WM_CANCELMODE to quit
- // the first popup, and set m_iNewPopup to the new menu to show.
- // Otherwise, m_iNewPopup will be -1 as set above.
- // So just set iButton to the next popup menu and keep looping...
- iButton = m_iNewPopup;
- }
- menu.Detach();
- }
- //////////////////
- // Given button rectangle, compute point and "exclude rect" for
- // TrackPopupMenu, based on current docking style, so that the menu will
- // appear always inside the window.
- //
- CPoint CMenuBar::ComputeMenuTrackPoint(const CRect& rcButn, TPMPARAMS& tpm)
- {
- tpm.cbSize = sizeof(tpm);
- DWORD dwStyle = m_dwStyle;
- CPoint pt;
- CRect& rcExclude = (CRect&)tpm.rcExclude;
- rcExclude = rcButn;
- ::GetWindowRect(::GetDesktopWindow(), &rcExclude);
- switch (dwStyle & CBRS_ALIGN_ANY) {
- case CBRS_ALIGN_BOTTOM:
- pt = CPoint(rcButn.left, rcButn.top);
- rcExclude.top = rcButn.top;
- break;
- case CBRS_ALIGN_LEFT:
- pt = CPoint(rcButn.right, rcButn.top);
- rcExclude.right = rcButn.right;
- break;
- case CBRS_ALIGN_RIGHT:
- pt = CPoint(rcButn.left, rcButn.top);
- rcExclude.left = rcButn.left;
- break;
- default: // case CBRS_ALIGN_TOP:
- pt = CPoint(rcButn.left, rcButn.bottom);
- break;
- }
- return pt;
- }
- //////////////////
- // This function translates special menu keys and mouse actions.
- // You must call it from your frame's PreTranslateMessage.
- //
- BOOL CMenuBar::TranslateFrameMessage(MSG* pMsg)
- {
- //ASSERT_VALID(this);
- //ASSERT(pMsg);
- UINT msg = pMsg->message;
- if (WM_LBUTTONDOWN <= msg && msg <= WM_MOUSELAST) {
- if (pMsg->hwnd != m_hWnd && m_iTrackingState > 0) {
- // user clicked outside menu bar: exit tracking mode
- MBTRACE(_T("CMenuBar::TranslateFrameMessage: user clicked outside menu bar: end trackingn"));
- SetTrackingState(TRACK_NONE);
- }
- } else if (msg==WM_SYSKEYDOWN || msg==WM_SYSKEYUP || msg==WM_KEYDOWN) {
- BOOL bAlt = HIWORD(pMsg->lParam) & KF_ALTDOWN; // Alt key down
- TCHAR vkey = pMsg->wParam; // get virt key
- if (vkey==VK_MENU ||
- (vkey==VK_F10 && !((GetKeyState(VK_SHIFT) & 0x80000000) ||
- (GetKeyState(VK_CONTROL) & 0x80000000) || bAlt))) {
- // key is VK_MENU or F10 with no alt/ctrl/shift: toggle menu mode
- if (msg==WM_SYSKEYUP) {
- MBTRACE(_T("CMenuBar::TranslateFrameMessage: handle menu keyn"));
- ToggleTrackButtonMode();
- }
- return TRUE;
- } else if ((msg==WM_SYSKEYDOWN || msg==WM_KEYDOWN)) {
- if (m_iTrackingState == TRACK_BUTTON) {
- // I am tracking: handle left/right/up/down/space/Esc
- switch (vkey) {
- case VK_LEFT:
- case VK_RIGHT:
- // left or right-arrow: change hot button if tracking buttons
- MBTRACE(_T("CMenuBar::TranslateFrameMessage: VK_LEFT/RIGHTn"));
- GetToolBarCtrl().SetHotItem(GetNextOrPrevButton(GetToolBarCtrl().GetHotItem(), vkey==VK_LEFT));
- return TRUE;
- case VK_SPACE: // (personally, I like SPACE to enter menu too)
- case VK_UP:
- case VK_DOWN:
- // up or down-arrow: move into current menu, if any
- MBTRACE(_T("CMenuBar::TranslateFrameMessage: VK_UP/DOWN/SPACEn"));
- TrackPopup(GetToolBarCtrl().GetHotItem());
- return TRUE;
- case VK_ESCAPE:
- // escape key: exit tracking mode
- MBTRACE(_T("CMenuBar::TranslateFrameMessage: VK_ESCAPEn"));
- SetTrackingState(TRACK_NONE);
- return TRUE;
- }
- }
- // Handle alphanumeric key: invoke menu. Note that Alt-X
- // chars come through as WM_SYSKEYDOWN, plain X as WM_KEYDOWN.
- if ((bAlt || m_iTrackingState == TRACK_BUTTON) && isalnum(vkey)) {
- // Alt-X, or else X while in tracking mode
- UINT nID;
- if (GetToolBarCtrl().MapAccelerator(vkey, &nID)) {
- MBTRACE(_T("CMenuBar::TranslateFrameMessage: map accleratorn"));
- TrackPopup(nID); // found menu mnemonic: track it
- return TRUE; // handled
- } else if (m_iTrackingState==TRACK_BUTTON && !bAlt) {
- MessageBeep(0);
- return TRUE;
- }
- }
- // Default for any key not handled so far: return to no-menu state
- if (m_iTrackingState > 0) {
- MBTRACE(_T("CMenuBar::TranslateFrameMessage: unknown key, stop trackingn"));
- SetTrackingState(TRACK_NONE);
- }
- }
- }
- return FALSE; // not handled, pass along
- }
- #ifdef _DEBUG
- void CMenuBar::AssertValid() const
- {
- COAMToolBar::AssertValid();
- //ASSERT(m_hmenu==NULL || ::IsMenu(m_hmenu));
- //ASSERT(TRACK_NONE<=m_iTrackingState && m_iTrackingState<=TRACK_POPUP);
- m_frameHook.AssertValid();
- }
- void CMenuBar::Dump(CDumpContext& dc) const
- {
- COAMToolBar::Dump(dc);
- }
- #endif
- //////////////////////////////////////////////////////////////////
- // CMenuBarFrameHook is used to trap menu-related messages sent to the owning
- // frame. The same class is also used to trap messages sent to the MDI client
- // window in an MDI app. I should really use two classes for this,
- // but it uses less code to chare the same class. Note however: there
- // are two different INSTANCES of CMenuBarFrameHook in CMenuBar: one for
- // the frame and one for the MDI client window.
- //
- CMenuBarFrameHook::CMenuBarFrameHook()
- {
- }
- CMenuBarFrameHook::~CMenuBarFrameHook()
- {
- HookWindow((HWND)NULL); // (unhook)
- }
- //////////////////
- // Install hook to trap window messages sent to frame or MDI client.
- //
- BOOL CMenuBarFrameHook::Install(CMenuBar* pMenuBar, HWND hWndToHook)
- {
- //ASSERT_VALID(pMenuBar);
- m_pMenuBar = pMenuBar;
- return HookWindow(hWndToHook);
- }
- //////////////////////////////////////////////////////////////////
- // Trap frame/MDI client messages specific to menubar.
- //
- LRESULT CMenuBarFrameHook::WindowProc(UINT msg, WPARAM wp, LPARAM lp)
- {
- CMenuBar& mb = *m_pMenuBar;
- switch (msg) {
- // The following messages are trapped for the frame window
- case WM_SYSCOLORCHANGE:
- mb.UpdateFont();
- break;
- case WM_MENUSELECT:
- mb.OnMenuSelect((HMENU)lp, (UINT)LOWORD(wp));
- break;
- }
- return CSubclassWnd::WindowProc(msg, wp, lp);
- }