BitmapMenu.cpp
上传用户:jbj_wl
上传日期:2007-01-02
资源大小:6k
文件大小:13k
源码类别:

菜单

开发平台:

Visual C++

  1. #include <afxwin.h>
  2. #include <afxcmn.h>
  3. #include <afxtempl.h>
  4. #include <BitmapMenu.h>
  5. BMenuData::BMenuData()
  6. {
  7. menuIconNormal = -1;
  8. menuIconSelected = -1;
  9. menuIconDisabled = -1;
  10. nID = 0;
  11. }
  12. CBitmapMenu::CBitmapMenu(CImageList* pList)
  13. {
  14. SetImageList(pList);
  15. m_clrText =  GetSysColor(COLOR_MENUTEXT);
  16. m_clrBack = GetSysColor(COLOR_MENU);
  17. m_brBackground.CreateSolidBrush(m_clrBack);
  18. m_penBack.CreatePen(PS_SOLID,0,m_clrBack);
  19. m_bLBtnDown = FALSE;
  20. m_hilightStyle = Normal;
  21. m_clrHilight = GetSysColor(COLOR_HIGHLIGHT);
  22. m_brSelect.CreateSolidBrush(m_clrHilight);
  23. m_clrHilightText = GetSysColor(COLOR_HIGHLIGHTTEXT);
  24. ZeroMemory((LPVOID)&m_lf,sizeof(LOGFONT));
  25. NONCLIENTMETRICS nm;
  26. nm.cbSize = sizeof(NONCLIENTMETRICS);
  27. //Get the system metrics for the Captionfromhere
  28. VERIFY(SystemParametersInfo(SPI_GETNONCLIENTMETRICS,0,&nm,0)); 
  29. m_lf = nm.lfMenuFont;
  30. m_iMenuHeight = nm.iMenuHeight;
  31. m_fontMenu.CreateFontIndirect(&m_lf);
  32. }
  33. CBitmapMenu::~CBitmapMenu()
  34. {
  35. DestroyMenu();
  36. }
  37. BOOL CBitmapMenu::DestroyMenu()
  38. {
  39. // Destroy Sub menus:
  40. int m;
  41. for( m = m_SubMenus.GetUpperBound(); m >= 0; m-- )
  42. delete(m_SubMenus[m]);
  43. m_SubMenus.RemoveAll();
  44. // Destroy brushes:
  45. if( (HBRUSH)m_brBackground != NULL )
  46. m_brBackground.DeleteObject();
  47. if( (HFONT)m_fontMenu != NULL )
  48. m_fontMenu.DeleteObject();
  49. if( (HBRUSH)m_brSelect != NULL )
  50. m_brSelect.DeleteObject ();
  51. // Destroy menu data
  52. int numItems;
  53. numItems = m_MenuList.GetUpperBound();
  54. for( m = 0; m <= numItems; m++ )
  55. delete(m_MenuList[m]);
  56. m_MenuList.RemoveAll();
  57. // Call base-class implementation last:
  58. return(CMenu::DestroyMenu());
  59. }
  60. /*
  61. =================================================================================
  62. void CBitmapMenu::DrawItem(LPDRAWITEMSTRUCT)
  63. ---------------------------------------
  64. Called by the framework when a particular item needs to be drawn.  We overide
  65. this to draw the menu item in a custom-fashion, including icons and the 3D
  66. rectangle bar.
  67. =================================================================================
  68. */
  69. void CBitmapMenu::DrawItem(LPDRAWITEMSTRUCT lpDIS)
  70. {
  71. ASSERT(lpDIS != NULL);
  72. CDC* pDC;
  73. pDC = CDC::FromHandle(lpDIS->hDC);
  74. CRect rect;
  75. HICON hIcon;
  76. COLORREF clrText;
  77. clrText = m_clrText;
  78. // draw the colored rectangle portion
  79. rect.CopyRect(&lpDIS->rcItem);
  80. // draw the up/down/focused/disabled state
  81. UINT action;
  82. UINT state;
  83. action = lpDIS->itemAction;
  84. state = lpDIS->itemState;
  85. CString strText;
  86. LOGFONT lf;
  87. lf = m_lf;
  88. CFont dispFont;
  89. CFont *pFont;
  90. if( lpDIS->itemData != NULL )
  91. {
  92. int nIconNormal = (((BMenuData*)(lpDIS->itemData))->menuIconNormal);
  93. int nIconSelected = (((BMenuData*)(lpDIS->itemData))->menuIconSelected);
  94. int nIconDisabled = (((BMenuData*)(lpDIS->itemData))->menuIconDisabled);
  95. strText = (((BMenuData*)(lpDIS->itemData))->menuText);
  96. if(nIconNormal == -1)
  97. hIcon = NULL;
  98. else
  99. {
  100. hIcon = NULL;
  101. // Obtain the IDs for the appropriate Icons:
  102. if( state & ODS_SELECTED && !(state & ODS_GRAYED) )
  103. {
  104. // Selected (but not disabled)
  105. if( nIconSelected != -1 )
  106. hIcon = m_pList->ExtractIcon(nIconSelected);
  107. }
  108. else
  109. {
  110. if( state & ODS_GRAYED )
  111. // Disabled (selected or not)
  112. if( nIconDisabled != -1 )
  113. hIcon = m_pList->ExtractIcon(nIconDisabled);
  114. }
  115. // If we didn't manage to select a specific icon, we'll use the
  116. // default (normal) one...
  117. if( hIcon == NULL )
  118. hIcon = m_pList->ExtractIcon(nIconNormal);
  119. }
  120. }
  121. else
  122. {
  123. strText.Empty();
  124. hIcon = NULL;
  125. }
  126. if( (state & ODS_SELECTED) )
  127. {
  128. // draw the down edges
  129. CPen *pOldPen = pDC->SelectObject(&m_penBack);
  130. // You need only Text highlight and thats what you get
  131. if( m_hilightStyle != Normal )
  132. pDC->FillRect(rect,&m_brBackground);
  133. else
  134. pDC->FillRect(rect,&m_brSelect);
  135. pDC->SelectObject(pOldPen);
  136. // This version provides a black-border:
  137. //pDC->Draw3dRect(rect,GetSysColor (COLOR_3DHILIGHT),RGB(0,0,0));
  138. //lf.lfWeight = FW_BOLD;
  139. if( (HFONT)dispFont != NULL )
  140. dispFont.DeleteObject();
  141. dispFont.CreateFontIndirect(&lf);
  142. clrText = m_clrHilightText;
  143. }
  144. else
  145. {
  146. CPen *pOldPen = pDC->SelectObject(&m_penBack);
  147. pDC->FillRect (rect,&m_brBackground);
  148. pDC->SelectObject (pOldPen);
  149. // draw the up edges
  150. pDC->Draw3dRect (rect,m_clrBack,m_clrBack);
  151. if( (HFONT)dispFont != NULL )
  152. dispFont.DeleteObject();
  153. dispFont.CreateFontIndirect(&lf);
  154. }
  155. // draw the text if there is any
  156. //We have to paint the text only if the image is nonexistant
  157. if (hIcon != NULL)
  158. DrawIconEx(pDC->GetSafeHdc(), rect.left,
  159. rect.top + (rect.Height() - m_nIconY) / 2, hIcon,
  160. m_nIconX, m_nIconY, 0, NULL, DI_NORMAL);
  161. rect.left = rect.left + m_nIconX + 2;
  162. if( !strText.IsEmpty() )
  163. {
  164. int iOldMode = pDC->GetBkMode();
  165. pDC->SetBkMode(TRANSPARENT);
  166. // Draw the text in the correct colour:
  167. UINT nFormat = DT_LEFT|DT_SINGLELINE|DT_EXPANDTABS|DT_VCENTER;
  168. if( !(lpDIS->itemState & ODS_GRAYED) )
  169. {
  170. pDC->SetTextColor(clrText);
  171. pDC->DrawText (strText,rect,nFormat);
  172. }
  173. else
  174. {
  175. // Draw the slightly lighter greyed text at an offset:
  176. RECT offset = *rect;
  177. offset.left += 1;
  178. offset.right += 1;
  179. offset.top += 1;
  180. offset.bottom += 1;
  181. pDC->SetTextColor(GetSysColor(COLOR_BTNHILIGHT));
  182. pDC->DrawText(strText,&offset, nFormat);
  183. // And the standard Grey text:
  184. pDC->SetTextColor(GetSysColor(COLOR_GRAYTEXT));
  185. pDC->DrawText(strText,rect, nFormat);
  186. }
  187. pFont = pDC->SelectObject(&dispFont);
  188. pDC->SetBkMode(iOldMode);
  189. pDC->SelectObject(pFont); //set it to the old font
  190. }
  191. dispFont.DeleteObject();
  192. }
  193. /*
  194. =================================================================================
  195. void CBitmapMenu::MeasureItem(LPMEASUREITEMSTRUCT)
  196. ---------------------------------------------
  197. Called by the framework when it wants to know what the width and height of our
  198. item will be.  To accomplish this we provide the width of the icon plus the
  199. width of the menu text, and then the height of the icon.
  200. =================================================================================
  201. */
  202. void CBitmapMenu::MeasureItem(LPMEASUREITEMSTRUCT lpMIS)
  203. {
  204. // Obtain the width of the text:
  205. CWnd *pWnd = AfxGetMainWnd(); // Get main window
  206. CDC *pDC = pWnd->GetDC(); // Get device context
  207. CFont* pFont = pDC->SelectObject(&m_fontMenu); // Select menu font in...
  208. LPCTSTR lpstrText = (((BMenuData*)(lpMIS->itemData))->menuText); // Get pointer to text
  209. SIZE t;
  210. GetTextExtentPoint32(pDC->GetSafeHdc(), lpstrText, strlen(lpstrText), &t); // Width of caption
  211. pDC->SelectObject(pFont); // Select old font in
  212. pWnd->ReleaseDC(pDC); // Release the DC
  213. lpMIS->itemWidth = t.cx;
  214. lpMIS->itemHeight = max(GetSystemMetrics(SM_CYMENU), t.cy);
  215. lpMIS->itemWidth += m_nIconX;
  216. lpMIS->itemHeight = max(m_nIconY, lpMIS->itemHeight);
  217. }
  218. void CBitmapMenu::SetTextColor(COLORREF clrText)
  219. {
  220. m_clrText = clrText;
  221. }
  222. void CBitmapMenu::SetBackColor(COLORREF clrBack)
  223. {
  224. m_clrBack = clrBack;
  225. if( (HBRUSH)m_brBackground != NULL )
  226. m_brBackground.DeleteObject();
  227. m_brBackground.CreateSolidBrush (clrBack);
  228. }
  229. void CBitmapMenu::SetHighlightColor(COLORREF clrHilight)
  230. {
  231. m_clrHilight = clrHilight;
  232. if( (HBRUSH)m_brSelect != NULL )
  233. m_brSelect.DeleteObject();
  234. m_brSelect.CreateSolidBrush(clrHilight);
  235. }
  236. void CBitmapMenu::SetHighlightTextColor(COLORREF clrHilightText)
  237. {
  238. m_clrHilightText = clrHilightText;
  239. }
  240. void CBitmapMenu::SetHighlightStyle(HIGHLIGHTSTYLE hilightStyle)
  241. {
  242. m_hilightStyle = hilightStyle;
  243. }
  244. void CBitmapMenu::SetImageList(CImageList* pList)
  245. {
  246. m_pList = pList;
  247. if( m_pList != NULL )
  248. {
  249. IMAGEINFO info;;
  250. m_pList->GetImageInfo(0, &info);
  251. m_nIconX = info.rcImage.right - info.rcImage.left;
  252. m_nIconY = info.rcImage.bottom - info.rcImage.top;
  253. }
  254. else
  255. {
  256. m_nIconX = 0;
  257. m_nIconY = 0;
  258. }
  259. }
  260. /*
  261. =================================================================================
  262. BOOL CBitmapMenu::AppendODMenu(LPCTSTR, UINT, UINT, UINT, UINT)
  263. BOOL CBitmapMenu::ModifyODMenu(LPCTSTR, UINT, UINT, UINT, UINT)
  264. ----------------------------------------------------------
  265. These 2 functions effectively replace the CMenu::AppendMenu() and CMenu::ModifyMenu()
  266. classes, with support for 3 icon states.  When using Owner-drawn menu items,
  267. use these functions instead of the usual ones.
  268. =================================================================================
  269. */
  270. BOOL CBitmapMenu::AppendMenu(UINT nFlags,
  271.   UINT nID,
  272.   LPCTSTR lpstrText,
  273.   int nIconNormal,
  274.   int nIconSelected,
  275.   int nIconDisabled)
  276. {
  277. if( (nFlags & MF_OWNERDRAW) != 0 || nIconNormal != -1 )
  278. {
  279. nFlags |= MF_OWNERDRAW;
  280. BMenuData *mdata = new BMenuData;
  281. m_MenuList.Add(mdata);
  282. lstrcpy(mdata->menuText, lpstrText);
  283. mdata->menuIconNormal = nIconNormal;
  284. mdata->menuIconSelected = nIconSelected;
  285. mdata->menuIconDisabled = nIconDisabled;
  286. return CMenu::AppendMenu(nFlags, nID, (LPCTSTR)mdata);
  287. }
  288. return CMenu::AppendMenu(nFlags, nID, lpstrText);
  289. }
  290. BOOL CBitmapMenu::ModifyODMenu(LPCTSTR lpstrText,
  291.   UINT nID,
  292.   int nIconNormal,
  293.   int nIconSelected,
  294.   int nIconDisabled)
  295. {
  296. // Delete the existing BMenuData structure associated with this item (if any)
  297. int numMenuItems = m_MenuList.GetUpperBound();
  298. BMenuData *mdata;
  299. for( int m = 0; m <= numMenuItems; m++ )
  300. {
  301. if( (mdata = m_MenuList[m]) != NULL )
  302. {
  303. if( mdata->nID == nID )
  304. {
  305. delete(mdata);
  306. m_MenuList.RemoveAt(m);
  307. break;
  308. }
  309. }
  310. }
  311. // Create a new BMenuData structure:
  312. mdata = new BMenuData;
  313. m_MenuList.Add(mdata);
  314. lstrcpy(mdata->menuText, lpstrText);
  315. mdata->menuIconNormal = nIconNormal;
  316. mdata->menuIconSelected = nIconSelected;
  317. mdata->menuIconDisabled = nIconDisabled;
  318. return CMenu::ModifyMenu(nID, MF_BYCOMMAND | MF_OWNERDRAW, nID, (LPCTSTR)mdata);
  319. }
  320. BOOL CBitmapMenu::LoadMenu(LPCTSTR lpszResourceName)
  321. {
  322. return CBitmapMenu::LoadMenu(MAKEINTRESOURCE(lpszResourceName));
  323. }
  324. BOOL CBitmapMenu::LoadMenu(int nResource)
  325. {
  326. // Find the Menu Resource:
  327. DWORD dwSize;
  328. WORD wrd = MAKEWORD(nResource, 0);
  329. HRSRC hRsrc = FindResource(NULL, (LPCTSTR)wrd, RT_MENU);
  330. // Find the resource
  331. if( hRsrc == NULL )
  332. {
  333. TRACE0("CBitmapMenu::LoadMenu() - Failed to find Menu Resourcen");
  334. ASSERT(FALSE);
  335. }
  336. // Get size of resource:
  337. dwSize = SizeofResource(NULL, hRsrc);
  338. // Load the Menu Resource:
  339. HGLOBAL hGlobal = LoadResource(NULL, hRsrc);
  340. if( hGlobal == NULL )
  341. {
  342. TRACE0("CBitmapMenu::LoadMenu() - Failed to load Menu Resourcen");
  343. ASSERT(FALSE);
  344. }
  345. // Attempt to create us as a menu...
  346. if( !CMenu::CreateMenu() )
  347. {
  348. TRACE0("CBitmapMenu::LoadMenu() - Failed to create Menun");
  349. ASSERT(FALSE);
  350. }
  351. // Get Item template Header, and calculate offset of MENUITEMTEMPLATES
  352. MENUITEMTEMPLATEHEADER* pTpHdr = (MENUITEMTEMPLATEHEADER*)LockResource(hGlobal);
  353. BYTE* pTp   = (BYTE*)pTpHdr + 
  354. (sizeof(MENUITEMTEMPLATEHEADER) + pTpHdr->offset);
  355. // Variables needed during processing of Menu Item Templates:
  356. BMenuData* pData = NULL; // New OD Menu Item Data
  357. WORD dwFlags = 0; // Flags of the Menu Item
  358. WORD dwID = 0; // ID of the Menu Item
  359. BOOL bLastPopup = 0;  // Last popup?
  360. UINT uFlags;  // Actual Flags.
  361. char caption[80]; // Allows up to 80 chars for caption
  362. int  nLen   = 0;  // Length of caption
  363. CTypedPtrArray<CPtrArray, CBitmapMenu*> m_Stack; // Popup menu stack
  364. m_Stack.Add(this); // Add it to this...
  365. do
  366. {
  367. // Obtain Flags and (if necessary), the ID...
  368. memcpy(&dwFlags, pTp, sizeof(WORD));
  369. pTp+=sizeof(WORD);
  370. // Obtain Flags
  371. if( !(dwFlags & MF_POPUP) )
  372. {
  373. memcpy(&dwID, pTp, sizeof(WORD));
  374. // Obtain ID
  375. pTp += sizeof(WORD);
  376. }
  377. else
  378. dwID = 0;
  379. uFlags = (UINT)dwFlags;  // Remove MF_END from the flags that will
  380. if( uFlags & MF_END ) // be passed to the Append(OD)Menu functions.
  381. uFlags -= MF_END;
  382. // Obtain Caption (and length)
  383. nLen = 0;
  384. char *ch = (char*)pTp;
  385. while( *ch != 0 )
  386. {
  387. caption[nLen] = ch[0];
  388. nLen++;  // Increment length
  389. ch+=2; // Accounts for UNICODE '0's...
  390. }
  391. caption[nLen] = 0; // Zero-terminate the string...
  392. pTp += (nLen+1) * 2; // Increase Pointer...
  393. // Handle popup menus first....
  394. if( dwFlags & MF_POPUP )
  395. {
  396. if( dwFlags & MF_END )
  397. bLastPopup = TRUE;
  398. CBitmapMenu* pSubMenu = new CBitmapMenu;
  399. pSubMenu->CreatePopupMenu();
  400. // Append it to the top of the stack:
  401. m_Stack[m_Stack.GetUpperBound()]->AppendMenu(uFlags, (UINT)pSubMenu->m_hMenu, caption);
  402. m_Stack.Add(pSubMenu); // Add to PopupStack
  403. m_SubMenus.Add(pSubMenu); // For deletion...
  404. }
  405. else
  406. {
  407. m_Stack[m_Stack.GetUpperBound()]->AppendMenu(uFlags, dwID, caption, -1, -1, -1);
  408. if( dwFlags & MF_END )
  409. m_Stack.RemoveAt(m_Stack.GetUpperBound()); // Remove top of stack
  410. if(bLastPopup)
  411. {
  412. bLastPopup = FALSE;
  413. m_Stack.RemoveAt(m_Stack.GetUpperBound()); // And again...
  414. }
  415. }
  416. }
  417. while( m_Stack.GetUpperBound() != -1 );
  418. return TRUE;
  419. }