MenuXP.cpp 20 KB

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