MenuXP.cpp
上传用户:lejushen
上传日期:2007-01-10
资源大小:183k
文件大小:22k
源码类别:

菜单

开发平台:

Visual C++

  1. // CustMenu.cpp: implementation of the CMenuXP class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "stdafx.h"
  5. #include "MenuXP.h"
  6. #include "KeyHelper.h"
  7. #ifdef _DEBUG
  8. #undef THIS_FILE
  9. static char THIS_FILE[]=__FILE__;
  10. #define new DEBUG_NEW
  11. #endif
  12. // constants used for drawing
  13. const CXGAP = 0; // num pixels between button and text
  14. const CXTEXTMARGIN = 2; // num pixels after hilite to start text
  15. const CXBUTTONMARGIN = 2; // num pixels wider button is than bitmap
  16. const CYBUTTONMARGIN = 2; // ditto for height
  17. // DrawText flags
  18. const DT_MYSTANDARD = DT_SINGLELINE|DT_LEFT|DT_VCENTER;
  19. //////////////////////////////////////////////////////////////////////
  20. // Construction/Destruction
  21. //////////////////////////////////////////////////////////////////////
  22. IMPLEMENT_DYNAMIC(CMenuXP, CMenu)
  23. CMenuXP::CMenuXP()
  24. {
  25. //initialize menu font with the default
  26. NONCLIENTMETRICS info;
  27. info.cbSize = sizeof(info);
  28. SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0);
  29. VERIFY(m_fontMenu.CreateFontIndirect(&info.lfMenuFont));
  30. //initialize colors with system default
  31. m_clrBackGround = ::GetSysColor(COLOR_MENU);
  32. m_clrSelectedBar = ::GetSysColor(COLOR_HIGHLIGHT);
  33. m_clrSelectedText = ::GetSysColor(COLOR_HIGHLIGHTTEXT);
  34. m_clrText = ::GetSysColor(COLOR_MENUTEXT);
  35. m_clrDisabledText = ::GetSysColor(COLOR_GRAYTEXT);
  36. m_clrIconArea = m_clrBackGround;
  37. //initialize sidebar colors
  38. m_clrSideBarStart = RGB(0, 0, 192);
  39. m_clrSideBarEnd = RGB(0, 0, 0);
  40. //the default sytle is office style
  41. m_Style = STYLE_OFFICE;
  42. m_bBreak = false;
  43. m_bBreakBar = false;
  44. m_hBitmap = NULL;
  45. }
  46. CMenuXP::~CMenuXP()
  47. {
  48. m_fontMenu.DeleteObject();
  49. Clear();
  50. }
  51. void CMenuXP::MeasureItem( LPMEASUREITEMSTRUCT lpms )
  52. {
  53. if (lpms->CtlType != ODT_MENU)
  54. return;
  55. CMenuXPItem *pItem = (CMenuXPItem *)lpms->itemData;
  56. TRACE("pItem: 0x%x",(DWORD)pItem); //This line prevent boundschecker from issue a resource leak
  57. if (!pItem || !pItem->IsMyData())
  58. return;
  59. if (pItem->m_bSideBar)
  60. {
  61. lpms->itemWidth = pItem->m_nSize;
  62. lpms->itemHeight = 0;
  63. }
  64. else if (pItem->m_bSeparator)
  65. {
  66. // separator: use half system height and zero width
  67. lpms->itemHeight = ::GetSystemMetrics(SM_CYMENUCHECK)>>1;
  68. lpms->itemWidth  = 0;
  69. }
  70. else
  71. {
  72. //calculate the size needed to draw the text: use DrawText with DT_CALCRECT
  73. CWindowDC dc(NULL); // screen DC--I won't actually draw on it
  74. CRect rcText(0,0,0,0);
  75. CFont* pOldFont;
  76. //Calculate the size with bold font, for default item to be correct
  77. CFont fontBold;
  78. LOGFONT logFont;
  79. m_fontMenu.GetLogFont(&logFont);
  80. logFont.lfWeight = FW_BOLD;
  81. fontBold.CreateFontIndirect(&logFont);
  82. pOldFont = dc.SelectObject(&fontBold);
  83. // pOldFont= dc.SelectObject(&m_fontMenu);
  84. dc.DrawText(pItem->m_strText, rcText, DT_MYSTANDARD|DT_CALCRECT);
  85. dc.SelectObject(pOldFont);
  86. // the height of the item should be the maximun of the text and the button
  87. lpms->itemHeight = max(rcText.Height(), pItem->m_nSize + (CYBUTTONMARGIN<<1));
  88. if (pItem->m_bButtonOnly)
  89. { //for button only style, we set the item's width to be the same as its height
  90. lpms->itemWidth = lpms->itemHeight;
  91. }
  92. else
  93. {
  94. // width is width of text plus a bunch of stuff
  95. int cx = rcText.Width(); // text width 
  96. cx += CXTEXTMARGIN<<1; // L/R margin for readability
  97. cx += CXGAP; // space between button and menu text
  98. cx += (pItem->m_nSize + CYBUTTONMARGIN * 2) <<1; // button width (L=button; R=empty margin)
  99. lpms->itemWidth = cx; // done deal
  100. }
  101. }
  102. // whatever value I return in lpms->itemWidth, Windows will add the
  103. // width of a menu checkmark, so I must subtract to defeat Windows. Argh.
  104. //
  105. lpms->itemWidth -= GetSystemMetrics(SM_CXMENUCHECK)-1;
  106. TRACE("MeasureItem: ID(%d), Width(%d), Height(%d)n", 
  107. lpms->itemID,
  108. lpms->itemWidth, lpms->itemHeight);
  109. }
  110. void CMenuXP::DrawItem( LPDRAWITEMSTRUCT lpds )
  111. {
  112. ASSERT(lpds);
  113. if (lpds->CtlType != ODT_MENU)
  114. return; // not handled by me
  115. CMenuXPItem * pItem = (CMenuXPItem *)lpds->itemData;
  116. if (!pItem)
  117. return;
  118. ASSERT(lpds->itemAction != ODA_FOCUS);
  119. ASSERT(lpds->hDC);
  120. CDC dc;
  121. dc.Attach(lpds->hDC);
  122. //get the drawing area
  123. CRect rcItem = lpds->rcItem;
  124. TRACE("DrawItem: ID(%d), Widht(%d),  Height(%d)n", 
  125. lpds->itemID, rcItem.Width(), rcItem.Height());
  126. if (pItem->m_bSideBar)
  127. {
  128. CRect rcClipBox;
  129. dc.GetClipBox(rcClipBox);
  130. //before drawing the sidebar, we must fill the entire menu area with its backgroundcolor,
  131. //orelse, the breakbar area will remain the the default menu color
  132. //so, if you want to avoid strange color and don't want a sidebar, just add a sidebar with 
  133. //zero width
  134. //dc.FillSolidRect(rcClipBox, m_Style==STYLE_XP? m_clrIconArea : m_clrBackGround);
  135. //draw the side bar
  136. CRect rc = rcItem;
  137. rc.top = rcClipBox.top;
  138. rc.bottom = rcClipBox.bottom;
  139. DrawSideBar(&dc, rc, pItem->m_hIcon, pItem->m_strText);
  140. }
  141. else if (pItem->m_bSeparator) 
  142. {
  143. //draw background first
  144. DrawBackGround(&dc, rcItem, FALSE, FALSE);
  145. // draw the background
  146. CRect rc = rcItem; // copy rect
  147. rc.top += rc.Height()>>1; // vertical center
  148. dc.DrawEdge(&rc, EDGE_ETCHED, BF_TOP); // draw separator line
  149. // in XP mode, fill the icon area with the iconarea color
  150. if (m_Style == STYLE_XP)
  151. {
  152. CRect rcArea(rcItem.TopLeft(),
  153. CSize(pItem->m_nSize + (CYBUTTONMARGIN<<1), 
  154. pItem->m_nSize + (CYBUTTONMARGIN<<1)));
  155. DrawIconArea(&dc, rcArea, FALSE, FALSE, FALSE);
  156. }
  157. else
  158. {
  159. BOOL bDisabled = lpds->itemState & ODS_GRAYED;
  160. BOOL bSelected = lpds->itemState & ODS_SELECTED;
  161. BOOL bChecked  = lpds->itemState & ODS_CHECKED;
  162. //draw the background first
  163. DrawBackGround(&dc, rcItem, bSelected, bDisabled);
  164. //Draw the icon area for XP style
  165. if (m_Style == STYLE_XP)
  166. {
  167. CRect rcArea(rcItem.TopLeft(), CSize(rcItem.Height(), rcItem.Height()));
  168. DrawIconArea(&dc, rcArea, bSelected, bDisabled, bChecked);
  169. }
  170. //draw the button, not the icon
  171. CRect rcButton(rcItem.TopLeft(), CSize(rcItem.Height(), rcItem.Height()));
  172. if (pItem->m_bButtonOnly)
  173. rcButton = rcItem;
  174. if (pItem->m_hIcon || bChecked)
  175. {
  176. DrawButton(&dc, rcButton, bSelected, bDisabled, bChecked);
  177. }
  178. //draw the icon actually
  179. if (pItem->m_hIcon)
  180. {
  181. CRect rcIcon = rcButton;
  182. rcIcon.DeflateRect(2, 2);
  183. DrawIcon(&dc, rcIcon, pItem->m_hIcon, bSelected, bDisabled, bChecked);
  184. }
  185. else if (bChecked)
  186. {
  187. //draw the check mark
  188. CRect rcCheck = rcButton;
  189. rcCheck.DeflateRect(2, 2);
  190. DrawCheckMark(&dc, rcCheck, bSelected);
  191. }
  192. //draw text finally
  193. if (!pItem->m_bButtonOnly)
  194. {
  195. CRect rcText = rcItem;  // start w/whole item
  196. rcText.left += rcButton.Width() + CXGAP + CXTEXTMARGIN; // left margin
  197. rcText.right -= pItem->m_nSize;  // right margin
  198. DrawText(&dc, rcText, pItem->m_strText, bSelected, bDisabled, lpds->itemState&ODS_DEFAULT ? 1 : 0);
  199. }
  200. }
  201. dc.Detach();
  202. }
  203. //draw background
  204. void CMenuXP::DrawBackGround(CDC *pDC, CRect rect, BOOL bSelected, BOOL bDisabled)
  205. {
  206. if (m_hBitmap && (!bSelected || bDisabled))
  207. {
  208. pDC->BitBlt(rect.left, rect.top, rect.Width(), rect.Height(), &m_memDC,
  209. 0, rect.top, SRCCOPY);
  210. }
  211. else if (bSelected)
  212. {
  213. FillRect(pDC, rect, bDisabled? ((m_Style==STYLE_XP)?m_clrBackGround:m_clrSelectedBar) : m_clrSelectedBar);
  214. }
  215. else
  216. {
  217. FillRect(pDC, rect, m_clrBackGround);
  218. }
  219. //in XP mode, draw a line rectangle around
  220. if (m_Style == STYLE_XP && bSelected && !bDisabled)
  221. {
  222. CGdiObject *pOldBrush = pDC->SelectStockObject(HOLLOW_BRUSH);
  223. CGdiObject *pOldPen = pDC->SelectStockObject(BLACK_PEN);
  224. pDC->Rectangle(rect);
  225. pDC->SelectObject(pOldBrush);
  226. pDC->SelectObject(pOldPen);
  227. }
  228. }
  229. //draw the icon button, the icon is not included
  230. void CMenuXP::DrawButton(CDC *pDC, CRect rect, BOOL bSelected, BOOL bDisabled, BOOL bChecked)
  231. {
  232. if (m_Style == STYLE_OFFICE)
  233. {
  234. // normal: fill BG depending on state
  235. if (bChecked && !bSelected)
  236. {
  237. FillRect(pDC, rect, GetSysColor(COLOR_3DHILIGHT));
  238. }
  239. else
  240. FillRect(pDC, rect, m_clrBackGround);
  241. // draw pushed-in or popped-out edge
  242. if (!bDisabled && (bSelected || bChecked) )
  243. {
  244. pDC->DrawEdge(rect, bChecked ? BDR_SUNKENOUTER : BDR_RAISEDINNER,
  245. BF_RECT);
  246. }
  247. }
  248. else if (m_Style == STYLE_XP && !bSelected)
  249. {
  250. if (bChecked && !bDisabled)
  251. {
  252. DrawBackGround(pDC, rect, TRUE, FALSE);
  253. }
  254. }
  255. }
  256. //draw the icon area, the icon is not included, only in XP style
  257. void CMenuXP::DrawIconArea(CDC *pDC, CRect rect, BOOL bSelected, BOOL bDisabled, BOOL bChecked)
  258. {
  259. if (m_Style != STYLE_XP)
  260. return;
  261. // normal: fill BG depending on state
  262. if (!bSelected || bDisabled)
  263. {
  264. FillRect(pDC, rect, m_clrIconArea);
  265. }
  266. }
  267. //draw the icon
  268. void CMenuXP::DrawIcon(CDC *pDC, CRect rect, HICON hIcon, BOOL bSelected, BOOL bDisabled, BOOL bChecked)
  269. {
  270. if (bDisabled)
  271. {
  272. DrawEmbossed(pDC, hIcon, rect);
  273. }
  274. else
  275. {
  276. if(m_Style==STYLE_XP && bSelected && !bChecked)
  277. {
  278. DrawEmbossed(pDC,hIcon,rect,FALSE, TRUE);
  279. rect.OffsetRect(-1,-1);
  280. }
  281. ::DrawIconEx(pDC->m_hDC, rect.left, rect.top, hIcon,
  282. rect.Width(), rect.Height(), 0, NULL,
  283. DI_NORMAL);
  284. /* ::DrawIconEx(pDC->m_hDC, rect.left, rect.top, hIcon,
  285. rect.Width(), rect.Height(), 0, NULL,
  286. DI_NORMAL);
  287. */ }
  288. }
  289. //draw the sidebar
  290. void CMenuXP::DrawSideBar(CDC *pDC, CRect rect, HICON hIcon, CString strText)
  291. {
  292. rect.right += 3; //fill the gap produced by the menubreak
  293. HBITMAP bmpBar = CreateGradientBMP(
  294. pDC->m_hDC, m_clrSideBarStart, m_clrSideBarEnd,
  295. rect.Width(), rect.Height(),
  296. 0, 256);
  297. if (bmpBar)
  298. {
  299. CDC memDC;
  300. memDC.CreateCompatibleDC(pDC);
  301. HBITMAP hOldBmp = (HBITMAP)::SelectObject(memDC.m_hDC, bmpBar);
  302. pDC->BitBlt(rect.left, rect.top,
  303. rect.Width(), rect.Height(),
  304. &memDC, 0, 0, SRCCOPY);
  305. ::SelectObject(memDC, hOldBmp);
  306. ::DeleteObject(bmpBar);
  307. }
  308. //Draw Sidebar text
  309. CFont vertFont;
  310. vertFont.CreateFont(16, 0, 900, 900, FW_BOLD,
  311. 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
  312. CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
  313. DEFAULT_PITCH, "Arial");
  314. CFont *pOldFont = pDC->SelectObject(&vertFont);
  315. COLORREF oldColor = pDC->GetTextColor();
  316. pDC->SetTextColor(RGB(255, 255, 255));
  317. pDC->SetBkMode(TRANSPARENT);
  318. pDC->TextOut(rect.left+2, rect.bottom-4, strText);
  319. pDC->SetTextColor(oldColor);
  320. pDC->SelectObject(pOldFont);
  321. vertFont.DeleteObject();
  322. }
  323. //draw the check mark
  324. void CMenuXP::DrawCheckMark(CDC *pDC, CRect rect, BOOL bSelected)
  325. {
  326. /* //"#define OEMRESOURCE" must be in the begining of your stdafx.h
  327. //for the LoadOEMBitmap to work
  328. #ifdef OEMRESOURCE
  329. CBitmap bmp; //Check mark bitmap
  330. VERIFY(bmp.LoadOEMBitmap(OBM_CHECK));
  331. // center bitmap in caller's rectangle
  332. BITMAP bm;
  333. bmp.GetBitmap(&bm);
  334. int cx = bm.bmWidth;
  335. int cy = bm.bmHeight;
  336. CRect rcDest = rect;
  337. CPoint p(0,0);
  338. CSize delta(CPoint((rect.Width() - cx)/2, (rect.Height() - cy)/2));
  339. if (rect.Width() > cx)
  340. rcDest = CRect(rect.TopLeft() + delta, CSize(cx, cy));
  341. else
  342. p -= delta;
  343. // select checkmark into memory DC
  344. CDC memdc;
  345. memdc.CreateCompatibleDC(pDC);
  346. CBitmap *pOldBmp = memdc.SelectObject(&bmp);
  347. COLORREF colorOld =
  348. pDC->SetBkColor(GetSysColor(bSelected ? COLOR_MENU : COLOR_3DLIGHT));
  349. pDC->BitBlt(rcDest.left, rcDest.top, rcDest.Width(), rcDest.Height(),
  350. &memdc, p.x, p.y, SRCCOPY);
  351. pDC->SetBkColor(colorOld);
  352. memdc.SelectObject(pOldBmp);
  353. bmp.DeleteObject();
  354. #else
  355. CRect rcDest = rect;
  356. pDC->DrawFrameControl(rcDest, DFC_MENU, DFCS_MENUCHECK);
  357. #endif
  358. */
  359. //Draw it myself :(
  360. const int nCheckDots = 8;
  361. CPoint pt1, pt2, pt3; //3 point of the checkmark
  362. pt1.x = 0; // 5/18 of the rect width
  363. pt1.y = 3;
  364. pt2.x = 2;
  365. pt2.y = 5;
  366. pt3.x = 7;
  367. pt3.y = 0;
  368. int xOff = (rect.Width()-nCheckDots)/2 + rect.left ;
  369. int yOff = (rect.Height()-nCheckDots)/2 + rect.top;
  370. pt1.Offset(xOff, yOff);
  371. pt2.Offset(xOff, yOff);
  372. pt3.Offset(xOff, yOff);
  373. CPen pen(PS_SOLID, 1, RGB(0, 0, 0));
  374. CGdiObject *pOldPen = pDC->SelectObject(&pen);
  375. pDC->MoveTo(pt1);
  376. pDC->LineTo(pt2);
  377. pDC->LineTo(pt3);
  378. pt1.Offset(0, 1);
  379. pt2.Offset(0, 1);
  380. pt3.Offset(0, 1);
  381. pDC->MoveTo(pt1);
  382. pDC->LineTo(pt2);
  383. pDC->LineTo(pt3);
  384. pt1.Offset(0, 1);
  385. pt2.Offset(0, 1);
  386. pt3.Offset(0, 1);
  387. pDC->MoveTo(pt1);
  388. pDC->LineTo(pt2);
  389. pDC->LineTo(pt3);
  390. pDC->SelectObject(pOldPen);
  391. }
  392. //Draw menu text
  393. void CMenuXP::DrawText(CDC *pDC, CRect rect, CString strText, BOOL bSelected, BOOL bDisabled, BOOL bBold)
  394. {
  395. CFont* pOldFont;
  396. CFont fontBold;
  397. if (bBold)
  398. {
  399. LOGFONT logFont;
  400. m_fontMenu.GetLogFont(&logFont);
  401. logFont.lfWeight = FW_BOLD;
  402. fontBold.CreateFontIndirect(&logFont);
  403. pOldFont = pDC->SelectObject(&fontBold);
  404. }
  405. else
  406. {
  407. pOldFont = pDC->SelectObject(&m_fontMenu);
  408. }
  409. pDC->SetBkMode(TRANSPARENT);
  410. if (bDisabled && (!bSelected || m_Style == STYLE_XP))
  411. {
  412. DrawMenuText(*pDC, rect + CPoint(1, 1), strText, m_clrSelectedText);
  413. }
  414. if (bDisabled)
  415. {
  416. DrawMenuText(*pDC, rect, strText, m_clrDisabledText);
  417. }
  418. else
  419. {
  420. DrawMenuText(*pDC, rect, strText, bSelected? m_clrSelectedText : m_clrText);
  421. }
  422. pDC->SelectObject(pOldFont);
  423. if (bBold)
  424. fontBold.DeleteObject();
  425. }
  426. //set menu font
  427. BOOL CMenuXP::SetMenuFont(LOGFONT lgfont)
  428. {
  429. m_fontMenu.DeleteObject();
  430. return m_fontMenu.CreateFontIndirect(&lgfont);
  431. }
  432. //clear all memory and handles
  433. void CMenuXP::Clear(void)
  434. {
  435. if (m_hBitmap)
  436. {
  437. DeleteObject(m_hBitmap);
  438. m_hBitmap = NULL;
  439. }
  440. UINT nCount = GetMenuItemCount();
  441. for (UINT i=0; i<nCount; i++)
  442. {
  443. MENUITEMINFO info;
  444. memset(&info, 0, sizeof(MENUITEMINFO));
  445. info.cbSize = sizeof(MENUITEMINFO);
  446. info.fMask = MIIM_DATA | MIIM_TYPE;
  447. GetMenuItemInfo(i, &info, TRUE);
  448. CMenuXPItem *pData = (CMenuXPItem *)info.dwItemData;
  449. if ((info.fType & MFT_OWNERDRAW) && pData && pData->IsMyData())
  450. {
  451. delete pData;
  452. }
  453. CMenu *pSubMenu = GetSubMenu(i);
  454. if (pSubMenu && pSubMenu->IsKindOf(RUNTIME_CLASS(CMenuXP)))
  455. delete pSubMenu;
  456. }
  457. }
  458. //draw embossed icon for the disabled item
  459. const DWORD MAGICROP = 0xb8074a;
  460. const COLORREF CWHITE  = RGB(255,255,255);
  461. void CMenuXP::DrawEmbossed(CDC *pDC, HICON hIcon, CRect rect, BOOL bColor, BOOL bShadow)
  462. {
  463. CDC memdc;
  464. memdc.CreateCompatibleDC(pDC);
  465. int cx = rect.Width();
  466. int cy = rect.Height();
  467. // create mono or color bitmap
  468. CBitmap bm;
  469. if (bColor)
  470. bm.CreateCompatibleBitmap(pDC, cx, cy);
  471. else
  472. bm.CreateBitmap(cx, cy, 1, 1, NULL);
  473. // draw image into memory DC--fill BG white first
  474. CBitmap* pOldBitmap = memdc.SelectObject(&bm);
  475. //FillRect(&memdc, CRect(0, 0, cx, cy), m_clrBackGround);
  476. memdc.PatBlt(0, 0, cx, cy, WHITENESS);
  477. ::DrawIconEx(memdc.m_hDC, 0, 0, hIcon, cx, cy, 1, NULL, DI_NORMAL);
  478. // This seems to be required. Why, I don't know. ???
  479. COLORREF colorOldBG = pDC->SetBkColor(CWHITE);
  480. // Draw using hilite offset by (1,1), then shadow
  481. CBrush brShadow(GetSysColor(COLOR_3DSHADOW));
  482. CBrush brHilite(GetSysColor(COLOR_3DHIGHLIGHT));
  483. CBrush* pOldBrush = pDC->SelectObject(bShadow ? &brShadow : &brHilite);
  484. pDC->BitBlt(rect.left+1, rect.top+1, cx, cy, &memdc, 0, 0, MAGICROP);
  485. pDC->SelectObject(&brShadow);
  486. pDC->BitBlt(rect.left, rect.top, cx, cy, &memdc, 0, 0, MAGICROP);
  487. pDC->SelectObject(pOldBrush);
  488. pDC->SetBkColor(colorOldBG);  // restore
  489. memdc.SelectObject(pOldBitmap);  // ...
  490. bm.DeleteObject();
  491. brShadow.DeleteObject();
  492. brHilite.DeleteObject();
  493. }
  494. //////////////////
  495. // Shorthand to fill a rectangle with a solid color.
  496. //
  497. void CMenuXP::FillRect(CDC *pDC, const CRect& rc, COLORREF color)
  498. {
  499. CBrush brush(color);
  500. CBrush* pOldBrush = pDC->SelectObject(&brush);
  501. pDC->PatBlt(rc.left, rc.top, rc.Width(), rc.Height(), PATCOPY);
  502. pDC->SelectObject(pOldBrush);
  503. brush.DeleteObject();
  504. }
  505. HBITMAP CMenuXP::CreateGradientBMP(HDC hDC,COLORREF cl1,COLORREF cl2,int nWidth,int nHeight,int nDir,int nNumColors)
  506. {
  507. if(nNumColors > 256)
  508. nNumColors = 256;
  509. COLORREF PalVal[256];
  510. memset(PalVal, 0, sizeof(COLORREF)*256);
  511. int nIndex;
  512. BYTE peRed=0,peGreen=0,peBlue=0;
  513. int r1=GetRValue(cl1);
  514. int r2=GetRValue(cl2);
  515. int g1=GetGValue(cl1);
  516. int g2=GetGValue(cl2);
  517. int b1=GetBValue(cl1);
  518. int b2=GetBValue(cl2);
  519.     for (nIndex = 0; nIndex < nNumColors; nIndex++)
  520.     {
  521.         peRed = (BYTE) (r1 + MulDiv((r2-r1),nIndex,nNumColors-1));
  522.         peGreen = (BYTE) (g1 + MulDiv((g2-g1),nIndex,nNumColors-1));
  523.         peBlue = (BYTE) (b1 + MulDiv((b2-b1),nIndex,nNumColors-1));
  524. PalVal[nIndex]=(peRed << 16) | (peGreen << 8) | (peBlue);
  525. }
  526. int x,y,w,h;
  527. w=nWidth;
  528. h=nHeight;
  529. LPDWORD pGradBits;
  530. BITMAPINFO GradBitInfo;
  531. pGradBits=(DWORD*) malloc(w*h*sizeof(DWORD));
  532. memset(&GradBitInfo,0,sizeof(BITMAPINFO));
  533. GradBitInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
  534. GradBitInfo.bmiHeader.biWidth=w;
  535. GradBitInfo.bmiHeader.biHeight=h;
  536. GradBitInfo.bmiHeader.biPlanes=1;
  537. GradBitInfo.bmiHeader.biBitCount=32;
  538. GradBitInfo.bmiHeader.biCompression=BI_RGB;
  539. if(nDir==0) 
  540. {
  541. for(y=0;y<h;y++) 
  542. {
  543. for(x=0;x<w;x++) 
  544. {
  545. *(pGradBits+(y*w)+x)=PalVal[MulDiv(nNumColors,y,h)];
  546. }
  547. }
  548. }
  549. else if(nDir==1) 
  550. {
  551. for(y=0;y<h;y++)
  552. {
  553. int l,r;
  554. l=MulDiv((nNumColors/2),y,h);
  555. r=l+(nNumColors/2)-1;
  556. for(x=0;x<w;x++)
  557. {
  558. *(pGradBits+(y*w)+x)=PalVal[l+MulDiv((r-l),x,w)];
  559. }
  560. }
  561. }
  562. else if(nDir==2)
  563. {
  564. for(x=0;x<w;x++)
  565. {
  566. for(y=0;y<h;y++)
  567. {
  568. *(pGradBits+(y*w)+x)=PalVal[MulDiv(nNumColors,x,w)];
  569. }
  570. }
  571. }
  572. else if(nDir==3)
  573. {
  574. for(y=0;y<h;y++)
  575. {
  576. int l,r;
  577. r=MulDiv((nNumColors/2),y,h);
  578. l=r+(nNumColors/2)-1;
  579. for(x=0;x<w;x++)
  580. {
  581. *(pGradBits+(y*w)+x)=PalVal[l+MulDiv((r-l),x,w)];
  582. }
  583. }
  584. }
  585. HBITMAP hBmp = CreateDIBitmap(hDC,&GradBitInfo.bmiHeader,CBM_INIT,
  586. pGradBits,&GradBitInfo,DIB_RGB_COLORS);
  587. free(pGradBits);
  588. return hBmp;
  589. }
  590. //static member for keyboard operation, you can used it in you parent window
  591. //it work with shortcut key
  592. LRESULT CMenuXP::OnMenuChar(UINT nChar, UINT nFlags, CMenu* pMenu) 
  593. {
  594. UINT iCurrentItem = (UINT)-1; // guaranteed higher than any command ID
  595. CUIntArray arItemsMatched; // items that match the character typed
  596. UINT nItem = pMenu->GetMenuItemCount();
  597. for (UINT i=0; i< nItem; i++) 
  598. {
  599. MENUITEMINFO info;
  600. memset(&info, 0, sizeof(info));
  601. info.cbSize = sizeof(info);
  602. info.fMask = MIIM_DATA | MIIM_TYPE | MIIM_STATE;
  603. ::GetMenuItemInfo(*pMenu, i, TRUE, &info);
  604. CMenuXPItem *pData = (CMenuXPItem *)info.dwItemData;
  605. if ((info.fType & MFT_OWNERDRAW) && pData && pData->IsMyData())
  606. {
  607. CString text = pData->m_strText;
  608. int iAmpersand = text.Find('&');
  609. if (iAmpersand >=0 && toupper(nChar)==toupper(text[iAmpersand+1]))
  610. arItemsMatched.Add(i);
  611. }
  612. if (info.fState & MFS_HILITE)
  613. iCurrentItem = i; // note index of current item
  614. }
  615. // arItemsMatched now contains indexes of items that match the char typed.
  616. //
  617. //   * if none: beep
  618. //   * if one:  execute it
  619. //   * if more than one: hilite next
  620. //
  621. UINT nFound = arItemsMatched.GetSize();
  622. if (nFound == 0)
  623. return 0;
  624. else if (nFound==1)
  625. return MAKELONG(arItemsMatched[0], MNC_EXECUTE);
  626. // more than one found--return 1st one past current selected item;
  627. UINT iSelect = 0;
  628. for (i=0; i < nFound; i++) {
  629. if (arItemsMatched[i] > iCurrentItem) {
  630. iSelect = i;
  631. break;
  632. }
  633. }
  634. return MAKELONG(arItemsMatched[iSelect], MNC_SELECT);
  635. }
  636. void CMenuXP::DrawMenuText(CDC& dc, CRect rc, CString text,
  637. COLORREF color)
  638. {
  639. CString left = text;
  640. CString right;
  641. int iTabPos = left.Find('t');
  642. if (iTabPos >= 0) {
  643. right = left.Right(left.GetLength() - iTabPos - 1);
  644. left  = left.Left(iTabPos);
  645. }
  646. dc.SetTextColor(color);
  647. dc.DrawText(left, &rc, DT_MYSTANDARD);
  648. if (iTabPos > 0)
  649. dc.DrawText(right, &rc, DT_MYSTANDARD|DT_RIGHT);
  650. }
  651. //find a popupmenu from a menuitem id
  652. CMenuXP *CMenuXP::FindSubMenuFromID(DWORD dwID)
  653. {
  654. CMenuXP *pSubMenu;
  655. CMenuXP *pResult;
  656. for (UINT i=0; i<GetMenuItemCount(); i++)
  657. {
  658. if (GetMenuItemID(i) == dwID)
  659. return this;
  660. }
  661. for (i=0; i<GetMenuItemCount(); i++)
  662. {
  663. pSubMenu = (CMenuXP *)GetSubMenu(i);
  664. if (pSubMenu)
  665. {
  666. pResult = pSubMenu->FindSubMenuFromID(dwID);
  667. if (pResult)
  668. return pResult;
  669. }
  670. }
  671. return NULL;
  672. }
  673. //Add a gradient sidebar, it must be the first item in a popupmenu
  674. BOOL CMenuXP::AddSideBar(CMenuXPSideBar *pItem)
  675. {
  676. ASSERT(pItem);
  677. m_bBreak = TRUE;
  678. m_bBreakBar = FALSE;
  679. return AppendMenu(MF_OWNERDRAW | MF_SEPARATOR, pItem->m_dwID, (LPCTSTR)pItem);
  680. }
  681. //add a normal menuitem, an accelerator key could be specified, and the accel text will
  682. //be added automatically
  683. BOOL CMenuXP::AppendODMenu(UINT nFlags, CMenuXPItem *pItem, ACCEL *pAccel)
  684. {
  685. ASSERT(pItem);
  686. nFlags |= MF_OWNERDRAW;
  687. if (m_bBreak) 
  688. nFlags |= MF_MENUBREAK;
  689. if (m_bBreakBar)
  690. nFlags |= MF_MENUBARBREAK;
  691. m_bBreak = m_bBreakBar = FALSE;
  692. if (pAccel)
  693. {
  694. CBCGKeyHelper keyhelper(pAccel);
  695. CString strAccel;
  696. keyhelper.Format(strAccel);
  697. if (strAccel.GetLength()>0)
  698. {
  699. pItem->m_strText += _T("t");
  700. pItem->m_strText += strAccel;
  701. }
  702. }
  703. return AppendMenu(nFlags, pItem->m_dwID, (LPCTSTR)pItem);
  704. }
  705. //Add a separator line
  706. BOOL CMenuXP::AppendSeparator(void)
  707. {
  708. m_bBreak = m_bBreakBar = FALSE;
  709. CMenuXPSeparator *pItem = new CMenuXPSeparator;
  710. return AppendMenu(MF_OWNERDRAW | MF_SEPARATOR, 0, (LPCTSTR)pItem);
  711. }
  712. //add a popup menu
  713. BOOL CMenuXP::AppendODPopup(UINT nFlags, CMenuXP *pPopup, CMenuXPItem *pItem)
  714. {
  715. ASSERT(pPopup);
  716. ASSERT(pItem);
  717. nFlags |= MF_OWNERDRAW;
  718. nFlags |= MF_POPUP;
  719. if (m_bBreak) 
  720. nFlags |= MF_MENUBREAK;
  721. if (m_bBreakBar)
  722. nFlags |= MF_MENUBARBREAK;
  723. m_bBreak = m_bBreakBar = FALSE;
  724. return AppendMenu(nFlags, (UINT)pPopup->m_hMenu, (LPCTSTR)pItem);
  725. }
  726. //Change column, the next item added will be in the next column
  727. void CMenuXP::Break(void)
  728. {
  729. m_bBreak = TRUE;
  730. }
  731. //same as Break(), except that a break line will appear between the two columns
  732. void CMenuXP::BreakBar(void)
  733. {
  734. m_bBreakBar = TRUE;
  735. }
  736. //Set background bitmap, null to remove
  737. void CMenuXP::SetBackBitmap(HBITMAP hBmp)
  738. {
  739. if (hBmp == NULL && m_hBitmap)
  740. {
  741. ::DeleteObject(m_hBitmap);
  742. m_hBitmap = NULL;
  743. m_memDC.DeleteDC();
  744. return;
  745. }
  746. m_hBitmap = hBmp;
  747. if (!m_memDC.m_hDC)
  748. {
  749. CWindowDC dc(NULL);
  750. m_memDC.CreateCompatibleDC(&dc);
  751. }
  752. ASSERT(m_memDC.m_hDC);
  753. ::SelectObject(m_memDC.m_hDC, m_hBitmap);
  754. }