MenuXP.cpp 20 KB

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