Click here to Skip to main content
Licence CPOL
First Posted 18 Mar 2002
Views 150,929
Bookmarked 36 times

CMenuXP - The OfficeXP menu (WTL version)

By | 19 Mar 2002 | Article
Ownerdrawn menu with the OfficeXP look (WTL version)

Sample Image - MenuXP (WTL).gif

Introduction

This is the WTL version of the Ownerdrawn menu with the Office XP look.
With this version, the menubar is a MS ReBar so I have customized its drawing too.

Implementation

All the interested code is in the CCommandBarCtrlImplXP class :
template <class T, class TBase = CCommandBarCtrlBase, 
          class TWinTraits = CControlWinTraits>
class ATL_NO_VTABLE CCommandBarCtrlImplXP 
          : public CCommandBarCtrlImpl< T, TBase, TWinTraits >
{
public:
    DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName())

// Message map and handlers
    typedef CCommandBarCtrlImplXP< T, TBase, TWinTraits > thisClass;
    typedef CCommandBarCtrlImpl< T, TBase, TWinTraits >   baseClass;
    BEGIN_MSG_MAP(CCommandBarCtrlXP)
        CHAIN_MSG_MAP(baseClass)
    ALT_MSG_MAP(1)      // Parent window messages
        NOTIFY_CODE_HANDLER(NM_CUSTOMDRAW, OnCustomDraw)
        CHAIN_MSG_MAP_ALT(baseClass,1)
    ALT_MSG_MAP(2)        // MDI client window messages
        CHAIN_MSG_MAP_ALT(baseClass,2)
    ALT_MSG_MAP(3)        // Message hook messages
        CHAIN_MSG_MAP_ALT(baseClass,3)

    END_MSG_MAP()

    LRESULT OnCustomDraw (int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
    {
        TCHAR sClass[128];

        GetClassName (pnmh->hwndFrom, sClass, 128);

        if ( _tcscmp (sClass, _T("WTL_CommandBarXP")) )
        {
            return CDRF_DODEFAULT;
        }
        NMCUSTOMDRAW* pCustomDraw = (NMCUSTOMDRAW*)pnmh;

        if ( pCustomDraw->dwDrawStage == CDDS_PREPAINT )
        {
            // Request prepaint notifications for each item
            return CDRF_NOTIFYITEMDRAW;
        }
        if ( pCustomDraw->dwDrawStage == CDDS_ITEMPREPAINT )
        {
            CDCHandle cDC (pCustomDraw->hdc);
            CRect rc = pCustomDraw->rc;
            TCHAR sBtnText[128];

            ::SendMessage (pnmh->hwndFrom, TB_GETBUTTONTEXT, 
                               pCustomDraw->dwItemSpec, (LPARAM)sBtnText);

            if ( pCustomDraw->uItemState & CDIS_HOT )
            {
                COLORREF crHighLight = ::GetSysColor (COLOR_HIGHLIGHT);
                CPenDC pen (cDC, crHighLight);
                CBrushDC brush (cDC, (pCustomDraw->uItemState & CDIS_SELECTED)? 
                                        HLS_TRANSFORM (crHighLight, +50, -50) : 
                                        HLS_TRANSFORM (crHighLight, +70, -57));

                cDC.Rectangle (rc);
                cDC.SetTextColor ((pCustomDraw->uItemState & CDIS_SELECTED)? 
                                       ::GetSysColor (COLOR_HIGHLIGHTTEXT) : 
                                       RGB(0,0,0));
            }
            else
            {
                cDC.FillSolidRect (rc, HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), 
                                   +20, 0));
                cDC.SetTextColor (::GetSysColor (m_bParentActive ? COLOR_BTNTEXT :
                                                 COLOR_3DSHADOW));
            }
            cDC.SetBkMode (TRANSPARENT);
            cDC.SelectFont ((HFONT)GetStockObject (DEFAULT_GUI_FONT));
            cDC.DrawText (sBtnText, _tcslen (sBtnText), rc, 
                          DT_CENTER|DT_VCENTER|DT_SINGLELINE);

            return CDRF_SKIPDEFAULT;
        }
        bHandled = FALSE;

        return CDRF_DODEFAULT;
    }

#define IMGPADDING 6
#define TEXTPADDING 8

