// MenuBarXP.cpp : implementation file // #include "stdafx.h" #include "MenuBarXP.h" #include "MenuXP.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CMenuBarXP CMenuBarXP::CMenuBarXP() { m_pMenu = NULL; m_bTrack = FALSE; m_nItemCount = 0; m_nPressed = 0; m_ptMouse.x = 0; m_ptMouse.y = 0; } CMenuBarXP::~CMenuBarXP() { if (m_pMenu) { delete m_pMenu; } } BEGIN_MESSAGE_MAP(CMenuBarXP, CToolBarCtrl) //{{AFX_MSG_MAP(CMenuBarXP) ON_WM_LBUTTONDOWN() ON_WM_MEASUREITEM() ON_WM_MENUCHAR() ON_WM_INITMENUPOPUP() //}}AFX_MSG_MAP ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, CToolBarXP::OnCustomDraw) ON_MESSAGE(MB_POPUPMENU, OnPopupMenu) ON_WM_EXITMENULOOP() ON_WM_ENTERMENULOOP() END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CMenuBarXP message handlers ///////////////////////////////////////////////////////////////////////////// //Load from a menu, can be a CMenuXP instance or just a CMenu //the pMenu object must be constructed on the heap, it will //automatically be destoyed when the MenuBar being destroyed BOOL CMenuBarXP::LoadMenu(CMenu *pMenu) { if (!m_hWnd) return FALSE; if (!pMenu) return FALSE; if (m_pMenu) delete m_pMenu; m_pMenu = pMenu; TRACE(_T("MainMenu Handle: 0x%x\n"), m_pMenu->GetSafeHmenu()); TBBUTTON tbb; int i,nStr; BOOL bRet = FALSE; TCHAR szText[_MAX_PATH]; memset(&tbb, 0, sizeof(TBBUTTON)); tbb.fsState = TBSTATE_ENABLED; tbb.fsStyle = TBSTYLE_BUTTON|TBSTYLE_AUTOSIZE; m_nItemCount = m_pMenu->GetMenuItemCount();//Count the main menu items SetBitmapSize(CSize(0, 0));//no icons for the main menu m_ilIcons.Create(16, 16, ILC_COLOR32 | ILC_MASK, 0, 1); for(i=0; iGetMenuItemInfo(i, &info, TRUE); CMenuXPItem *pData = (CMenuXPItem *)info.dwItemData; if (pData && (info.fType & MFT_OWNERDRAW)) { lstrcpy(szText, pData->m_strText); if (pData->m_hIcon) { tbb.iBitmap = m_ilIcons.Add(pData->m_hIcon); } else tbb.iBitmap = -1; } else { m_pMenu->GetMenuString(i, szText, 80, MF_BYPOSITION); } nStr = AddStrings(szText); tbb.dwData = NULL; tbb.iString = nStr; tbb.idCommand = i; bRet = AddButtons(1, &tbb); if(!bRet) return FALSE; } if (m_ilIcons.GetImageCount()>0) SetImageList(&m_ilIcons); return bRet; } //////////////////////////////////////////////////////////////////////////////// CMenuBarXP* g_pMenuBar = NULL; HHOOK g_hMsgHook = NULL; //////////////////////////////////////////////////////////////////////////////// // The hook, used to process message when menu is visible LRESULT CMenuBarXP::MenuInputFilter(int nCode, WPARAM wParam, LPARAM lParam) { MSG* pMsg = (MSG*)lParam; if(!g_pMenuBar || nCode!=MSGF_MENU) return CallNextHookEx(g_hMsgHook,nCode,wParam,lParam); if(g_pMenuBar->OnMenuInput(pMsg)) return TRUE; else return CallNextHookEx(g_hMsgHook,nCode,wParam,lParam); } ////////////////////////////////////////////////////////////////////////// // Show popupmenu void CMenuBarXP::TrackPopup() { CMenu *pSubMenu = m_pMenu->GetSubMenu(m_nPressed); if(pSubMenu == NULL)return; TRACE(_T("Tracking Menu handle: 0x%x\n"), pSubMenu->GetSafeHmenu()); m_bTrack = TRUE; PressButton(m_nPressed,TRUE); //Get the rect of the button CRect rc; GetItemRect(m_nPressed,&rc); ClientToScreen(&rc); //get the in-screen part of the button CRect rcScreen; GetDesktopWindow()->GetWindowRect(rcScreen); rc.IntersectRect(rc, rcScreen); TPMPARAMS tpm; tpm.cbSize = sizeof(tpm); tpm.rcExclude = rc; //Install the hook g_pMenuBar = this; g_hMsgHook = SetWindowsHookEx(WH_MSGFILTER, MenuInputFilter, NULL, GetCurrentThreadId()); //Show menu TrackPopupMenuEx(pSubMenu->GetSafeHmenu(), TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_RIGHTBUTTON|TPM_VERTICAL, rc.left, rc.bottom, m_hWnd, &tpm); PressButton(m_nPressed,FALSE); UnhookWindowsHookEx(g_hMsgHook);//Uninstall the hook g_hMsgHook = NULL; g_pMenuBar = NULL; } ///////////////////////////////////////////////////////////////////////////////// // Actually process messages, called by the hook BOOL CMenuBarXP::OnMenuInput(MSG* pMsg) { BOOL bResult = FALSE; switch(pMsg->message) { case WM_MOUSEMOVE: { POINT pt; pt.x = LOWORD(pMsg->lParam); pt.y = HIWORD(pMsg->lParam); ScreenToClient(&pt); if(m_ptMouse.x == pt.x && m_ptMouse.y == pt.y) return TRUE; m_ptMouse.x = pt.x; m_ptMouse.y = pt.y; int nTest = HitTest(&pt); if(nTest>=0 && nTestlParam); pt.y = HIWORD(pMsg->lParam); ScreenToClient(&pt); int nTest = HitTest(&pt); if(nTest<0) m_bTrack = FALSE; else if(nTest == m_nPressed) { m_bTrack = FALSE; PostMessage(WM_CANCELMODE,0,0); bResult = TRUE; } } break; case WM_KEYDOWN: { TCHAR vkey = pMsg->wParam; if(vkey == VK_LEFT) { PressButton(m_nPressed,FALSE); m_nPressed --; PostMessage(WM_CANCELMODE,0,0); PostMessage(MB_POPUPMENU,0,0); bResult = TRUE; } else if(vkey == VK_RIGHT) { PressButton(m_nPressed,FALSE); m_nPressed ++; PostMessage(WM_CANCELMODE,0,0); PostMessage(MB_POPUPMENU,0,0); bResult = TRUE; } else if (vkey == VK_ESCAPE) { PostMessage(WM_CANCELMODE,0,0); m_bTrack = FALSE; bResult = TRUE; } } break; case WM_MENUSELECT: GetOwner()->SendMessage(WM_MENUSELECT, pMsg->wParam, pMsg->lParam); bResult = TRUE; break; default: break; } return bResult; } void CMenuBarXP::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default int nTest = HitTest(&point); if(nTest<0 || nTest>=m_nItemCount) return; m_nPressed = nTest; TrackPopup(); } LRESULT CMenuBarXP::OnPopupMenu(WPARAM wParam, LPARAM lParam) { if(m_nPressed<0) m_nPressed = m_nItemCount - 1; if(m_nPressed>=m_nItemCount) m_nPressed = 0; TrackPopup(); return 0; } void CMenuBarXP::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct) { // TODO: Add your message handler code here and/or call default if (nIDCtl == 0 && m_pMenu) { m_pMenu->MeasureItem(lpMeasureItemStruct); } } void CMenuBarXP::OnExitMenuLoop(BOOL bIsTrackPopupMenu) { GetOwner()->SendMessage(WM_EXITMENULOOP, (WPARAM)bIsTrackPopupMenu); } void CMenuBarXP::OnEnterMenuLoop(BOOL bIsTrackPopupMenu) { GetOwner()->SendMessage(WM_ENTERMENULOOP, (WPARAM)bIsTrackPopupMenu); } LRESULT CMenuBarXP::OnMenuChar(UINT nChar, UINT nFlags, CMenu* pMenu) { return CMenuXP::OnMenuChar(nChar, nFlags, pMenu); } //If there's a main menuitem with a mnemonic key nChar, then open it BOOL CMenuBarXP::OpenMenu(UINT nChar) { int nCount = (int)m_pMenu->GetMenuItemCount(); TCHAR szText[80]; for(int i=0; iGetMenuItemInfo(i, &info, TRUE); CMenuXPItem *pData = (CMenuXPItem *)info.dwItemData; if (pData && (info.fType & MFT_OWNERDRAW)) { lstrcpy(szText, pData->m_strText); } else { m_pMenu->GetMenuString(i, szText, 80, MF_BYPOSITION); } CString text = szText; int iAmpersand = text.Find('&'); if (iAmpersand >=0 && toupper(nChar)==toupper(text[iAmpersand+1])) { m_nPressed = i; PostMessage(MB_POPUPMENU,0,0); return TRUE; } } return FALSE; } void CMenuBarXP::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu) { CToolBarCtrl::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu); // TODO: Add your message handler code here GetOwner()->SendMessage(WM_INITMENUPOPUP, (WPARAM)pPopupMenu->GetSafeHmenu(), MAKELONG(nIndex, bSysMenu)); }