MenuBarXP.cpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. // MenuBarXP.cpp : implementation file
  2. //
  3. #include "stdafx.h"
  4. #include "MenuBarXP.h"
  5. #include "MenuXP.h"
  6. #include "..\YLGL.h"
  7. #ifdef _DEBUG
  8. #define new DEBUG_NEW
  9. #undef THIS_FILE
  10. static char THIS_FILE[] = __FILE__;
  11. #endif
  12. /////////////////////////////////////////////////////////////////////////////
  13. // CMenuBarXP
  14. CMenuBarXP::CMenuBarXP()
  15. {
  16. m_pMenu = NULL;
  17. m_bTrack = FALSE;
  18. m_nItemCount = 0;
  19. m_nPressed = 0;
  20. m_ptMouse.x = 0;
  21. m_ptMouse.y = 0;
  22. }
  23. CMenuBarXP::~CMenuBarXP()
  24. {
  25. if (m_pMenu)
  26. {
  27. delete m_pMenu;
  28. }
  29. }
  30. BEGIN_MESSAGE_MAP(CMenuBarXP, CToolBarCtrl)
  31. //{{AFX_MSG_MAP(CMenuBarXP)
  32. ON_WM_LBUTTONDOWN()
  33. ON_WM_MEASUREITEM()
  34. ON_WM_MENUCHAR()
  35. ON_WM_INITMENUPOPUP()
  36. //}}AFX_MSG_MAP
  37. ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, CToolBarXP::OnCustomDraw)
  38. ON_MESSAGE(MB_POPUPMENU, OnPopupMenu)
  39. ON_WM_EXITMENULOOP()
  40. ON_WM_ENTERMENULOOP()
  41. END_MESSAGE_MAP()
  42. /////////////////////////////////////////////////////////////////////////////
  43. // CMenuBarXP message handlers
  44. /////////////////////////////////////////////////////////////////////////////
  45. //Load from a menu, can be a CMenuXP instance or just a CMenu
  46. //the pMenu object must be constructed on the heap, it will
  47. //automatically be destoyed when the MenuBar being destroyed
  48. BOOL CMenuBarXP::LoadMenu(CMenu *pMenu)
  49. {
  50. if (!m_hWnd)
  51. return FALSE;
  52. if (!pMenu)
  53. return FALSE;
  54. if (m_pMenu)
  55. delete m_pMenu;
  56. m_pMenu = pMenu;
  57. TRACE(_T("MainMenu Handle: 0x%x\n"), m_pMenu->GetSafeHmenu());
  58. TBBUTTON tbb;
  59. int i,nStr;
  60. BOOL bRet = FALSE;
  61. TCHAR szText[_MAX_PATH];
  62. memset(&tbb, 0, sizeof(TBBUTTON));
  63. tbb.fsState = TBSTATE_ENABLED;
  64. tbb.fsStyle = TBSTYLE_BUTTON|TBSTYLE_AUTOSIZE;
  65. m_nItemCount = m_pMenu->GetMenuItemCount();//Count the main menu items
  66. SetBitmapSize(CSize(0, 0));//no icons for the main menu
  67. m_ilIcons.Create(16, 16, ILC_COLOR32 | ILC_MASK, 0, 1);
  68. for(i=0; i<m_nItemCount; i++)
  69. {
  70. memset(szText, 0, _MAX_PATH);
  71. MENUITEMINFO info;
  72. memset(&info, 0, sizeof(MENUITEMINFO));
  73. info.cbSize = sizeof(MENUITEMINFO);
  74. info.fMask = MIIM_DATA | MIIM_TYPE;
  75. m_pMenu->GetMenuItemInfo(i, &info, TRUE);
  76. CMenuXPItem *pData = (CMenuXPItem *)info.dwItemData;
  77. if (pData && (info.fType & MFT_OWNERDRAW))
  78. {
  79. lstrcpy(szText, pData->m_strText);
  80. if (pData->m_hIcon)
  81. {
  82. tbb.iBitmap = m_ilIcons.Add(pData->m_hIcon);
  83. }
  84. else
  85. tbb.iBitmap = -1;
  86. }
  87. else
  88. {
  89. m_pMenu->GetMenuString(i, szText, 80, MF_BYPOSITION);
  90. }
  91. nStr = AddStrings(szText);
  92. tbb.dwData = NULL;
  93. tbb.iString = nStr;
  94. tbb.idCommand = i;
  95. bRet = AddButtons(1, &tbb);
  96. if(!bRet)
  97. return FALSE;
  98. }
  99. if (m_ilIcons.GetImageCount()>0)
  100. SetImageList(&m_ilIcons);
  101. return bRet;
  102. }
  103. ////////////////////////////////////////////////////////////////////////////////
  104. CMenuBarXP* g_pMenuBar = NULL;
  105. HHOOK g_hMsgHook = NULL;
  106. ////////////////////////////////////////////////////////////////////////////////
  107. // The hook, used to process message when menu is visible
  108. LRESULT CMenuBarXP::MenuInputFilter(int nCode, WPARAM wParam, LPARAM lParam)
  109. {
  110. MSG* pMsg = (MSG*)lParam;
  111. if(!g_pMenuBar || nCode!=MSGF_MENU)
  112. return CallNextHookEx(g_hMsgHook,nCode,wParam,lParam);
  113. if(g_pMenuBar->OnMenuInput(pMsg))
  114. return TRUE;
  115. else
  116. return CallNextHookEx(g_hMsgHook,nCode,wParam,lParam);
  117. }
  118. //////////////////////////////////////////////////////////////////////////
  119. // Show popupmenu
  120. void CMenuBarXP::TrackPopup()
  121. {
  122. CMenu *pSubMenu = m_pMenu->GetSubMenu(m_nPressed);
  123. if(pSubMenu == NULL)return;
  124. TRACE(_T("Tracking Menu handle: 0x%x\n"), pSubMenu->GetSafeHmenu());
  125. m_bTrack = TRUE;
  126. PressButton(m_nPressed,TRUE);
  127. //Get the rect of the button
  128. CRect rc;
  129. GetItemRect(m_nPressed,&rc);
  130. ClientToScreen(&rc);
  131. //get the in-screen part of the button
  132. CRect rcScreen;
  133. GetDesktopWindow()->GetWindowRect(rcScreen);
  134. rc.IntersectRect(rc, rcScreen);
  135. TPMPARAMS tpm;
  136. tpm.cbSize = sizeof(tpm);
  137. tpm.rcExclude = rc;
  138. //Install the hook
  139. g_pMenuBar = this;
  140. g_hMsgHook = SetWindowsHookEx(WH_MSGFILTER,
  141. MenuInputFilter, NULL, GetCurrentThreadId());
  142. //Show menu
  143. TrackPopupMenuEx(pSubMenu->GetSafeHmenu(),
  144. TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_RIGHTBUTTON|TPM_VERTICAL,
  145. rc.left, rc.bottom, m_hWnd, &tpm);
  146. PressButton(m_nPressed,FALSE);
  147. UnhookWindowsHookEx(g_hMsgHook);//Uninstall the hook
  148. g_hMsgHook = NULL;
  149. g_pMenuBar = NULL;
  150. }
  151. /////////////////////////////////////////////////////////////////////////////////
  152. // Actually process messages, called by the hook
  153. BOOL CMenuBarXP::OnMenuInput(MSG* pMsg)
  154. {
  155. BOOL bResult = FALSE;
  156. switch(pMsg->message)
  157. {
  158. case WM_MOUSEMOVE:
  159. {
  160. POINT pt;
  161. pt.x = LOWORD(pMsg->lParam);
  162. pt.y = HIWORD(pMsg->lParam);
  163. ScreenToClient(&pt);
  164. if(m_ptMouse.x == pt.x && m_ptMouse.y == pt.y)
  165. return TRUE;
  166. m_ptMouse.x = pt.x;
  167. m_ptMouse.y = pt.y;
  168. int nTest = HitTest(&pt);
  169. if(nTest>=0 && nTest<m_nItemCount && nTest != m_nPressed)
  170. {
  171. PressButton(m_nPressed,FALSE);
  172. SendMessage(WM_CANCELMODE,0,0);
  173. m_nPressed = nTest;
  174. PostMessage(MB_POPUPMENU,0,0);
  175. bResult = TRUE;
  176. }
  177. }
  178. break;
  179. case WM_LBUTTONDOWN:
  180. {
  181. POINT pt;
  182. pt.x = LOWORD(pMsg->lParam);
  183. pt.y = HIWORD(pMsg->lParam);
  184. ScreenToClient(&pt);
  185. int nTest = HitTest(&pt);
  186. if(nTest<0)
  187. m_bTrack = FALSE;
  188. else if(nTest == m_nPressed)
  189. {
  190. m_bTrack = FALSE;
  191. PostMessage(WM_CANCELMODE,0,0);
  192. bResult = TRUE;
  193. }
  194. }
  195. break;
  196. case WM_KEYDOWN:
  197. {
  198. TCHAR vkey = pMsg->wParam;
  199. if(vkey == VK_LEFT)
  200. {
  201. PressButton(m_nPressed,FALSE);
  202. m_nPressed --;
  203. PostMessage(WM_CANCELMODE,0,0);
  204. PostMessage(MB_POPUPMENU,0,0);
  205. bResult = TRUE;
  206. }
  207. else if(vkey == VK_RIGHT)
  208. {
  209. PressButton(m_nPressed,FALSE);
  210. m_nPressed ++;
  211. PostMessage(WM_CANCELMODE,0,0);
  212. PostMessage(MB_POPUPMENU,0,0);
  213. bResult = TRUE;
  214. }
  215. else if (vkey == VK_ESCAPE)
  216. {
  217. PostMessage(WM_CANCELMODE,0,0);
  218. m_bTrack = FALSE;
  219. bResult = TRUE;
  220. }
  221. }
  222. break;
  223. case WM_MENUSELECT:
  224. GetOwner()->SendMessage(WM_MENUSELECT, pMsg->wParam, pMsg->lParam);
  225. bResult = TRUE;
  226. break;
  227. default:
  228. break;
  229. }
  230. return bResult;
  231. }
  232. void CMenuBarXP::OnLButtonDown(UINT nFlags, CPoint point)
  233. {
  234. // TODO: Add your message handler code here and/or call default
  235. int nTest = HitTest(&point);
  236. if(nTest<0 || nTest>=m_nItemCount)
  237. return;
  238. m_nPressed = nTest;
  239. TrackPopup();
  240. }
  241. LRESULT CMenuBarXP::OnPopupMenu(WPARAM wParam, LPARAM lParam)
  242. {
  243. if(m_nPressed<0)
  244. m_nPressed = m_nItemCount - 1;
  245. if(m_nPressed>=m_nItemCount)
  246. m_nPressed = 0;
  247. TrackPopup();
  248. return 0;
  249. }
  250. void CMenuBarXP::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct)
  251. {
  252. // TODO: Add your message handler code here and/or call default
  253. if (nIDCtl == 0 && m_pMenu)
  254. {
  255. m_pMenu->MeasureItem(lpMeasureItemStruct);
  256. }
  257. }
  258. void CMenuBarXP::OnExitMenuLoop(BOOL bIsTrackPopupMenu)
  259. {
  260. GetOwner()->SendMessage(WM_EXITMENULOOP, (WPARAM)bIsTrackPopupMenu);
  261. }
  262. void CMenuBarXP::OnEnterMenuLoop(BOOL bIsTrackPopupMenu)
  263. {
  264. GetOwner()->SendMessage(WM_ENTERMENULOOP, (WPARAM)bIsTrackPopupMenu);
  265. }
  266. LRESULT CMenuBarXP::OnMenuChar(UINT nChar, UINT nFlags, CMenu* pMenu)
  267. {
  268. return CMenuXP::OnMenuChar(nChar, nFlags, pMenu);
  269. }
  270. //If there's a main menuitem with a mnemonic key nChar, then open it
  271. BOOL CMenuBarXP::OpenMenu(UINT nChar)
  272. {
  273. int nCount = (int)m_pMenu->GetMenuItemCount();
  274. TCHAR szText[80];
  275. for(int i=0; i<m_nItemCount; i++)
  276. {
  277. MENUITEMINFO info;
  278. memset(&info, 0, sizeof(MENUITEMINFO));
  279. info.cbSize = sizeof(MENUITEMINFO);
  280. info.fMask = MIIM_DATA | MIIM_TYPE;
  281. m_pMenu->GetMenuItemInfo(i, &info, TRUE);
  282. CMenuXPItem *pData = (CMenuXPItem *)info.dwItemData;
  283. if (pData && (info.fType & MFT_OWNERDRAW))
  284. {
  285. lstrcpy(szText, pData->m_strText);
  286. }
  287. else
  288. {
  289. m_pMenu->GetMenuString(i, szText, 80, MF_BYPOSITION);
  290. }
  291. CString text = szText;
  292. int iAmpersand = text.Find('&');
  293. if (iAmpersand >=0 && toupper(nChar)==toupper(text[iAmpersand+1]))
  294. {
  295. m_nPressed = i;
  296. PostMessage(MB_POPUPMENU,0,0);
  297. return TRUE;
  298. }
  299. }
  300. return FALSE;
  301. }
  302. void CMenuBarXP::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu)
  303. {
  304. CToolBarCtrl::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu);
  305. // TODO: Add your message handler code here
  306. GetOwner()->SendMessage(WM_INITMENUPOPUP, (WPARAM)pPopupMenu->GetSafeHmenu(), MAKELONG(nIndex, bSysMenu));
  307. }