// From <winuser.h>
#define OBM_CHECK 32760

    void DrawItem (LPDRAWITEMSTRUCT lpDrawItemStruct)
    {
        _MenuItemData* pmd = (_MenuItemData*)lpDrawItemStruct->itemData;
        CDCHandle dc = lpDrawItemStruct->hDC;
        const RECT& rcItem = lpDrawItemStruct->rcItem;
        LPCRECT pRect = &rcItem;
        BOOL bDisabled = lpDrawItemStruct->itemState & ODS_GRAYED;
        BOOL bSelected = lpDrawItemStruct->itemState & ODS_SELECTED;
        BOOL bChecked = lpDrawItemStruct->itemState & ODS_CHECKED;
        COLORREF crBackImg = CLR_NONE;
        CDCHandle* pDC = &dc; 

        if ( bSelected )
        {
            COLORREF crHighLight = ::GetSysColor (COLOR_HIGHLIGHT);
            CPenDC pen (*pDC, crHighLight);
            CBrushDC brush (*pDC, crBackImg = bDisabled ? 
                            HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), +73, 0) : 
                            HLS_TRANSFORM (crHighLight, +70, -57));

            pDC->Rectangle (pRect);
        }
        else
        {
            CRect rc (pRect);

            rc.right = m_szBitmap.cx+IMGPADDING;
            pDC->FillSolidRect (rc, 
                   crBackImg = HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), +20, 0));
            rc.left = rc.right;
            rc.right = pRect->right;
            pDC->FillSolidRect (rc, 
                              HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), +75, 0));
        }
        if ( pmd->fType & MFT_SEPARATOR )
        {
            CPenDC pen (*pDC, HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), -18, 0));

            pDC->MoveTo (pRect->left+m_szBitmap.cx+IMGPADDING+TEXTPADDING,  
                         (pRect->top+pRect->bottom)/2);
            pDC->LineTo (pRect->right-1, (pRect->top+pRect->bottom)/2);
        }
        else
        {
            CRect rc (pRect);
            CString sCaption = pmd->lpstrText;
            int nTab = sCaption.Find ('\t');

            if ( nTab >= 0 )
            {
                sCaption = sCaption.Left (nTab);
            }
            pDC->SetTextColor (bDisabled ? HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), 
                                           -18, 0) : ::GetSysColor (COLOR_MENUTEXT));
            pDC->SetBkMode (TRANSPARENT);

            CBoldDC bold (*pDC, (lpDrawItemStruct->itemState & ODS_DEFAULT) != 0);

            rc.left = m_szBitmap.cx+IMGPADDING+TEXTPADDING;
            pDC->DrawText (sCaption, sCaption.GetLength(), rc, 
                           DT_SINGLELINE|DT_VCENTER|DT_LEFT);

            if ( nTab >= 0 )
            {    
                rc.right -= TEXTPADDING+4;
                pDC->DrawText (pmd->lpstrText+nTab+1, _tcslen (pmd->lpstrText+nTab+1), 
                               rc, DT_SINGLELINE|DT_VCENTER|DT_RIGHT);
            }
            if ( bChecked  )
            {
                COLORREF crHighLight = ::GetSysColor (COLOR_HIGHLIGHT);
                CPenDC pen (*pDC, crHighLight);
                CBrushDC brush (*pDC, crBackImg = bDisabled ? 
                              HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), +73, 0) :
                                (bSelected ? HLS_TRANSFORM (crHighLight, +50, -50) : 
                                   HLS_TRANSFORM (crHighLight, +70, -57)));

                pDC->Rectangle (CRect (pRect->left+1, pRect->top+1, 
                                pRect->left+m_szButton.cx-2, pRect->bottom-1));
            }
            if ( m_hImageList != NULL && pmd->iButton >= 0 )
            {
                bool bOver = !bDisabled && bSelected;

                if ( bDisabled || (bSelected && !bChecked) )
                {
                    HICON hIcon = ImageList_ExtractIcon (NULL, m_hImageList, 
                                                         pmd->iButton);
                    CBrush brush;

                    brush.CreateSolidBrush (bOver ? 
                         HLS_TRANSFORM (::GetSysColor (COLOR_HIGHLIGHT), +50, -66) : 
                         HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), -27, 0));
                    pDC->DrawState (CPoint (pRect->left + ( bOver ? 4 : 3 ), 
                                    rc.top + ( bOver ? 5 : 4 )),
                                    CSize (m_szBitmap.cx, m_szBitmap.cx), hIcon, 
                                    DSS_MONO, brush);
                    DestroyIcon (hIcon);
                }
                if ( !bDisabled )
                {
                    ::ImageList_Draw (m_hImageList, pmd->iButton, pDC->m_hDC,
                                      pRect->left+( (bSelected && !bChecked) ?
                                      2 : 3 ), rc.top+( (bSelected && !bChecked) ? 
                                      3 : 4 ), ILD_TRANSPARENT);
                }
            }
            else if ( bChecked )
            {
                // Draw the check mark
                rc.left  = pRect->left+5;
                rc.right = rc.left + m_szBitmap.cx+IMGPADDING;
                pDC->SetBkColor (crBackImg);
                HBITMAP hBmp = LoadBitmap (NULL, MAKEINTRESOURCE(OBM_CHECK));
                pDC->DrawState (CPoint (rc.left,rc.top+3), CSize(rc.Size()), 
                                hBmp, DSS_NORMAL, (HBRUSH)NULL);
                DeleteObject (hBmp);
            }
    }
    }
};


