NGenericMenu.cpp
上传用户:whjcdz88
上传日期:2007-01-02
资源大小:350k
文件大小:14k
源码类别:

工具条

开发平台:

Visual C++

  1. // NGenericMenu.cpp: implementation of the CNGenericMenu class.
  2. //
  3. /*
  4. Copyright (C) 1998 Tony Hoyle (tmh@netfusion.co.uk)
  5. This program is free software; you can redistribute it and/or modify it under the terms
  6. of the GNU General Public License as published by the Free Software Foundation; either
  7. version 2 of the License, or (at your option) any later version.
  8. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  9. without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. See the GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License along with this program;
  12. if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  13. */
  14. //////////////////////////////////////////////////////////////////////
  15. // Revised by Zhenxin Li.
  16. // Fix the no-sub-menu bug.
  17. #include "stdafx.h"
  18. #include "afxpriv.h"
  19. #include "NGenericMenu.h"
  20. #include "NGenericPopup.h"
  21. #include "NMDIClient.h"
  22. #include "resource.h"
  23. #ifdef _DEBUG
  24. #undef THIS_FILE
  25. static char THIS_FILE[]=__FILE__;
  26. #define new DEBUG_NEW
  27. #endif
  28. IMPLEMENT_DYNAMIC(CNGenericMenu,CNGenericToolBar)
  29. BEGIN_MESSAGE_MAP(CNGenericMenu,CNGenericToolBar)
  30. //{{AFX_MSG_MAP(CNGenericMenu)
  31. ON_WM_NCPAINT()
  32. ON_WM_SYSCOMMAND()
  33. ON_WM_LBUTTONDOWN()
  34. ON_WM_MOUSEMOVE()
  35. ON_WM_LBUTTONUP()
  36. ON_WM_PAINT()
  37. ON_WM_NCCALCSIZE()
  38. //}}AFX_MSG_MAP
  39. ON_MESSAGE_VOID(WM_IDLEUPDATECMDUI, OnIdleUpdateCmdUI)
  40. ON_NOTIFY_REFLECT(TBN_DROPDOWN,OnDropDown)
  41. ON_NOTIFY_REFLECT(TBN_HOTITEMCHANGE,OnHotChange)
  42. ON_UPDATE_COMMAND_UI_RANGE(65000,65100,OnMenuUpdate)
  43. ON_REGISTERED_MESSAGE(WM_MENU_DISMISS, OnDismiss)
  44. END_MESSAGE_MAP()
  45. //////////////////////////////////////////////////////////////////////
  46. // Construction/Destruction
  47. //////////////////////////////////////////////////////////////////////
  48. CNGenericMenu::CNGenericMenu()
  49. {
  50. m_bHasBitmaps=FALSE;
  51. m_bItemDropped=FALSE;
  52. m_bForceText=TRUE;
  53. m_pParent=NULL;
  54. m_hMenu=NULL;
  55. m_bSysMenuIcon=FALSE;
  56. m_pIconMap=NULL;
  57. m_nIconMapSize=0;
  58. }
  59. CNGenericMenu::~CNGenericMenu()
  60. {
  61. }
  62. BOOL CNGenericMenu::Create(CFrameWnd* pParent)
  63. {
  64. m_pParent=pParent;
  65. m_hMenu=NULL;
  66. if(!CNGenericToolBar::CreateEx(pParent,TBSTYLE_FLAT|TBSTYLE_LIST|TBSTYLE_AUTOSIZE|TBSTYLE_TRANSPARENT|TBSTYLE_TOOLTIPS,WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_SIZE_DYNAMIC,AFX_IDW_MENU_BAR)) return FALSE;
  67. // Menu font fix by lg@ndirect.co.uk
  68. NONCLIENTMETRICS info;
  69. info.cbSize = sizeof(info);
  70. SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0);
  71. VERIFY(menuFont.CreateFontIndirect(&info.lfMenuFont));
  72. SetFont(&menuFont,TRUE);
  73. CString csMenu;
  74. csMenu.LoadString(IDS_MENU);
  75. SetWindowText(csMenu);
  76. SendMessage(TB_BUTTONSTRUCTSIZE,sizeof(TBBUTTON));
  77. SendMessage(TB_SETBITMAPSIZE,0,MAKELPARAM(0,0));
  78. return TRUE;
  79. }
  80. BOOL CNGenericMenu::DrawMenuBar()
  81. {
  82. return SetMenu(m_hMenu);
  83. }
  84. BOOL CNGenericMenu::SetMenu(HMENU hMenu)
  85. {
  86. m_hMenu=hMenu;
  87. if(!hMenu) return FALSE;
  88. CToolBarCtrl* pCtrl=&GetToolBarCtrl();
  89. CMenu* pMenu=CMenu::FromHandle(hMenu);
  90. int nCount=pMenu->GetMenuItemCount();
  91. int* idString=new int[nCount];
  92. TBBUTTON* pTB=new TBBUTTON[nCount];
  93. int n;
  94. char tmp[65];
  95. LPCTSTR q;
  96. m_accelList.SetSize(0);
  97. CFrameWnd* pChildFrame=m_pParent->GetActiveFrame();
  98. if(pChildFrame && pChildFrame!=m_pParent)
  99. {
  100. m_hSysMenuIcon=(HICON)GetClassLong(*pChildFrame,GCL_HICONSM);
  101. }
  102. for(n=0; n<nCount; n++)
  103. {
  104. pMenu->GetMenuString(n,tmp,64,MF_BYPOSITION);
  105. tmp[strlen(tmp)+1]='';
  106. idString[n]=pCtrl->AddStrings(tmp);
  107. for(q=tmp; *q; q++)
  108. {
  109. if(*q=='&')
  110. {
  111. int s=m_accelList.GetSize();
  112. m_accelList.SetSize(s+1);
  113. m_accelList[s].nKey=toupper(*(q+1));
  114. m_accelList[s].nId=65000+n;
  115. break;
  116. }
  117. }
  118. memset(&pTB[n],0,sizeof(TBBUTTON));
  119. pTB[n].iBitmap=1;
  120. pTB[n].idCommand=65000+n;
  121. pTB[n].fsState=TBSTATE_ENABLED;
  122. pTB[n].fsStyle=TBSTYLE_BUTTON|TBSTYLE_DROPDOWN|TBSTYLE_AUTOSIZE;
  123. pTB[n].iString=idString[n];
  124. }
  125. while(pCtrl->DeleteButton(0))
  126. ;
  127. pCtrl->AddButtons(nCount,pTB);
  128. delete []idString;
  129. delete []pTB;
  130. RecalcSize();
  131. return TRUE;
  132. }
  133. void CNGenericMenu::OnDropDown(NMHDR * pNotifyStruct, LRESULT* result)
  134. {
  135. LPNMTOOLBAR lpnmtb = (LPNMTOOLBAR)pNotifyStruct;
  136. ShowDropDown(FALSE,lpnmtb->iItem);
  137. *result=TBDDRET_DEFAULT;
  138. }
  139. void CNGenericMenu::ShowDropDown(BOOL bFromKey, int iItem)
  140. {
  141. HMENU hPopup;
  142. CRect rect;
  143. CWnd* pParent;
  144. hPopup=*m_pParent->GetActiveFrame()->GetSystemMenu(FALSE);
  145. if(!m_bItemDropped)
  146. {
  147. if(iItem==-1)
  148. m_pParent->GetActiveFrame()->SendMessage(WM_INITMENU,(WPARAM)hPopup);
  149. else
  150. m_pParent->SendMessage(WM_INITMENU,(WPARAM)m_hMenu);
  151. }
  152. else
  153. {
  154. if(m_iItem==-1 && iItem!=-1)
  155. m_pParent->SendMessage(WM_INITMENU,(WPARAM)m_hMenu);
  156. else if(m_iItem!=-1 && iItem==-1)
  157. m_pParent->GetActiveFrame()->SendMessage(WM_INITMENU,(WPARAM)hPopup);
  158. if(m_iItem!=-1) SendMessage(TB_SETSTATE,m_iItem,TBSTATE_ENABLED);
  159. }
  160. m_iItem=iItem;
  161. m_bItemDropped=TRUE;
  162. if(iItem!=-1) SendMessage(TB_SETSTATE,iItem,TBSTATE_ENABLED|TBSTATE_PRESSED);
  163. if(iItem!=-1)
  164. {
  165. hPopup=::GetSubMenu(m_hMenu,iItem-65000);
  166. GetItemRect(iItem-65000,rect);
  167. ClientToScreen(rect);
  168. }
  169. else
  170. {
  171. CRect wr;
  172. GetWindowRect(wr);
  173. rect=m_rectSysMenu;
  174. rect.OffsetRect(wr.left,wr.top);
  175. }
  176. // revised by Zhenxin Li.
  177. // no sub menu, so return.
  178. if (!hPopup)
  179. return;
  180. if(iItem!=-1)
  181. {
  182. pParent=m_pParent;
  183. pParent->SendMessage(WM_INITMENUPOPUP,(WPARAM)hPopup,iItem-65000);
  184. }
  185. else
  186. {
  187. pParent=m_pParent->GetActiveFrame();
  188. pParent->SendMessage(WM_INITMENUPOPUP,(WPARAM)hPopup,0);
  189. }
  190. if (m_dwStyle & CBRS_ALIGN_LEFT)
  191. m_popup.ShowMenu(POP_MENU_LEFT,bFromKey,this,rect.right+1,rect.top,m_pParent,hPopup);
  192. else if(m_dwStyle & CBRS_ALIGN_RIGHT)
  193. m_popup.ShowMenu(POP_MENU_RIGHT,bFromKey,this,rect.left,rect.top,m_pParent,hPopup);
  194. else if(m_dwStyle & CBRS_ALIGN_TOP)
  195. m_popup.ShowMenu(POP_MENU_TOP,bFromKey,this,rect.left,rect.bottom+1,m_pParent,hPopup);
  196. else if(m_dwStyle & CBRS_ALIGN_BOTTOM)
  197. m_popup.ShowMenu(POP_MENU_BOTTOM,bFromKey,this,rect.left,rect.top,m_pParent,hPopup);
  198. }
  199. void CNGenericMenu::OnHotChange(NMHDR * pNotifyStruct, LRESULT* result)
  200. {
  201. LPNMTBHOTITEM lpnmtb = (LPNMTBHOTITEM)pNotifyStruct;
  202. if(m_bItemDropped && lpnmtb->idNew!=m_iItem)
  203. {
  204. if(lpnmtb->idNew)
  205. ShowDropDown(FALSE,lpnmtb->idNew);
  206. else
  207. {
  208. CPoint pt;
  209. CRect r;
  210. GetCursorPos(&pt);
  211. GetWindowRect(r);
  212. pt.x-=r.left;
  213. pt.y-=r.top;
  214. if(m_bSysMenuIcon && m_rectSysMenu.PtInRect(pt))
  215. ShowDropDown(FALSE,-1);
  216. }
  217. }
  218. *result=0;
  219. }
  220. void CNGenericMenu::OnOverSysMenu()
  221. {
  222. if(m_bItemDropped && m_iItem!=-1)
  223. ShowDropDown(FALSE,-1);
  224. }
  225. void CNGenericMenu::OnMenuUpdate(CCmdUI* pCmd)
  226. {
  227. if(!m_hMenu) return;
  228. CMenu* pMenu=CMenu::FromHandle(m_hMenu);
  229. if(!pMenu) return;
  230. pCmd->Enable(pMenu->GetMenuState(pCmd->m_nID-65000,MF_DISABLED));
  231. }
  232. LRESULT CNGenericMenu::OnDismiss(WPARAM wParam, LPARAM lParam)
  233. {
  234. if(m_bItemDropped)
  235. {
  236. if(m_iItem!=-1) SendMessage(TB_SETSTATE,m_iItem,TBSTATE_ENABLED);
  237. }
  238. m_bItemDropped=FALSE;
  239. return 0;
  240. }
  241. BOOL CNGenericMenu::TranslateMenuChar(UINT nChar)
  242. {
  243. for(int n=0; n<m_accelList.GetSize(); n++)
  244. {
  245. if(m_accelList[n].nKey==(UINT)toupper(nChar))
  246. {
  247. ShowDropDown(TRUE,m_accelList[n].nId);
  248. return TRUE;
  249. }
  250. }
  251. return FALSE;
  252. }
  253. BOOL CNGenericMenu::KeyboardFilter(UINT nChar, UINT nRepCnt, UINT nFlags)
  254. {
  255. if(m_bItemDropped)
  256. {
  257. if(nChar==VK_LEFT)
  258. {
  259. if(m_iItem>65000)
  260. ShowDropDown(TRUE,m_iItem-1);
  261. else if(m_iItem==-1)
  262. ShowDropDown(TRUE,65000+GetToolBarCtrl().GetButtonCount()-1);
  263. else
  264. ShowDropDown(TRUE,m_bSysMenuIcon?-1:65000+GetToolBarCtrl().GetButtonCount()-1);
  265. }
  266. if(nChar==VK_RIGHT)
  267. {
  268. if(m_iItem==-1)
  269. ShowDropDown(TRUE,65000);
  270. else if(m_iItem<65000+GetToolBarCtrl().GetButtonCount()-1)
  271. ShowDropDown(TRUE,m_iItem+1);
  272. else
  273. ShowDropDown(TRUE,m_bSysMenuIcon?-1:65000);
  274. }
  275. }
  276. return FALSE;
  277. }
  278. void CNGenericMenu::OnNcPaint() 
  279. {
  280. EraseNonClient(TRUE);
  281. }
  282. void CNGenericMenu::OnSysCommand(UINT nID, LPARAM lParam) 
  283. {
  284. if(m_bSysMenuIcon)
  285. {
  286. switch(nID&0xfff0)
  287. {
  288. case SC_KEYMENU:
  289. ShowDropDown(TRUE,-1);
  290. break;
  291. case SC_MOUSEMENU:
  292. ShowDropDown(FALSE,-1);
  293. break;
  294. }
  295. m_pParent->GetActiveFrame()->PostMessage(WM_SYSCOMMAND,nID,lParam);
  296. }
  297. }
  298. void CNGenericMenu::OnIdleUpdateCmdUI()
  299. {
  300. BOOL bSysMenuIcon=(m_pParent->GetActiveFrame()!=m_pParent && m_pParent->GetActiveFrame()->IsZoomed())?TRUE:FALSE;
  301. if(bSysMenuIcon!=m_bSysMenuIcon)
  302. {
  303. m_bSysMenuIcon=bSysMenuIcon;
  304. SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_FRAMECHANGED);
  305. PostMessage(WM_LBUTTONDOWN, 0, MAKELONG(-1, -1));
  306. PostMessage(WM_LBUTTONUP, 0, MAKELONG(-1, -1));
  307. }
  308. CNGenericToolBar::OnIdleUpdateCmdUI(0,0);
  309. }
  310. BOOL CNGenericMenu::SetIconMap(int nIconMapSize, IconMap* pIconMap)
  311. {
  312. m_nIconMapSize=nIconMapSize;
  313. m_pIconMap=pIconMap;
  314. return m_popup.SetIconMap(nIconMapSize,pIconMap);
  315. }
  316. CSize CNGenericMenu::CalcFixedLayout(BOOL bStretch, BOOL bHorz)
  317. {
  318. // Revised by Zhenxin Li.
  319. // Fix the WIN98(95) Showing bug. If the width value is too high, the menu bar won't be displayed.
  320. CRect r;
  321. m_pDockBar->GetParent()->GetClientRect(r);
  322. CSize s = CNGenericToolBar::CalcFixedLayout(bStretch, bHorz);
  323. if (m_dwStyle&CBRS_ORIENT_HORZ)
  324. s.cx = r.right;
  325. else
  326. s.cy = r.bottom;
  327. return s;
  328. }
  329. CSize CNGenericMenu::CalcDynamicLayout(int nLength, DWORD dwMode)
  330. {
  331. CSize s = CNGenericToolBar::CalcDynamicLayout(nLength, dwMode);
  332. // Revised by Zhenxin Li.
  333. // Make room for system icon.
  334. //#th Fixed to allow for buttons as well
  335. if (m_bSysMenuIcon)
  336. {
  337. int nSize=16; // Icon size
  338. CRect r1,r2,r3;
  339. GetSysButtonRects(r1,r2,r3);
  340. nSize=r3.right-r1.left;
  341. nSize+=12; // Gap
  342. if (m_dwStyle&CBRS_ORIENT_HORZ)
  343. s.cx += nSize;
  344. else
  345. s.cy += nSize;
  346. }
  347. return s;
  348. }
  349. void CNGenericMenu::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS FAR* lpncsp) 
  350. {
  351. CNGenericToolBar::OnNcCalcSize(bCalcValidRects, lpncsp);
  352. // Adjust for system menu icon
  353. if(m_bSysMenuIcon)
  354. {
  355. if(m_dwStyle&CBRS_ORIENT_HORZ)
  356. {
  357. // move 16 pixels right to make room
  358. lpncsp->rgrc[0].left += 16;
  359. lpncsp->rgrc[0].right += 16;
  360. }
  361. else
  362. {
  363. // move 16 pixels downto make room
  364. lpncsp->rgrc[0].top += 16;
  365. lpncsp->rgrc[0].bottom += 16;
  366. }
  367. }
  368. }
  369. void CNGenericMenu::GetSysButtonRects(CRect& r1, CRect& r2, CRect& r3)
  370. {
  371. CRect r;
  372. CPoint p;
  373. int rows = SendMessage(TB_GETROWS);
  374. int cxIcon = 16;
  375. int cyIcon = 16;
  376. #define gap1 1
  377. #define gap2 2
  378. #define bcx (3*cxIcon+gap1+gap2+1)
  379. #define bcy (3*cyIcon+gap1+gap2+1)
  380. if (m_dwStyle&CBRS_FLOATING)
  381. {
  382. GetClientRect(r);
  383. p.x = r.right - 12 - bcx;
  384. p.y = r.bottom*(rows-1)/rows+(r.bottom/rows-cyIcon)/2;
  385. }
  386. else
  387. if (m_dwStyle&CBRS_ORIENT_HORZ)
  388. {
  389. m_pDockBar->GetClientRect(r);
  390. p.x = r.right;
  391. m_pDockBar->MapWindowPoints(this, &p, 1);
  392. GetClientRect(r);
  393. p.y = r.bottom*(rows-1)/rows+(r.bottom/rows-cyIcon)/2;
  394. p.x -= bcx;
  395. }
  396. else
  397. {
  398. m_pDockBar->GetClientRect(r);
  399. p.y = r.bottom - 1;
  400. m_pDockBar->MapWindowPoints(this, &p, 1);
  401. GetClientRect(r);
  402. p.x = (r.right-cxIcon)/2;
  403. p.y -= bcy;
  404. }
  405. r1 = CRect(p, CSize(cxIcon, cyIcon));
  406. if (m_dwStyle&CBRS_ORIENT_HORZ)
  407. {
  408. r2 = r1;
  409. r2.OffsetRect(cxIcon+gap1, 0);
  410. r3 = r2;
  411. r3.OffsetRect(cxIcon+gap2, 0);
  412. }
  413. else
  414. {
  415. r2 = r1;
  416. r2.OffsetRect(0, cyIcon+gap1);
  417. r3 = r2;
  418. r3.OffsetRect(0, cyIcon+gap2);
  419. }
  420. }
  421. void CNGenericMenu::DrawButton(CDC* pDC, CRect rect, LPCTSTR szText, BOOL bPressed)
  422. {
  423. DWORD c1 = GetSysColor(COLOR_3DHILIGHT);
  424. DWORD c2 = GetSysColor(COLOR_3DDKSHADOW);
  425. DWORD c3 = GetSysColor(COLOR_3DSHADOW);
  426. if (bPressed)
  427. {
  428. pDC->FillRect(rect,&CBrush(GetSysColor(COLOR_BTNFACE)));
  429. pDC->TextOut(rect.left+4,rect.top+4,szText);
  430. pDC->Draw3dRect(rect, c2, c1);
  431. rect.top++;
  432. rect.left++;
  433. pDC->Draw3dRect(rect, c3, c1);
  434. }
  435. else
  436. {
  437. pDC->FillRect(rect,&CBrush(GetSysColor(COLOR_BTNFACE)));
  438. pDC->TextOut(rect.left+3,rect.top+3,szText);
  439. pDC->Draw3dRect(rect, c1, c2);
  440. rect.bottom--;
  441. rect.right--;
  442. pDC->Draw3dRect(rect, c1, c3);
  443. }
  444. }
  445. ENButtonState CNGenericMenu::UpdateSysButtons(UINT nFlags, CPoint point)
  446. {
  447. if (m_bSysMenuIcon)
  448. {
  449. CRect r1, r2, r3;
  450. GetSysButtonRects(r1, r2, r3);
  451. CDC* pDC = GetDC();
  452. CFont f;
  453. f.CreatePointFont(80,"Marlett",pDC);
  454. pDC->SelectObject(f);
  455. pDC->SetBkMode(TRANSPARENT);
  456. DrawButton(pDC, r1, "0", r1.PtInRect(point)?nFlags&MK_LBUTTON:0);
  457. DrawButton(pDC, r2, "2", r2.PtInRect(point)?nFlags&MK_LBUTTON:0);
  458. DrawButton(pDC, r3, "r", r3.PtInRect(point)?nFlags&MK_LBUTTON:0);
  459. ReleaseDC(pDC);
  460. if(r1.PtInRect(point)) return Button_Minimize;
  461. if(r2.PtInRect(point)) return Button_Restore;
  462. if(r3.PtInRect(point)) return Button_Close;
  463. return Button_None;
  464. }
  465. return Button_None;
  466. }
  467. void CNGenericMenu::OnLButtonDown(UINT nFlags, CPoint point) 
  468. {
  469. if (UpdateSysButtons(nFlags, point))
  470. SetCapture();
  471. else
  472. CNGenericToolBar::OnLButtonDown(nFlags, point);
  473. }
  474. void CNGenericMenu::OnMouseMove(UINT nFlags, CPoint point) 
  475. {
  476. BOOL bCapture = (::GetCapture()==m_hWnd);
  477. if (!((bCapture)&&(UpdateSysButtons(nFlags, point))))
  478. CNGenericToolBar::OnMouseMove(nFlags, point);
  479. }
  480. void CNGenericMenu::OnLButtonUp(UINT nFlags, CPoint point) 
  481. {
  482. ENButtonState state;
  483. BOOL bCapture = (::GetCapture()==m_hWnd);
  484. ReleaseCapture();
  485. if (bCapture&&(state=UpdateSysButtons(nFlags, point))!=Button_None)
  486. {
  487. switch(state)
  488. {
  489. case Button_Minimize:
  490. PostMessage(WM_SYSCOMMAND,SC_MINIMIZE);
  491. break;
  492. case Button_Restore:
  493. PostMessage(WM_SYSCOMMAND,SC_RESTORE);
  494. break;
  495. case Button_Close:
  496. PostMessage(WM_SYSCOMMAND,SC_CLOSE);
  497. break;
  498. }
  499. }
  500. else
  501. CNGenericToolBar::OnLButtonUp(nFlags, point);
  502. }
  503. void CNGenericMenu::OnPaint() 
  504. {
  505. CNGenericToolBar::OnPaint();
  506. POINT point;
  507. GetCursorPos(&point);
  508. UpdateSysButtons(0, point);
  509. }