MenuXP.cpp 20 KB

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