Click here to Skip to main content
15,885,278 members
Articles / Desktop Programming / WTL
Article

CMenuXP - The OfficeXP menu (WTL version)

Rate me:
Please Sign up or sign in to vote.
4.76/5 (8 votes)
19 Mar 2002CPOL 187.9K   2.9K   40   36
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)


Written By
Web Developer CSC
France France
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.

Comments and Discussions

 
GeneralRe: A Menu is a Window,we can make it flat! Pin
11-May-02 19:32
suss11-May-02 19:32 
GeneralRe: A Menu is a Window,we can make it flat! Pin
Bjarke Viksoe29-Mar-02 1:12
Bjarke Viksoe29-Mar-02 1:12 
GeneralRe: A Menu is a Window,we can make it flat! Pin
MaTrIX2k22-May-02 17:52
MaTrIX2k22-May-02 17:52 
GeneralRe: A Menu is a Window,we can make it flat! Pin
Bjarke Viksoe5-May-02 7:32
Bjarke Viksoe5-May-02 7:32 
GeneralRe: A Menu is a Window,we can make it flat! Pin
MaTrIX2k25-May-02 12:14
MaTrIX2k25-May-02 12:14 
GeneralRe: A Menu is a Window,we can make it flat! Pin
Ernest Laurentin6-Feb-03 18:25
Ernest Laurentin6-Feb-03 18:25 
GeneralLittle Question Pin
Ramon Casellas19-Mar-02 21:25
Ramon Casellas19-Mar-02 21:25 
GeneralMerci Pin
Ramon Casellas19-Mar-02 21:24
Ramon Casellas19-Mar-02 21:24 
Thank you very much. I hope that the new release of WTL does not break your code Wink | ;)

Regards,
R.

GeneralRe: Merci Pin
Laurent Kempé19-Mar-02 21:49
Laurent Kempé19-Mar-02 21:49 
Generalcontext menu Pin
Igor Vigdorchik19-Mar-02 11:29
Igor Vigdorchik19-Mar-02 11:29 

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

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