For the MFC version, have a look here.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Jean-Michel LE FOL

Web Developer
CSC
France France

Member

Jean-Michel LE FOL is a GraphTalk product architect.
GraphTalk is a set of products which cover the whole scope of the development process. GraphTalk is used by the main insurance compagnies over the world.
The development team is currently based in France near Paris.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
GeneralDemo doesn't work in WTL80 Pinmembertestano6:43 20 Jul '07  
NewsTrue color bmp popup menu example [modified] PinmemberVC Spark22:15 9 Apr '07  
Generalwork in Release Mode, but not Debug Mode Pinmembergankh3:41 8 Jan '06  
QuestionHow can this be used in a context menu? PinmemberAnna-Jayne Metcalfe3:23 31 Aug '04  
AnswerRe: How can this be used in a context menu? PinmemberIgor Vigdorchik7:24 13 Mar '06  
GeneralRe: How can this be used in a context menu? PinmemberAnna-Jayne Metcalfe7:59 13 Mar '06  
GeneralRe: How can this be used in a context menu? PinmemberIgor Vigdorchik8:31 13 Mar '06  
GeneralRe: How can this be used in a context menu? PinmemberAnna-Jayne Metcalfe8:43 13 Mar '06  
GeneralRe: How can this be used in a context menu? PinmemberIgor Vigdorchik8:54 13 Mar '06  
Generalthere is a little bug~ Pinmemberkimdoyoung19:46 5 Apr '04  
GeneralRelease Mode Failure PinsussKen Hester13:29 12 Dec '03  
GeneralMenu Appears transparent first time PinmemberBilal Ahmed14:07 17 Aug '03  
GeneralWTL XP Look in ATL COM Composite Control PinmemberSchauhan21:15 12 May '03  
QuestionHow to change ccommmandbarctrl's backcolor? Pinmembermarco.song4:59 29 Dec '02  
GeneralProblem on WTL7 PinmemberPetr Pavlik2:03 10 May '02  
GeneralRe: Problem on WTL7 PinmemberBozoLeClown7:28 22 Nov '02  
GeneralRe: Problem on WTL7 PinmemberErikLindemann0:58 31 May '05  
GeneralDoes not work! PinmemberYazan Diranieh1:22 28 Mar '02  
GeneralRe: Does not work! PinmemberJean-Michel LE FOL3:34 28 Mar '02  
GeneralRe: Does not work! PinmemberRamon Casellas6:50 28 Mar '02  
GeneralSample code does not compile PinmemberYazan Diranieh0:47 27 Mar '02  
GeneralRe: Sample code does not compile PinmemberRamon Casellas1:19 27 Mar '02  
GeneralA Menu is a Window,we can make it flat! Pinmembertomer dror9:57 20 Mar '02  
GeneralRe: A Menu is a Window,we can make it flat! PinmemberRamon Casellas11:28 20 Mar '02  
GeneralRe: A Menu is a Window,we can make it flat! PinmemberCosmoS2k16:27 28 Mar '02  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web02 | 2.5.120517.1 | Last Updated 20 Mar 2002
Article Copyright 2002 by Jean-Michel LE FOL
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid