RTMenu.cpp
上传用户:qhonly
上传日期:2013-06-10
资源大小:487k
文件大小:41k
源码类别:

界面编程

开发平台:

Visual C++

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // MenuXP.cpp : implementation file
  4. //
  5. ///////////////////////////////////////////////////////////////////////////////
  6. #include "stdafx.h"
  7. #include "RTMenu.h"
  8. #include "RTTools.h"
  9. #include "RTDraw.h"
  10. #ifdef _DEBUG
  11. #define new DEBUG_NEW
  12. #undef THIS_FILE
  13. static char THIS_FILE[] = __FILE__;
  14. #endif
  15. #ifndef DWORD_PTR
  16.     typedef ULONG DWORD_PTR;
  17.     typedef long LONG_PTR;
  18. #endif
  19. #ifndef ODS_HOTLIGHT
  20.     #define ODS_HOTLIGHT 0x0040
  21. #endif
  22. #ifndef ODS_INACTIVE
  23.     #define ODS_INACTIVE 0x0080
  24. #endif
  25. #ifndef ODS_NOACCEL
  26.     #define ODS_NOACCEL 0x0100
  27. #endif
  28. #ifndef DT_HIDEPREFIX
  29.     #define DT_HIDEPREFIX 0x00100000
  30. #endif
  31. #ifndef SPI_GETKEYBOARDCUES
  32.     #define SPI_GETKEYBOARDCUES 0x100A
  33. #endif
  34. // From <winuser.h>
  35. #ifndef OBM_CHECK
  36.     #define OBM_CHECK 32760
  37. #endif
  38. #define IMGWIDTH 16
  39. #define IMGHEIGHT 16
  40. #define IMGPADDING 6
  41. #define TEXTPADDING 8
  42. #define TEXTPADDING_MNUBR 4
  43. #define SM_CXSHADOW 4
  44. const TCHAR _WndPropName_OldProc[] = _T("XPWndProp_OldProc");
  45. const TCHAR _WndPropName_MenuXP[] = _T("XPWndProp_MenuXP");
  46. ///////////////////////////////////////////////////////////////////////////////
  47. // Menu item management class
  48. //
  49. class CRTMenuItem
  50. {
  51. protected:
  52.     MENUITEMINFO m_miInfo;
  53.     CString      m_sCaption;
  54.     CImgDesc     m_ImgDesc;
  55.     HIMAGELIST   m_hImgList;
  56.     int          m_nIndex;
  57. public:
  58.     CRTMenuItem ();
  59.     CRTMenuItem (HMENU hMenu, UINT uItem, bool fByPosition = true);
  60.    ~CRTMenuItem ();
  61. // Properties
  62. public:
  63.     int   GetCaption   (CString& sCaption) const;
  64.     int   GetShortCut  (CString& sShortCut) const;
  65.     bool  GetSeparator () const;
  66.     bool  GetChecked   () const;
  67.     bool  GetRadio     () const;
  68.     bool  GetDisabled  () const;
  69.     bool  GetDefault   () const;
  70.     HMENU GetPopup     () const;
  71.     UINT  GetID        () const;
  72. // Methods
  73. public:
  74.     int  GetCaptionWidth  (CDC* pDC) const;
  75.     int  GetShortCutWidth (CDC* pDC) const;
  76.     int  GetHeight        (CDC* pDC) const;
  77.     bool Draw             (CDC* pDC, LPCRECT pRect, bool bSelected, bool bMenuBar = false, bool bHotLight = false, bool bInactive = false, bool bNoAccel = false) const;
  78. public:
  79.     static BYTE ms_nCheck;
  80.     static CRect ms_rcMRUMenuBarItem;
  81. };
  82. ///////////////////////////////////////////////////////////////////////////////
  83. ///////////////////////////////////////////////////////////////////////////////
  84. BYTE CRTMenuItem::ms_nCheck = 0;
  85. CRect CRTMenuItem::ms_rcMRUMenuBarItem (0, 0, 0, 0);
  86. ///////////////////////////////////////////////////////////////////////////////
  87. CRTMenuItem::CRTMenuItem ()
  88. {
  89.     memset (&m_miInfo, 0, sizeof(MENUITEMINFO));
  90. }
  91. ///////////////////////////////////////////////////////////////////////////////
  92. CRTMenuItem::CRTMenuItem (HMENU hMenu, UINT uItem, bool fByPosition)
  93. {
  94.     memset (&m_miInfo, 0, sizeof(MENUITEMINFO));
  95.     m_miInfo.cbSize = sizeof(MENUITEMINFO);
  96.     m_miInfo.fMask = MIIM_STATE|MIIM_SUBMENU|MIIM_TYPE|MIIM_DATA|MIIM_ID;
  97.     VERIFY (::GetMenuItemInfo (hMenu, uItem, fByPosition, &m_miInfo));
  98.     if ( !(m_miInfo.fType & MFT_SEPARATOR) )
  99.     {
  100.         if ( m_miInfo.hSubMenu != NULL )
  101.         {
  102.             CRTMenu::ms_sSubMenuCaptions.Lookup (m_miInfo.hSubMenu, m_sCaption);
  103.             CRTMenu::ms_SubMenuImages.Lookup (m_miInfo.hSubMenu, m_ImgDesc);
  104.         }
  105.         else
  106.         {
  107.             CRTMenu::ms_sCaptions.Lookup (m_miInfo.wID, m_sCaption);
  108.             CRTMenu::ms_Images.Lookup (m_miInfo.wID, m_ImgDesc);
  109.         }
  110.     }
  111. }
  112. ///////////////////////////////////////////////////////////////////////////////
  113. CRTMenuItem::~CRTMenuItem ()
  114. {
  115. }
  116. ///////////////////////////////////////////////////////////////////////////////
  117. int CRTMenuItem::GetCaption (CString& sCaption) const
  118. {
  119.     ASSERT(m_miInfo.fMask & MIIM_TYPE);
  120.     sCaption = m_sCaption;
  121.     int nShortCutPos = sCaption.Find ('t');
  122.     if ( nShortCutPos == -1 )
  123.     {
  124.         return sCaption.GetLength();
  125.     }
  126.     sCaption = sCaption.Left (nShortCutPos);
  127.     return nShortCutPos-1;
  128. }
  129. ///////////////////////////////////////////////////////////////////////////////
  130. int CRTMenuItem::GetShortCut (CString& sShortCut) const
  131. {
  132.     ASSERT(m_miInfo.fMask & MIIM_TYPE);
  133.     CString sCaption = m_sCaption;
  134.     int nShortCutPos = sCaption.Find ('t');
  135.     if ( nShortCutPos == -1 )
  136.     {
  137.         sShortCut = "";
  138.         return 0;
  139.     }
  140.     int nLength = sCaption.GetLength()-nShortCutPos-1;
  141.     sShortCut = sCaption.Right (nLength);
  142.     return nLength;
  143. }
  144. ///////////////////////////////////////////////////////////////////////////////
  145. bool CRTMenuItem::GetSeparator () const
  146. {
  147.     ASSERT(m_miInfo.fMask & MIIM_TYPE);
  148.     return (m_miInfo.fType & MFT_SEPARATOR) == MFT_SEPARATOR;
  149. }
  150. ///////////////////////////////////////////////////////////////////////////////
  151. bool CRTMenuItem::GetChecked () const
  152. {
  153.     ASSERT(m_miInfo.fMask & MIIM_STATE);
  154.     return (m_miInfo.fState & MFS_CHECKED) == MFS_CHECKED;
  155. }
  156. ///////////////////////////////////////////////////////////////////////////////
  157. bool CRTMenuItem::GetRadio () const
  158. {
  159.     ASSERT(m_miInfo.fMask & MIIM_TYPE);
  160.     return (m_miInfo.fType & MFT_RADIOCHECK) == MFT_RADIOCHECK;
  161. }
  162. ///////////////////////////////////////////////////////////////////////////////
  163. bool CRTMenuItem::GetDisabled () const
  164. {
  165.     ASSERT(m_miInfo.fMask & MIIM_STATE);
  166.     return (m_miInfo.fState & MFS_GRAYED) == MFS_GRAYED;
  167. }
  168. ///////////////////////////////////////////////////////////////////////////////
  169. bool CRTMenuItem::GetDefault () const
  170. {
  171.     ASSERT(m_miInfo.fMask & MIIM_STATE);
  172.     return (m_miInfo.fState & MFS_DEFAULT) == MFS_DEFAULT;
  173. }
  174. ///////////////////////////////////////////////////////////////////////////////
  175. HMENU CRTMenuItem::GetPopup () const
  176. {
  177.     ASSERT(m_miInfo.fMask & MIIM_SUBMENU);
  178.     return m_miInfo.hSubMenu;
  179. }
  180. ///////////////////////////////////////////////////////////////////////////////
  181. UINT CRTMenuItem::GetID () const
  182. {
  183.     ASSERT(m_miInfo.fMask & MIIM_ID);
  184.     return m_miInfo.wID;
  185. }
  186. ///////////////////////////////////////////////////////////////////////////////
  187. int CRTMenuItem::GetCaptionWidth (CDC* pDC) const
  188. {
  189.     if ( GetSeparator() )
  190.     {
  191.         return 0;
  192.     }
  193.     CString sCaption;
  194.     int nLength = 0;
  195.     if ( GetCaption (sCaption) > 0 )
  196.     {
  197.         int nPos = sCaption.Find ('&');
  198.         CBoldDC bold (*pDC, GetDefault());
  199.         if ( nPos >= 0 )
  200.         {
  201.             sCaption = sCaption.Left (nPos) + sCaption.Right (sCaption.GetLength()-nPos-1);
  202.         }
  203.         nLength = pDC->GetTextExtent (sCaption).cx;
  204.     }
  205.     return nLength;
  206. }
  207. ///////////////////////////////////////////////////////////////////////////////
  208. int CRTMenuItem::GetShortCutWidth (CDC* pDC) const
  209. {
  210.     if ( GetSeparator() )
  211.     {
  212.         return 0;
  213.     }
  214.     CString sShortCut;
  215.     int nLength = 0;
  216.     if ( GetShortCut (sShortCut) > 0 )
  217.     {
  218.         CBoldDC bold (*pDC, GetDefault());
  219.         nLength = pDC->GetTextExtent (sShortCut).cx;
  220.     }
  221.     return nLength;
  222. }
  223. ///////////////////////////////////////////////////////////////////////////////
  224. int CRTMenuItem::GetHeight (CDC* pDC) const
  225. {
  226.     TEXTMETRIC tm;
  227.     pDC->GetTextMetrics (&tm);
  228.                      
  229.     return GetSeparator() ? tm.tmHeight/2+2 : tm.tmHeight+4;
  230. }
  231. ///////////////////////////////////////////////////////////////////////////////
  232. bool CRTMenuItem::Draw (CDC* pDC, LPCRECT pRect, bool bSelected,bool bMenuBar, bool bHotLight, bool bInactive, bool bNoAccel) const
  233. {
  234.     COLORREF crBackImg = CLR_NONE;
  235.     bool bMenuBarItemSelected = false;
  236.     if ( bMenuBar && bSelected )
  237.     {
  238. if(CRTMenu::m_MenuBarBitmap[BMP_DOWN] != NULL && CRTMenu::m_bEnableSkin)
  239. {
  240. CRTDraw::RTDrawBitmap(pDC,pRect,CRTMenu::m_MenuBarBitmap[BMP_DOWN],CRTMenu::m_MenuBarBitmapDrawMode[BMP_DOWN]);
  241. }
  242. else
  243. {
  244. CRect rc (pRect);
  245. CPenDC pen (*pDC, ::GetSysColor (COLOR_3DDKSHADOW));
  246. CBrushDC brush (*pDC, HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), +20, 0));
  247. rc.right -= TEXTPADDING_MNUBR;
  248. ms_rcMRUMenuBarItem = rc;
  249. bMenuBarItemSelected = true;
  250. pDC->Rectangle (rc);
  251. rc.left = rc.right;
  252. rc.right += TEXTPADDING_MNUBR;
  253. pDC->FillSolidRect (rc, ::GetSysColor (COLOR_3DFACE));
  254. for ( int x = 0; x < SM_CXSHADOW; x++ )
  255. {
  256. for ( int y = ( x < 2 ) ? 2-x : 0; y < rc.Height()-x-((x>0)?1:2); y++ )
  257. {
  258. int nMakeSpec = 78+(3-(y==0?0:(y==1?(x<2?0:1):(y==2?(x<2?x:2):x))))*5;
  259. COLORREF cr = pDC->GetPixel (rc.right-x-1, rc.top+y+SM_CXSHADOW);
  260. COLORREF cr2 = RGB(((nMakeSpec * int(GetRValue(cr))) / 100),
  261. ((nMakeSpec * int(GetGValue(cr))) / 100),
  262. ((nMakeSpec * int(GetBValue(cr))) / 100));
  263. pDC->SetPixel (rc.right-x-1, rc.top+y+SM_CXSHADOW, cr2);
  264. }
  265. }
  266. }
  267.     }
  268.     else if ( bSelected || (bHotLight && !bInactive) )
  269.     {
  270.         COLORREF crHighLight = ::GetSysColor (COLOR_HIGHLIGHT);
  271.         CPenDC pen (*pDC, crHighLight);
  272.         CBrushDC brush (*pDC, crBackImg = GetDisabled() ? HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), +73, 0) : HLS_TRANSFORM (crHighLight, +70, -57));
  273.         if ( bMenuBar )
  274.         {
  275. if(CRTMenu::m_MenuBarBitmap[BMP_FOCUS] != NULL && CRTMenu::m_bEnableSkin)
  276. {
  277. CRTDraw::RTDrawBitmap(pDC,pRect,CRTMenu::m_MenuBarBitmap[BMP_FOCUS],CRTMenu::m_MenuBarBitmapDrawMode[BMP_FOCUS]);
  278. }
  279. else
  280. {
  281. CRect rc (pRect);
  282. rc.right -= TEXTPADDING_MNUBR;
  283. pDC->Rectangle (rc);
  284. rc.left = rc.right;
  285. rc.right += TEXTPADDING_MNUBR;
  286. pDC->FillSolidRect (rc, ::GetSysColor (COLOR_3DFACE));
  287. }
  288.         }
  289.         else
  290.         {
  291. if(CRTMenu::m_MenuItemBitmap[BMP_FOCUS] != NULL && CRTMenu::m_bEnableSkin)
  292. {
  293. CRect rc (pRect);
  294. rc.right = IMGWIDTH+IMGPADDING;
  295. CRTDraw::RTDrawBitmap(pDC,&rc,CRTMenu::m_MenuItemBitmap[BMP_SLIDER],CRTMenu::m_MenuItemBitmapDrawMode[BMP_SLIDER]);
  296. rc.left = rc.right;
  297. rc.right = pRect->right;
  298. CRTDraw::RTDrawBitmap(pDC,&rc,CRTMenu::m_MenuItemBitmap[BMP_FOCUS],CRTMenu::m_MenuItemBitmapDrawMode[BMP_FOCUS]);
  299. }
  300. else
  301. {
  302.   pDC->Rectangle (pRect);
  303. }
  304.         }
  305.     }
  306.     else if ( !bMenuBar )
  307.     {
  308.         CRect rc (pRect);
  309. rc.right = IMGWIDTH+IMGPADDING;
  310. if(CRTMenu::m_MenuItemBitmap[BMP_SLIDER] != NULL && CRTMenu::m_bEnableSkin)
  311. {
  312. CRTDraw::RTDrawBitmap(pDC,&rc,CRTMenu::m_MenuItemBitmap[BMP_SLIDER],CRTMenu::m_MenuItemBitmapDrawMode[BMP_SLIDER]);
  313. }
  314. else
  315. {
  316. pDC->FillSolidRect (rc, HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), +20, 0));
  317. }
  318. rc.left = rc.right;
  319. rc.right = pRect->right;
  320. if(CRTMenu::m_MenuItemBitmap[BMP_NORMAL] != NULL && CRTMenu::m_bEnableSkin)
  321. {
  322. CRTDraw::RTDrawBitmap(pDC,&rc,CRTMenu::m_MenuItemBitmap[BMP_NORMAL],CRTMenu::m_MenuItemBitmapDrawMode[BMP_NORMAL]);
  323. }
  324. else
  325. {
  326. pDC->FillSolidRect (rc, HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), +75, 0));
  327. }
  328.     }
  329.     else//MenuBar
  330.     {
  331. if(CRTMenu::m_MenuBarBitmap[BMP_NORMAL] != NULL && CRTMenu::m_bEnableSkin)
  332. {
  333. CRTDraw::RTDrawBitmap(pDC,pRect,CRTMenu::m_MenuBarBitmap[BMP_NORMAL],CRTMenu::m_MenuBarBitmapDrawMode[BMP_NORMAL]);
  334. }
  335. else
  336. {
  337. pDC->FillSolidRect (pRect, ::GetSysColor (COLOR_3DFACE));
  338. }
  339.     }
  340.     if ( GetSeparator() )
  341.     {
  342.         CPenDC pen (*pDC, HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), -18, 0));
  343.         pDC->MoveTo (pRect->left+IMGWIDTH+IMGPADDING+TEXTPADDING,  (pRect->top+pRect->bottom)/2);
  344.         pDC->LineTo (pRect->right-1, (pRect->top+pRect->bottom)/2);
  345.     }
  346.     else
  347.     {
  348.         CRect rc (pRect);
  349.         CString sCaption;
  350.         if ( GetCaption (sCaption) > 0 )
  351.         {
  352.             pDC->SetTextColor (bInactive ? ::GetSysColor (COLOR_3DSHADOW) : (GetDisabled() ? HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), -18, 0) : ::GetSysColor (COLOR_MENUTEXT)));
  353.             pDC->SetBkMode (TRANSPARENT);
  354.             BOOL bKeyboardCues = true;
  355.             ::SystemParametersInfo (SPI_GETKEYBOARDCUES, 0, &bKeyboardCues, 0);
  356.             DWORD dwHidePrefix = ( bNoAccel && !bKeyboardCues ) ? DT_HIDEPREFIX : 0;
  357.             if ( bMenuBar )
  358.             {
  359.                 rc.right -= TEXTPADDING_MNUBR;
  360.                 pDC->DrawText (sCaption, rc, DT_SINGLELINE|DT_VCENTER|DT_CENTER|dwHidePrefix);
  361.             }
  362.             else
  363.             {
  364.                 CBoldDC bold (*pDC, GetDefault());
  365.                 rc.left = IMGWIDTH+IMGPADDING+TEXTPADDING;
  366.                 pDC->DrawText (sCaption, rc, DT_SINGLELINE|DT_VCENTER|DT_LEFT|dwHidePrefix);
  367.                 CString sShortCut;
  368.                 if ( GetShortCut (sShortCut) > 0 )
  369.                 {
  370.                     rc.right -= TEXTPADDING+4;
  371.                     pDC->DrawText (sShortCut, rc, DT_SINGLELINE|DT_VCENTER|DT_RIGHT);
  372.                 }
  373.                 if ( GetChecked() )
  374.                 {
  375.                     COLORREF crHighLight = ::GetSysColor (COLOR_HIGHLIGHT);
  376.                     CPenDC pen (*pDC, crHighLight);
  377.                     CBrushDC brush (*pDC, crBackImg = GetDisabled() ? HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), +73, 0) :
  378.                                                                       (bSelected ? HLS_TRANSFORM (crHighLight, +50, -50) : HLS_TRANSFORM (crHighLight, +70, -57)));
  379.                     pDC->Rectangle (CRect (pRect->left+1, pRect->top+1, pRect->left+IMGWIDTH+4, pRect->bottom-1));
  380.                 }
  381.                 if ( m_ImgDesc.m_hImgList != NULL && m_ImgDesc.m_nIndex != -1 )
  382.                 {
  383.                     bool bOver = !GetDisabled() && bSelected;
  384.                     if ( GetDisabled() || (bSelected && !GetChecked()) )
  385.                     {
  386.                         HICON hIcon = ImageList_ExtractIcon (NULL, m_ImgDesc.m_hImgList, m_ImgDesc.m_nIndex);
  387.                         pDC->DrawState (CPoint (pRect->left + ( bOver ? 4 : 3 ), rc.top + ( bOver ? 4 : 3 )),
  388.                                         CSize (IMGWIDTH, IMGHEIGHT), hIcon, DSS_MONO,
  389.                                         CBrush (bOver ? HLS_TRANSFORM (::GetSysColor (COLOR_HIGHLIGHT), +50, -66) : HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), -27, 0)));
  390.                         DestroyIcon (hIcon);
  391.                     }
  392.                     if ( !GetDisabled() )
  393.                     {
  394.                         ::ImageList_Draw (m_ImgDesc.m_hImgList, m_ImgDesc.m_nIndex, pDC->m_hDC,
  395.                                           pRect->left+( (bSelected && !GetChecked()) ? 2 : 3 ), rc.top+( (bSelected && !GetChecked()) ? 2 : 3 ), ILD_TRANSPARENT);
  396.                     }
  397.                 }
  398.                 else if ( GetChecked() )
  399.                 {
  400.                     // Draw the check mark
  401.                     rc.left  = pRect->left+IMGWIDTH/4+1;
  402.                     rc.right = rc.left + IMGWIDTH-1;
  403.                     if ( GetRadio() )
  404.                     {
  405.                         CPoint ptCenter = rc.CenterPoint();
  406.                         COLORREF crBullet = GetDisabled() ? HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), -27, 0) : ::GetSysColor (COLOR_MENUTEXT);
  407.                         CPenDC pen (*pDC, crBullet);
  408.                         CBrushDC brush (*pDC, crBullet);
  409.                         
  410.                         pDC->Ellipse (CRect (ptCenter.x-4, ptCenter.y-3, ptCenter.x+3, ptCenter.y+4));
  411.                         pDC->SetPixel (ptCenter.x+1, ptCenter.y+2, crBackImg);
  412.                     }
  413.                     else
  414.                     {
  415.                         pDC->SetBkColor (crBackImg);
  416.                         HBITMAP hBmp = LoadBitmap (NULL, MAKEINTRESOURCE(OBM_CHECK));
  417.                         pDC->DrawState (CPoint (rc.left,rc.top+3), CSize(rc.Size()), hBmp, DSS_NORMAL, (HBRUSH)NULL);
  418.                         DeleteObject (hBmp);
  419.                     }
  420.                 }
  421.             }
  422.         }
  423.     }
  424.     return bMenuBarItemSelected;
  425. }
  426. ///////////////////////////////////////////////////////////////////////////////
  427. ///////////////////////////////////////////////////////////////////////////////
  428. CMap <int, int, CString, CString&> CRTMenu::ms_sCaptions;
  429. CMap <HMENU, HMENU, CString, CString&> CRTMenu::ms_sSubMenuCaptions;
  430. CMap <int, int, CImgDesc, CImgDesc&> CRTMenu::ms_Images;
  431. CMap <HMENU, HMENU, CImgDesc, CImgDesc&> CRTMenu::ms_SubMenuImages;
  432. CBitmap* CRTMenu::m_MenuBarBitmap[5] = {NULL,NULL,NULL,NULL,NULL};
  433. UINT     CRTMenu::m_MenuBarBitmapDrawMode[5] = {0,0,0,0,0};
  434. CBitmap* CRTMenu::m_MenuItemBitmap[5] = {NULL,NULL,NULL,NULL,NULL};
  435. UINT     CRTMenu::m_MenuItemBitmapDrawMode[5] = {0,0,0,0,0};
  436. BOOL     CRTMenu::m_bEnableSkin = FALSE;
  437. ///////////////////////////////////////////////////////////////////////////////
  438. void CRTMenu::EnableSkin(BOOL IsEnable)
  439. {
  440. m_bEnableSkin = IsEnable;
  441. }
  442. void CRTMenu::SetXPLookNFeel (CWnd* pWnd, BOOL bXPLook)
  443. {
  444.     if ( bXPLook )
  445.     {
  446.         ::SetProp (pWnd->GetSafeHwnd(), _WndPropName_MenuXP, (HANDLE)TRUE);
  447.     }
  448.     else
  449.     {
  450.         ::RemoveProp (pWnd->GetSafeHwnd(), _WndPropName_MenuXP);
  451.     }
  452. }
  453. ///////////////////////////////////////////////////////////////////////////////
  454. bool CRTMenu::GetXPLookNFeel (const CWnd* pWnd)
  455. {
  456.     return ::GetProp (pWnd->GetSafeHwnd(), _WndPropName_MenuXP) != NULL;
  457. }
  458. ///////////////////////////////////////////////////////////////////////////////
  459. void CRTMenu::UpdateMenuBar (CWnd* pWnd)
  460. {
  461.     if ( GetXPLookNFeel (pWnd) )
  462.     {
  463.         HMENU hMenu = pWnd->GetMenu()->GetSafeHmenu();
  464.         if ( hMenu != NULL )
  465.         {
  466.             SetXPLookNFeel (pWnd, hMenu, true, true);
  467.         }
  468.     }
  469. }
  470. ///////////////////////////////////////////////////////////////////////////////
  471. void CRTMenu::SetXPLookNFeel (CWnd* pWnd, HMENU hMenu, BOOL bXPLook, BOOL bMenuBar)
  472. {
  473.     if ( !bXPLook )
  474.     {
  475.         // TODO: Remove the ownerdraw style ?
  476.         return;
  477.     }
  478. //    TRACE(_T("Referenced captions : %in"), ms_sCaptions.GetCount()+ms_sSubMenuCaptions.GetCount());
  479.     // Clean up old references...
  480.     // ... for captions
  481.     POSITION pos = ms_sSubMenuCaptions.GetStartPosition();
  482.     while ( pos != NULL )
  483.     {
  484.         HMENU hSubMenu;
  485.         CString sBuff;
  486.         ms_sSubMenuCaptions.GetNextAssoc (pos, hSubMenu, sBuff);
  487.         if ( !::IsMenu (hSubMenu) )
  488.         {
  489.             ms_sSubMenuCaptions.RemoveKey (hSubMenu);
  490.         }
  491.     }
  492.     // ... for images
  493.     pos = ms_SubMenuImages.GetStartPosition();
  494.     while ( pos != NULL )
  495.     {
  496.         HMENU hSubMenu;
  497.         CImgDesc ImgDesc;
  498.         ms_SubMenuImages.GetNextAssoc (pos, hSubMenu, ImgDesc);
  499.         if ( !::IsMenu (hSubMenu) )
  500.         {
  501.             ms_SubMenuImages.RemoveKey (hSubMenu);
  502.         }
  503.     }
  504.     ASSERT(hMenu != NULL);
  505.     int nItemCount = ::GetMenuItemCount (hMenu);
  506.     MENUITEMINFO mii = { sizeof MENUITEMINFO, MIIM_ID|MIIM_TYPE|MIIM_SUBMENU };
  507.     CClientDC cDC (AfxGetMainWnd());
  508.     TEXTMETRIC tm;
  509.     CFontDC font (cDC, DEFAULT_GUI_FONT);
  510.     cDC.GetTextMetrics (&tm);
  511.     int nHeight = max(tm.tmHeight+2,IMGHEIGHT)+4;
  512.     int nSepHeight = tm.tmHeight/2+2;
  513.     int nCaptionLength = 0;
  514.     int nShortCutLength = 0;
  515.     CPtrList* pListControlBars = NULL;
  516.     if ( pWnd != NULL && !bMenuBar )
  517.     {
  518.         if ( pWnd->IsKindOf (RUNTIME_CLASS(CMDIFrameWnd)) )
  519.         {
  520.             CMDIChildWnd* pActiveChild = ((CMDIFrameWnd*)pWnd)->MDIGetActive();
  521.             if ( pActiveChild != NULL && pActiveChild->GetSystemMenu (false)->GetSafeHmenu() == hMenu )
  522.             {
  523.                 CRTMenuItem::ms_rcMRUMenuBarItem.SetRectEmpty();
  524.                 return;
  525.             }
  526.         }
  527.         if ( pWnd->IsKindOf (RUNTIME_CLASS(CFrameWnd)) && !((CFrameWnd*)pWnd)->m_listControlBars.IsEmpty() )
  528.         {
  529.             pListControlBars = &((CFrameWnd*)pWnd)->m_listControlBars;
  530.         }
  531.         else
  532.         {
  533.             CFrameWnd* pFrame = pWnd->GetParentFrame();
  534.             if ( pFrame != NULL && pFrame->IsKindOf (RUNTIME_CLASS(CMDIChildWnd)) )
  535.             {
  536.                 pFrame = pFrame->GetParentFrame();
  537.             }
  538.             if ( pFrame != NULL )
  539.             {
  540.                 pListControlBars = &pFrame->m_listControlBars;
  541.             }
  542.         }
  543.     }
  544.     for ( int i = 0; i < nItemCount; i++ )
  545.     {
  546.         TCHAR sCaption[256] = _T("");
  547.         mii.dwTypeData = sCaption;
  548.         mii.cch = 255;
  549.         mii.fMask &= ~MIIM_DATA;
  550.         ::GetMenuItemInfo (hMenu, i, true, &mii);
  551.         if ( (mii.fType & MFT_OWNERDRAW) == 0 && (!bMenuBar || (mii.fType & MFT_BITMAP) == 0) )
  552.         {
  553.             mii.fType |= MFT_OWNERDRAW;
  554.             if ( bMenuBar )
  555.             {
  556.                 CRect rcText (0, 0, 1000, 0);
  557.                 cDC.DrawText (sCaption, (int)_tcslen (sCaption), rcText, DT_SINGLELINE|DT_LEFT|DT_CALCRECT);
  558.                 mii.dwItemData = MAKELONG(MAKEWORD(0, 0), rcText.Width());
  559.                 mii.fMask |= MIIM_DATA;
  560.             }
  561.             ::SetMenuItemInfo (hMenu, i, true, &mii);
  562.             if ( (mii.fType & MFT_SEPARATOR) == 0 )
  563.             {
  564.                 CString sBuff(sCaption);
  565.                 if ( mii.hSubMenu != NULL )
  566.                 {
  567.                     ms_sSubMenuCaptions.SetAt (mii.hSubMenu, sBuff);
  568.                 }
  569.                 else
  570.                 {
  571.                     ms_sCaptions.SetAt (mii.wID, sBuff);
  572.                 }
  573.                 if ( pListControlBars != NULL )
  574.                 {
  575.                     POSITION pos = pListControlBars->GetHeadPosition();
  576.                     while ( pos != NULL )
  577.                     {
  578.                         CControlBar* pBar = (CControlBar*)pListControlBars->GetNext (pos);
  579.                         ASSERT(pBar != NULL);
  580.                         TCHAR sClassName[256];
  581.                         ::GetClassName (pBar->m_hWnd, sClassName, lengthof (sClassName));
  582.                         if ( !_tcsicmp (sClassName, _T("ToolbarWindow32")) )
  583.                         {
  584.                             TBBUTTONINFO tbbi = { sizeof(TBBUTTONINFO), TBIF_COMMAND|TBIF_IMAGE };
  585.                             if ( pBar->SendMessage (TB_GETBUTTONINFO, mii.wID, (LPARAM)&tbbi) != -1 &&
  586.                                  (UINT)tbbi.idCommand == mii.wID && tbbi.iImage != -1 )
  587.                             {
  588.                                 CImgDesc imgDesc ((HIMAGELIST)pBar->SendMessage (TB_GETIMAGELIST, 0, 0), tbbi.iImage);
  589.                                 if ( mii.hSubMenu != NULL )
  590.                                 {
  591.                                     ms_SubMenuImages.SetAt (mii.hSubMenu, imgDesc);
  592.                                 }
  593.                                 else
  594.                                 {
  595.                                     ms_Images.SetAt (mii.wID, imgDesc);
  596.                                 }
  597.                                 break;
  598.                             }
  599.                         }
  600.                     }
  601.                 }
  602.             }
  603.         }
  604.         if ( !bMenuBar )
  605.         {
  606.             CRTMenuItem mnuItem (hMenu, i);
  607.             int       nWidth = mnuItem.GetCaptionWidth (&cDC);
  608.             if ( nWidth > nCaptionLength )
  609.             {
  610.                 nCaptionLength = nWidth;
  611.             }
  612.             nWidth = mnuItem.GetShortCutWidth (&cDC);
  613.             if ( nWidth > nShortCutLength )
  614.             {
  615.                 nShortCutLength = nWidth;
  616.             }
  617.         }
  618.     }
  619.     if ( !bMenuBar )
  620.     {
  621.         for ( int j = 0; j < nItemCount; j++ )
  622.         {
  623.             mii.fMask = MIIM_TYPE;
  624.             ::GetMenuItemInfo (hMenu, j, true, &mii);
  625.             if ( (mii.fType & MFT_SEPARATOR) == 0 )
  626.             {
  627.                 mii.dwItemData = MAKELONG(MAKEWORD(nHeight, nShortCutLength), nCaptionLength);
  628.             }
  629.             else
  630.             {
  631.                 mii.dwItemData = nSepHeight;
  632.             }
  633.             mii.fMask = MIIM_DATA;
  634.             ::SetMenuItemInfo (hMenu, j, true, &mii);
  635.         }
  636.     }
  637. }
  638. ///////////////////////////////////////////////////////////////////////////////
  639. bool CRTMenu::IsOwnerDrawn (HMENU hMenu)
  640. {
  641.     MENUITEMINFO mii = { sizeof MENUITEMINFO, MIIM_TYPE };
  642.     ::GetMenuItemInfo (hMenu, 0, true, &mii);
  643.     return (mii.fType & MFT_OWNERDRAW) != 0;
  644. }
  645. ///////////////////////////////////////////////////////////////////////////////
  646. void CRTMenu::SetMRUMenuBarItem (RECT& rc)
  647. {
  648.     CRTMenuItem::ms_rcMRUMenuBarItem = rc;
  649. }
  650. ///////////////////////////////////////////////////////////////////////////////
  651. void CRTMenu::SetMenuItemImage (UINT nID, HIMAGELIST hImgList, int nIndex)
  652. {
  653.     CImgDesc imgDesc (hImgList, nIndex);
  654.     ms_Images.SetAt (nID, imgDesc);
  655. }
  656. void CRTMenu::SetMenuBarBitmap(CBitmap* MenuBarBitmap[],UINT DrawMode[])
  657. {
  658. for(int i = 0; i < 5; i ++)
  659. {
  660. m_MenuBarBitmap[i] = MenuBarBitmap[i];
  661. m_MenuBarBitmapDrawMode[i] = DrawMode[i];
  662. }
  663. }
  664. void CRTMenu::SetMenuItemBitmap(CBitmap* MenuItemBitmap[],UINT DrawMode[])
  665. {
  666. for(int i = 0; i < 5; i ++)
  667. {
  668. m_MenuItemBitmap[i] = MenuItemBitmap[i];
  669. m_MenuItemBitmapDrawMode[i] = DrawMode[i];
  670. }
  671. }
  672. ///////////////////////////////////////////////////////////////////////////////
  673. void CRTMenu::OnMeasureItem (MEASUREITEMSTRUCT* pMeasureItemStruct)
  674. {
  675.     if ( pMeasureItemStruct->CtlType == ODT_MENU )
  676.     {
  677.         pMeasureItemStruct->itemHeight = LOBYTE(LOWORD(pMeasureItemStruct->itemData));
  678.         if ( pMeasureItemStruct->itemHeight == 0 )
  679.         {
  680.             // This is a menubar item
  681.             pMeasureItemStruct->itemWidth = HIWORD(pMeasureItemStruct->itemData) + TEXTPADDING_MNUBR;
  682.         }
  683.         else
  684.         {
  685.             pMeasureItemStruct->itemWidth = IMGWIDTH + IMGPADDING + HIWORD(pMeasureItemStruct->itemData) + TEXTPADDING + HIBYTE(LOWORD(pMeasureItemStruct->itemData)) + TEXTPADDING + 4;
  686.         }
  687.     }
  688. }
  689. ///////////////////////////////////////////////////////////////////////////////
  690. bool CRTMenu::OnDrawItem (DRAWITEMSTRUCT* pDrawItemStruct, HWND hWnd)
  691. {
  692.     if ( pDrawItemStruct->CtlType != ODT_MENU )
  693.     {
  694.         return false;
  695.     }
  696.     ASSERT (pDrawItemStruct->CtlType == ODT_MENU);
  697.     CBufferDC cDC (pDrawItemStruct->hDC, pDrawItemStruct->rcItem);
  698.     CRTMenuItem item ((HMENU)pDrawItemStruct->hwndItem, pDrawItemStruct->itemID, false);
  699.     CFontDC font (cDC, DEFAULT_GUI_FONT);
  700. if ( item.Draw (&cDC, &pDrawItemStruct->rcItem, (pDrawItemStruct->itemState&ODS_SELECTED)!=0,LOBYTE(LOWORD(pDrawItemStruct->itemData))==0, (pDrawItemStruct->itemState&ODS_HOTLIGHT)!=0, (pDrawItemStruct->itemState&ODS_INACTIVE)!=0, (pDrawItemStruct->itemState&ODS_NOACCEL)!=0) )
  701.     {
  702.         CRect rc;
  703.         ::GetMenuItemRect (hWnd, (HMENU)pDrawItemStruct->hwndItem, 0, rc);
  704.         ::ClientToScreen (hWnd, CRTMenuItem::ms_rcMRUMenuBarItem);
  705.         CRTMenuItem::ms_rcMRUMenuBarItem.top = rc.top;
  706.         CRTMenuItem::ms_rcMRUMenuBarItem.bottom = rc.bottom;
  707.         
  708.         if ( CWnd::FromHandle (hWnd)->IsKindOf (RUNTIME_CLASS(CDialog)) )
  709.         {
  710.             CRTMenuItem::ms_rcMRUMenuBarItem.OffsetRect (1, 0);
  711.         }
  712.     }
  713.     CRTMenuItem::ms_nCheck++;
  714.     
  715.     return true;
  716. }
  717. ///////////////////////////////////////////////////////////////////////////////
  718. LRESULT CRTMenu::OnMenuChar (HMENU hMenu, UINT nChar, UINT nFlags)
  719. {
  720.     if ( (nFlags & (MF_POPUP|MF_SYSMENU)) == MF_POPUP || nFlags == 0 )
  721.     {
  722.         int nItemCount = ::GetMenuItemCount (hMenu);
  723.         nChar = toupper (nChar);
  724.         for ( int i = 0; i < nItemCount; i++ )
  725.         {
  726.             CRTMenuItem mnuItem (hMenu, i);
  727.             CString sCaption;
  728.             mnuItem.GetCaption (sCaption);
  729.             sCaption.MakeUpper();
  730.             for ( int nPos = sCaption.GetLength()-2; nPos >= 0; nPos-- )
  731.             {
  732.                 if ( sCaption[nPos] == '&' && (UINT)toupper (sCaption[nPos+1]) == nChar &&
  733.                      (nPos == 0 || sCaption[nPos-1] != '&') )
  734.                 {
  735.                     return MAKELRESULT(i,2);
  736.                 }
  737.             }
  738.         }
  739.     }
  740.     return 0;
  741. }
  742. ///////////////////////////////////////////////////////////////////////////////
  743. ///////////////////////////////////////////////////////////////////////////////
  744. // CRTWndMenu class : management of the window used by system to display popup menus
  745. //
  746. class CRTWndMenu
  747. {
  748. public:
  749.     CRTWndMenu (HWND hWnd);
  750.    ~CRTWndMenu ();
  751. public:
  752.     static CRTWndMenu* FromHandle (HWND hWnd, bool bPermanent = true);
  753. protected:
  754.     void OnWindowPosChanging (WINDOWPOS* pWP);
  755.     void OnEraseBkgnd ();
  756.     void OnPrint (CDC* pDC, bool bOwnerDrawnItems);
  757.     void OnNcPaint ();
  758.     void OnShowWindow (bool bShow);
  759.     void OnNcDestroy ();
  760. private:
  761.     static LRESULT CALLBACK WindowsHook (int code, WPARAM wParam, LPARAM lParam);
  762.     static LRESULT CALLBACK SubClassMenuProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  763. protected:
  764.     HWND m_hWnd;
  765.     CRect m_rcMenu;
  766.     CPoint m_ptMenu;
  767.     CBitmap m_bmpBkGnd;
  768.     static CMap <HWND, HWND, CRTWndMenu*, CRTWndMenu*> ms_WndMenuMap;
  769.     static DWORD ms_dwRefCount;
  770.     static HHOOK ms_hHookOldMenuCbtFilter;
  771. friend class CRTMenu;
  772. };
  773. ///////////////////////////////////////////////////////////////////////////////
  774. void CRTMenu::InitializeHook ()
  775. {
  776.     CRTWndMenu::ms_dwRefCount++;
  777.     if ( CRTWndMenu::ms_hHookOldMenuCbtFilter == NULL )
  778.     {
  779.         CRTWndMenu::ms_hHookOldMenuCbtFilter = ::SetWindowsHookEx (WH_CALLWNDPROC, CRTWndMenu::WindowsHook, AfxGetApp()->m_hInstance, ::GetCurrentThreadId());
  780.     }
  781. }
  782. ///////////////////////////////////////////////////////////////////////////////
  783. void CRTMenu::UninitializeHook ()
  784. {
  785.     if ( CRTWndMenu::ms_dwRefCount == 0 )
  786.     {
  787.         return;
  788.     }
  789.     if ( --CRTWndMenu::ms_dwRefCount == 0 )
  790.     {
  791.         POSITION pos = CRTWndMenu::ms_WndMenuMap.GetStartPosition();
  792.         while ( pos != NULL )
  793.         {
  794.             HWND hKey;
  795.             CRTWndMenu* pVal;
  796.             CRTWndMenu::ms_WndMenuMap.GetNextAssoc (pos, hKey, pVal);
  797.             delete pVal;
  798.         }
  799.         CRTWndMenu::ms_WndMenuMap.RemoveAll();
  800.         if ( CRTWndMenu::ms_hHookOldMenuCbtFilter != NULL )
  801.         {
  802.             ::UnhookWindowsHookEx (CRTWndMenu::ms_hHookOldMenuCbtFilter);
  803.         }
  804.     }
  805. }
  806. ///////////////////////////////////////////////////////////////////////////////
  807. CMap <HWND, HWND, CRTWndMenu*, CRTWndMenu*> CRTWndMenu::ms_WndMenuMap;
  808. DWORD CRTWndMenu::ms_dwRefCount = 0;
  809. HHOOK CRTWndMenu::ms_hHookOldMenuCbtFilter = NULL;
  810. ///////////////////////////////////////////////////////////////////////////////
  811. CRTWndMenu::CRTWndMenu (HWND hWnd)
  812.     : m_hWnd (hWnd), m_rcMenu (0, 0, 0, 0), m_ptMenu (-0xFFFF, -0xFFFF)
  813. {
  814. }
  815. ///////////////////////////////////////////////////////////////////////////////
  816. CRTWndMenu::~CRTWndMenu ()
  817. {
  818.     WNDPROC oldWndProc = (WNDPROC)::GetProp (m_hWnd, _WndPropName_OldProc);
  819.     if ( oldWndProc != NULL )
  820.     {
  821.         ::SetWindowLong (m_hWnd, GWL_WNDPROC, (DWORD)(DWORD_PTR)oldWndProc);
  822.         ::RemoveProp (m_hWnd, _WndPropName_OldProc);
  823.     }
  824.     ms_WndMenuMap.RemoveKey (m_hWnd);
  825. }
  826. ///////////////////////////////////////////////////////////////////////////////
  827. CRTWndMenu* CRTWndMenu::FromHandle (HWND hWnd, bool bPermanent)
  828. {
  829.     CRTWndMenu* pWnd = NULL;
  830.     if ( ms_WndMenuMap.Lookup (hWnd, pWnd) )
  831.     {
  832.         return pWnd;
  833.     }
  834.     if ( bPermanent )
  835.     {
  836.         return NULL;
  837.     }
  838.     pWnd = new CRTWndMenu (hWnd);
  839.     ms_WndMenuMap.SetAt (hWnd, pWnd);
  840.     return pWnd;
  841. }
  842. ///////////////////////////////////////////////////////////////////////////////
  843. void CRTWndMenu::OnWindowPosChanging (WINDOWPOS* pWP)
  844. {
  845.     if ( GetWinVersion() < wvWinXP )
  846.     {
  847.         pWP->cx += SM_CXSHADOW;
  848.         pWP->cy += SM_CXSHADOW;
  849.     }
  850.     pWP->y--;
  851.     m_ptMenu.x = pWP->x;
  852.     m_ptMenu.y = pWP->y;
  853. }
  854. ///////////////////////////////////////////////////////////////////////////////
  855. void CRTWndMenu::OnEraseBkgnd ()
  856. {
  857.     if ( !IsWindowVisible (m_hWnd) )
  858.     {
  859.         CClientRect rc (m_hWnd);
  860.         if ( m_bmpBkGnd.m_hObject != NULL )
  861.         {
  862.             m_bmpBkGnd.DeleteObject();
  863.         }
  864.         m_bmpBkGnd.Attach (GetScreenBitmap (CRect (m_ptMenu.x, m_ptMenu.y, rc.right+m_ptMenu.x+10,
  865.                                                    rc.bottom+m_ptMenu.y+10)));
  866.     }
  867. }
  868. ///////////////////////////////////////////////////////////////////////////////
  869. void DrawShadow (HDC hDCIn, HDC hDCOut, RECT& rc)
  870. {
  871.     for ( int x = 0; x < rc.right-1; x++ )
  872.     {
  873.         int nEnd = ( x > rc.right-SM_CXSHADOW*2 ) ? rc.right-SM_CXSHADOW-x : SM_CXSHADOW;
  874.         for ( int y = ( x < 2 ) ? 2-x : x > rc.right-SM_CXSHADOW-3 ? x-rc.right+SM_CXSHADOW+3 : 0; y < nEnd; y++ )
  875.         {
  876.             int nMakeSpec = 78+(3-(x==0?0:(x==1?(y<2?0:1):(x==2?(y<2?y:2):y))))*5;
  877.             COLORREF cr = GetPixel (hDCIn, x+SM_CXSHADOW, rc.bottom-y-1);
  878.             COLORREF cr2 = RGB(((nMakeSpec * int(GetRValue(cr))) / 100),
  879.                    ((nMakeSpec * int(GetGValue(cr))) / 100),
  880.                    ((nMakeSpec * int(GetBValue(cr))) / 100));
  881. SetPixel (hDCOut, x+SM_CXSHADOW, rc.bottom-y-1, cr2);
  882.         }
  883.     }
  884.     for ( x = 0; x < SM_CXSHADOW; x++ )
  885.     {
  886.         for ( int y = ( x < 2 ) ? 2-x : 0; y < rc.bottom-x-SM_CXSHADOW-((x>0)?1:2); y++ )
  887.         {
  888.             int nMakeSpec = 78+(3-(y==0?0:(y==1?(x<2?0:1):(y==2?(x<2?x:2):x))))*5;
  889.             COLORREF cr = GetPixel (hDCIn, rc.right-x-1, y+SM_CXSHADOW);
  890.             COLORREF cr2 = RGB(((nMakeSpec * int(GetRValue(cr))) / 100),
  891.                    ((nMakeSpec * int(GetGValue(cr))) / 100),
  892.                    ((nMakeSpec * int(GetBValue(cr))) / 100));
  893. SetPixel (hDCOut, rc.right-x-1, y+SM_CXSHADOW, cr2);
  894.         }
  895.     }
  896. }
  897. ///////////////////////////////////////////////////////////////////////////////
  898. void CRTWndMenu::OnPrint (CDC* pDC, bool bOwnerDrawnItems)
  899. {
  900.     CWindowRect rc (m_hWnd);
  901.     CBrushDC br (pDC->m_hDC);
  902.     CPenDC pen (pDC->m_hDC, ::GetSysColor (COLOR_3DDKSHADOW));
  903.     rc.OffsetRect (-rc.TopLeft());
  904.     m_rcMenu = rc;
  905.     if ( GetWinVersion() < wvWinXP )
  906.     {
  907.         rc.right -= SM_CXSHADOW;
  908.         rc.bottom -= SM_CXSHADOW;
  909.     }
  910.     pDC->Rectangle (rc);
  911.     pen.Color (HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), +75, 0));
  912.     rc.DeflateRect (1, 1);
  913.     pDC->Rectangle (rc);
  914.     rc.DeflateRect (1, 1);
  915.     pDC->Rectangle (rc);
  916.     if ( bOwnerDrawnItems && !CRTMenuItem::ms_rcMRUMenuBarItem.IsRectEmpty() &&
  917.          CRTMenuItem::ms_rcMRUMenuBarItem.bottom == m_ptMenu.y+1 )
  918.     {
  919.         pen.Color (HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), +20, 0));
  920.         pDC->MoveTo (CRTMenuItem::ms_rcMRUMenuBarItem.left-m_ptMenu.x-3, 0);
  921.         pDC->LineTo (CRTMenuItem::ms_rcMRUMenuBarItem.left-m_ptMenu.x+CRTMenuItem::ms_rcMRUMenuBarItem.Width()-5, 0);
  922.     }
  923.     if ( GetWinVersion() < wvWinXP )
  924.     {
  925.         rc.right += SM_CXSHADOW+2;
  926.         rc.bottom += SM_CXSHADOW+2;
  927.         CDC cMemDC;
  928.         cMemDC.CreateCompatibleDC (pDC);
  929.         HGDIOBJ hOldBitmap = ::SelectObject (cMemDC.m_hDC, m_bmpBkGnd);
  930.         pDC->BitBlt (0, rc.bottom-SM_CXSHADOW, SM_CXSHADOW*2, SM_CXSHADOW, &cMemDC, 0, rc.bottom-SM_CXSHADOW, SRCCOPY);
  931.         pDC->BitBlt (rc.right-SM_CXSHADOW, rc.bottom-SM_CXSHADOW, SM_CXSHADOW, SM_CXSHADOW, &cMemDC, rc.right-SM_CXSHADOW, rc.bottom-SM_CXSHADOW, SRCCOPY);
  932.         pDC->BitBlt (rc.right-SM_CXSHADOW, 0, SM_CXSHADOW, SM_CXSHADOW*2, &cMemDC, rc.right-SM_CXSHADOW, 0, SRCCOPY);
  933.         DrawShadow (cMemDC.m_hDC, pDC->m_hDC, rc);
  934.         ::SelectObject (cMemDC.m_hDC, hOldBitmap);
  935.     }
  936. }
  937. ///////////////////////////////////////////////////////////////////////////////
  938. void CRTWndMenu::OnNcPaint ()
  939. {
  940.     CWindowDC cDC (CWnd::FromHandle (m_hWnd));
  941.     CDC* pDC = &cDC;
  942.     CWindowRect rc (m_hWnd);
  943.     m_ptMenu.x = rc.left;
  944.     m_ptMenu.y = rc.top;
  945.     rc.OffsetRect (-rc.TopLeft());
  946.     if ( rc != m_rcMenu )
  947.     {
  948.         m_rcMenu = rc;
  949.         CBrushDC br (pDC->m_hDC);
  950.         CPenDC pen (pDC->m_hDC, ::GetSysColor (COLOR_3DDKSHADOW));
  951.         if ( GetWinVersion() < wvWinXP )
  952.         {
  953.             rc.right -= SM_CXSHADOW;
  954.             rc.bottom -= SM_CXSHADOW;
  955.         }
  956.         pDC->Rectangle (rc);
  957.         pen.Color (HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), +75, 0));
  958.         rc.DeflateRect (1, 1);
  959. pDC->Rectangle (rc);
  960.         rc.DeflateRect (1, 1);
  961. pDC->Rectangle (rc);
  962.         if ( !CRTMenuItem::ms_rcMRUMenuBarItem.IsRectEmpty() &&
  963.              CRTMenuItem::ms_rcMRUMenuBarItem.bottom == m_ptMenu.y+1 )
  964.         {
  965.             pen.Color (HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), +20, 0));
  966.             pDC->MoveTo (CRTMenuItem::ms_rcMRUMenuBarItem.left-m_ptMenu.x-3, 0);
  967.             pDC->LineTo (CRTMenuItem::ms_rcMRUMenuBarItem.left-m_ptMenu.x+CRTMenuItem::ms_rcMRUMenuBarItem.Width()-5, 0);
  968.         }
  969.         if ( GetWinVersion() < wvWinXP )
  970.         {
  971.             rc.right += SM_CXSHADOW+2;
  972.             rc.bottom += SM_CXSHADOW+2;
  973.             DrawShadow (pDC->m_hDC, pDC->m_hDC, rc);
  974.         }
  975.     }
  976. }
  977. ///////////////////////////////////////////////////////////////////////////////
  978. void CRTWndMenu::OnShowWindow (bool bShow)
  979. {
  980.     if ( !bShow )
  981.     {
  982.         delete this;
  983.     }
  984. }
  985. ///////////////////////////////////////////////////////////////////////////////
  986. void CRTWndMenu::OnNcDestroy ()
  987. {
  988.     delete this;
  989. }
  990. ///////////////////////////////////////////////////////////////////////////////
  991. LRESULT CALLBACK CRTWndMenu::WindowsHook (int code, WPARAM wParam, LPARAM lParam)
  992. {
  993.     CWPSTRUCT* pStruct = (CWPSTRUCT*)lParam;
  994.     // Not a real loop (just for 'break' branchment)
  995.     while ( code == HC_ACTION )
  996.     {
  997.         HWND hWnd = pStruct->hwnd;
  998.         // Normal and special handling for menu 0x10012
  999.         if ( pStruct->message != WM_CREATE && pStruct->message != 0x01E2 )
  1000.         {
  1001.             break;
  1002.         }
  1003.         CWnd* pFrame = CWnd::GetForegroundWindow();
  1004. if ( pFrame == NULL || !CRTMenu::GetXPLookNFeel (pFrame) || !CRTMenu::m_bEnableSkin )
  1005.         {
  1006.             break;
  1007.         }
  1008.         TCHAR sClassName[10];
  1009.         int Count = ::GetClassName (hWnd, sClassName, lengthof(sClassName));
  1010.         // Check for the menu-class
  1011.         if ( Count != 6 || _tcscmp (sClassName, _T("#32768")) != 0 )
  1012.         {
  1013.             break;
  1014.         }
  1015.         VERIFY(CRTWndMenu::FromHandle (pStruct->hwnd, false) != NULL);
  1016.         if ( ::GetProp (pStruct->hwnd, _WndPropName_OldProc) != NULL )
  1017.         {
  1018.             // Already subclassed
  1019.             break;
  1020.         }
  1021.         // Subclass the window
  1022.         WNDPROC oldWndProc = (WNDPROC)(LONG_PTR)::GetWindowLong (pStruct->hwnd, GWL_WNDPROC);
  1023.         if ( oldWndProc == NULL )
  1024.         {
  1025.             break;
  1026.         }
  1027.         ASSERT(oldWndProc != SubClassMenuProc);
  1028.         if ( !SetProp (pStruct->hwnd, _WndPropName_OldProc, oldWndProc) )
  1029.         {
  1030.             break;
  1031.         }
  1032.         if ( !SetWindowLong (pStruct->hwnd, GWL_WNDPROC,(DWORD)(DWORD_PTR)SubClassMenuProc) )
  1033.         {
  1034.             ::RemoveProp (pStruct->hwnd, _WndPropName_OldProc);
  1035.             break;
  1036.         }
  1037.         // Success !
  1038.         break;
  1039.     }
  1040.     return CallNextHookEx (CRTWndMenu::ms_hHookOldMenuCbtFilter, code, wParam, lParam);
  1041. }
  1042. ///////////////////////////////////////////////////////////////////////////////
  1043. LRESULT CALLBACK CRTWndMenu::SubClassMenuProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1044. {
  1045.     WNDPROC oldWndProc = (WNDPROC)::GetProp (hWnd, _WndPropName_OldProc);
  1046.     CRTWndMenu* pWnd = NULL;
  1047.     switch ( uMsg )
  1048.     {
  1049.     case WM_NCCALCSIZE:
  1050.         {
  1051.             LRESULT lResult = CallWindowProc (oldWndProc, hWnd, uMsg, wParam, lParam);
  1052.             if ( GetWinVersion() < wvWinXP )
  1053.             {
  1054.                 NCCALCSIZE_PARAMS* lpncsp = (NCCALCSIZE_PARAMS*)lParam;
  1055.                 lpncsp->rgrc[0].right -= SM_CXSHADOW;
  1056.                 lpncsp->rgrc[0].bottom -= SM_CXSHADOW;
  1057.             }
  1058.             return lResult;
  1059.         }
  1060.     case WM_WINDOWPOSCHANGING:
  1061.         if ( (pWnd=CRTWndMenu::FromHandle (hWnd)) != NULL )
  1062.         {
  1063.             pWnd->OnWindowPosChanging ((LPWINDOWPOS)lParam);
  1064.         }
  1065.         break;
  1066.     case WM_ERASEBKGND:
  1067.         if ( (pWnd=CRTWndMenu::FromHandle (hWnd)) != NULL )
  1068.         {
  1069.             pWnd->OnEraseBkgnd();
  1070.         }
  1071.         break;
  1072.     case WM_PRINT:
  1073.         {
  1074.             BYTE nCheck = CRTMenuItem::ms_nCheck;
  1075.             LRESULT lResult = CallWindowProc (oldWndProc, hWnd, uMsg, wParam, lParam);
  1076.             bool bOwnerDrawnItems = nCheck != CRTMenuItem::ms_nCheck;
  1077.             if ( (pWnd=CRTWndMenu::FromHandle (hWnd)) != NULL )
  1078.             {
  1079.                 pWnd->OnPrint (CDC::FromHandle ((HDC)wParam), bOwnerDrawnItems);
  1080.             }
  1081.             return lResult;
  1082.         }
  1083.     case WM_NCPAINT:
  1084.         if ( (pWnd=CRTWndMenu::FromHandle (hWnd)) != NULL )
  1085.         {
  1086.             pWnd->OnNcPaint();
  1087.             return 0;
  1088.         }
  1089.         break;
  1090.     case WM_SHOWWINDOW:
  1091.         if ( (pWnd=CRTWndMenu::FromHandle (hWnd)) != NULL )
  1092.         {
  1093.             pWnd->OnShowWindow (wParam != 0);
  1094.         }
  1095.         break;
  1096.     case WM_NCDESTROY:
  1097.         if ( (pWnd=CRTWndMenu::FromHandle (hWnd)) != NULL )
  1098.         {
  1099.             pWnd->OnNcDestroy();
  1100.         }
  1101.         break;
  1102.     }
  1103.     return CallWindowProc (oldWndProc, hWnd, uMsg, wParam, lParam);
  1104. }