CButtonST使用技术,CButtonST类简要介绍使用办法

by admin on 2019年8月26日
#include "stdafx.h"
#include "BtnST.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CButtonST

// Mask for control's type
#define BS_TYPEMASK SS_TYPEMASK

CButtonST::CButtonST()
{
    m_bIsPressed        = FALSE;
    m_bIsFocused        = FALSE;
    m_bIsDisabled        = FALSE;
    m_bMouseOnButton    = FALSE;

    FreeResources(FALSE);

    // Default type is "flat" button
    m_bIsFlat = TRUE;
    // Button will be tracked also if when the window is inactive (like Internet Explorer)
    m_bAlwaysTrack = TRUE;

    // By default draw border in "flat" button 
    m_bDrawBorder = TRUE; 

    // By default icon is aligned horizontally
    m_byAlign = ST_ALIGN_HORIZ; 

    // By default, for "flat" button, don't draw the focus rect
    m_bDrawFlatFocus = FALSE;

    // By default the button is not the default button
    m_bIsDefault = FALSE;
    // Invalid value, since type still unknown
    m_nTypeStyle = BS_TYPEMASK;

    // By default the button is not a checkbox
    m_bIsCheckBox = FALSE;
    m_nCheck = 0;

    // Set default colors
    SetDefaultColors(FALSE);

    // No tooltip created
    m_ToolTip.m_hWnd = NULL;

    // Do not draw as a transparent button
    m_bDrawTransparent = FALSE;
    m_pbmpOldBk = NULL;

    // No URL defined
    SetURL(NULL);

    // No cursor defined
    m_hCursor = NULL;

    // No associated menu
#ifndef    BTNST_USE_BCMENU
    m_hMenu = NULL;
#endif
    m_hParentWndMenu = NULL;
    m_bMenuDisplayed = FALSE;

    m_bShowDisabledBitmap = TRUE;
} // End of CButtonST

CButtonST::~CButtonST()
{
    // Restore old bitmap (if any)
    if (m_dcBk.m_hDC && m_pbmpOldBk)
    {
        m_dcBk.SelectObject(m_pbmpOldBk);
    } // if

    FreeResources();

    // Destroy the cursor (if any)
    if (m_hCursor) ::DestroyCursor(m_hCursor);

    // Destroy the menu (if any)
#ifdef    BTNST_USE_BCMENU
    if (m_menuPopup.m_hMenu)    m_menuPopup.DestroyMenu();
#else
    if (m_hMenu)    ::DestroyMenu(m_hMenu);
#endif
} // End of ~CButtonST

BEGIN_MESSAGE_MAP(CButtonST, CButton)
    //{{AFX_MSG_MAP(CButtonST)
    ON_WM_SETCURSOR()
    ON_WM_KILLFOCUS()
    ON_WM_MOUSEMOVE()
    ON_WM_SYSCOLORCHANGE()
    ON_CONTROL_REFLECT_EX(BN_CLICKED, OnClicked)
    ON_WM_ACTIVATE()
    ON_WM_ENABLE()
    ON_WM_CANCELMODE()
    ON_WM_GETDLGCODE()
    ON_WM_CTLCOLOR_REFLECT()
    //}}AFX_MSG_MAP
#ifdef    BTNST_USE_BCMENU
    ON_WM_MENUCHAR()
    ON_WM_MEASUREITEM()
#endif

    ON_MESSAGE(BM_SETSTYLE, OnSetStyle)
    ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)
    ON_MESSAGE(BM_SETCHECK, OnSetCheck)
    ON_MESSAGE(BM_GETCHECK, OnGetCheck)
END_MESSAGE_MAP()

void CButtonST::FreeResources(BOOL bCheckForNULL)
{
    if (bCheckForNULL)
    {
        // Destroy icons
        // Note: the following two lines MUST be here! even if
        // BoundChecker says they are unnecessary!
        if (m_csIcons[0].hIcon)    ::DestroyIcon(m_csIcons[0].hIcon);
        if (m_csIcons[1].hIcon)    ::DestroyIcon(m_csIcons[1].hIcon);

        // Destroy bitmaps
        if (m_csBitmaps[0].hBitmap)    ::DeleteObject(m_csBitmaps[0].hBitmap);
        if (m_csBitmaps[1].hBitmap)    ::DeleteObject(m_csBitmaps[1].hBitmap);

        // Destroy mask bitmaps
        if (m_csBitmaps[0].hMask)    ::DeleteObject(m_csBitmaps[0].hMask);
        if (m_csBitmaps[1].hMask)    ::DeleteObject(m_csBitmaps[1].hMask);
    } // if

    ::ZeroMemory(&m_csIcons, sizeof(m_csIcons));
    ::ZeroMemory(&m_csBitmaps, sizeof(m_csBitmaps));
} // End of FreeResources

void CButtonST::PreSubclassWindow() 
{
    UINT nBS;

    nBS = GetButtonStyle();

    // Set initial control type
    m_nTypeStyle = nBS & BS_TYPEMASK;

    // Check if this is a checkbox
    if (nBS & BS_CHECKBOX) m_bIsCheckBox = TRUE;

    // Set initial default state flag
    if (m_nTypeStyle == BS_DEFPUSHBUTTON)
    {
        // Set default state for a default button
        m_bIsDefault = TRUE;

        // Adjust style for default button
        m_nTypeStyle = BS_PUSHBUTTON;
    } // If

    // You should not set the Owner Draw before this call
    // (don't use the resource editor "Owner Draw" or
    // ModifyStyle(0, BS_OWNERDRAW) before calling PreSubclassWindow() )
    ASSERT(m_nTypeStyle != BS_OWNERDRAW);

    // Switch to owner-draw
    ModifyStyle(BS_TYPEMASK, BS_OWNERDRAW, SWP_FRAMECHANGED);

    CButton::PreSubclassWindow();
} // End of PreSubclassWindow

UINT CButtonST::OnGetDlgCode() 
{
    UINT nCode = CButton::OnGetDlgCode();

    // Tell the system if we want default state handling
    // (losing default state always allowed)
    nCode |= (m_bIsDefault ? DLGC_DEFPUSHBUTTON : DLGC_UNDEFPUSHBUTTON);

    return nCode;
} // End of OnGetDlgCode

BOOL CButtonST::PreTranslateMessage(MSG* pMsg) 
{
    InitToolTip();
    m_ToolTip.RelayEvent(pMsg);

    return CButton::PreTranslateMessage(pMsg);
} // End of PreTranslateMessage

LRESULT CButtonST::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
{
    if (message == WM_LBUTTONDBLCLK)
    {
        message = WM_LBUTTONDOWN;
    } // if
    /*
    switch (message)
    {
        case WM_LBUTTONDBLCLK:
            message = WM_LBUTTONDOWN;
            break;
        case WM_MOVE:
            CRect rect;

            GetClientRect(&rect);
            if (::IsWindow(m_ToolTip.m_hWnd))
            {
                if (m_ToolTip.GetToolCount() != 0)
                    m_ToolTip.SetToolRect(this, 1, &rect);
            } // if
            break;
    } // switch
    */
    return CButton::DefWindowProc(message, wParam, lParam);
} // End of DefWindowProc

HBRUSH CButtonST::CtlColor(CDC* pDC, UINT nCtlColor) 
{
    return (HBRUSH)::GetStockObject(NULL_BRUSH); 
} // End of CtlColor

void CButtonST::OnSysColorChange() 
{
    CButton::OnSysColorChange();

    m_dcBk.DeleteDC();
    m_bmpBk.DeleteObject();    
} // End of OnSysColorChange

LRESULT CButtonST::OnSetStyle(WPARAM wParam, LPARAM lParam)
{
    UINT nNewType = (wParam & BS_TYPEMASK);

    // Update default state flag
    if (nNewType == BS_DEFPUSHBUTTON)
    {
        m_bIsDefault = TRUE;
    } // if
    else if (nNewType == BS_PUSHBUTTON)
    {
        // Losing default state always allowed
        m_bIsDefault = FALSE;
    } // if

    // Can't change control type after owner-draw is set.
    // Let the system process changes to other style bits
    // and redrawing, while keeping owner-draw style
    return DefWindowProc(BM_SETSTYLE,
        (wParam & ~BS_TYPEMASK) | BS_OWNERDRAW, lParam);
} // End of OnSetStyle

LRESULT CButtonST::OnSetCheck(WPARAM wParam, LPARAM lParam)
{
    ASSERT(m_bIsCheckBox);

    switch (wParam)
    {
        case BST_CHECKED:
        case BST_INDETERMINATE:    // Indeterminate state is handled like checked state
            SetCheck(1);
            break;
        default:
            SetCheck(0);
            break;
    } // switch

    return 0;
} // End of OnSetCheck

LRESULT CButtonST::OnGetCheck(WPARAM wParam, LPARAM lParam)
{
    ASSERT(m_bIsCheckBox);
    return GetCheck();
} // End of OnGetCheck

#ifdef    BTNST_USE_BCMENU
LRESULT CButtonST::OnMenuChar(UINT nChar, UINT nFlags, CMenu* pMenu) 
{
    LRESULT lResult;
    if (BCMenu::IsMenu(pMenu))
        lResult = BCMenu::FindKeyboardShortcut(nChar, nFlags, pMenu);
    else
        lResult = CButton::OnMenuChar(nChar, nFlags, pMenu);
    return lResult;
} // End of OnMenuChar
#endif

#ifdef    BTNST_USE_BCMENU
void CButtonST::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct) 
{
    BOOL bSetFlag = FALSE;
    if (lpMeasureItemStruct->CtlType == ODT_MENU)
    {
        if (IsMenu((HMENU)lpMeasureItemStruct->itemID) && BCMenu::IsMenu((HMENU)lpMeasureItemStruct->itemID))
        {
            m_menuPopup.MeasureItem(lpMeasureItemStruct);
            bSetFlag = TRUE;
        } // if
    } // if
    if (!bSetFlag) CButton::OnMeasureItem(nIDCtl, lpMeasureItemStruct);
} // End of OnMeasureItem
#endif

void CButtonST::OnEnable(BOOL bEnable) 
{
    CButton::OnEnable(bEnable);

    if (bEnable == FALSE)    
    {
        CWnd*    pWnd = GetParent()->GetNextDlgTabItem(this);
        if (pWnd)
            pWnd->SetFocus();
        else
            GetParent()->SetFocus();

        CancelHover();
    } // if
} // End of OnEnable

void CButtonST::OnKillFocus(CWnd * pNewWnd)
{
    CButton::OnKillFocus(pNewWnd);
    CancelHover();
} // End of OnKillFocus

void CButtonST::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) 
{
    CButton::OnActivate(nState, pWndOther, bMinimized);
    if (nState == WA_INACTIVE)    CancelHover();
} // End of OnActivate

void CButtonST::OnCancelMode() 
{
    CButton::OnCancelMode();
    CancelHover();
} // End of OnCancelMode

BOOL CButtonST::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
{
    // If a cursor was specified then use it!
    if (m_hCursor != NULL)
    {
        ::SetCursor(m_hCursor);
        return TRUE;
    } // if

    return CButton::OnSetCursor(pWnd, nHitTest, message);
} // End of OnSetCursor

void CButtonST::CancelHover()
{
    // Only for flat buttons
    if (m_bIsFlat)
    {
        if (m_bMouseOnButton)
        {
            m_bMouseOnButton = FALSE;
            Invalidate();
        } // if
    } // if
} // End of CancelHover

void CButtonST::OnMouseMove(UINT nFlags, CPoint point)
{
    CWnd*                wndUnderMouse = NULL;
    CWnd*                wndActive = this;
    TRACKMOUSEEVENT        csTME;

    CButton::OnMouseMove(nFlags, point);

    ClientToScreen(&point);
    wndUnderMouse = WindowFromPoint(point);

    // If the mouse enter the button with the left button pressed then do nothing
    if (nFlags & MK_LBUTTON && m_bMouseOnButton == FALSE) return;

    // If our button is not flat then do nothing
    if (m_bIsFlat == FALSE) return;

    if (m_bAlwaysTrack == FALSE)    wndActive = GetActiveWindow();

    if (wndUnderMouse && wndUnderMouse->m_hWnd == m_hWnd && wndActive)
    {
        if (!m_bMouseOnButton)
        {
            m_bMouseOnButton = TRUE;

            Invalidate();

            csTME.cbSize = sizeof(csTME);
            csTME.dwFlags = TME_LEAVE;
            csTME.hwndTrack = m_hWnd;
            ::_TrackMouseEvent(&csTME);
        } // if
    } else CancelHover();
} // End of OnMouseMove

// Handler for WM_MOUSELEAVE
LRESULT CButtonST::OnMouseLeave(WPARAM wParam, LPARAM lParam)
{
    CancelHover();
    return 0;
} // End of OnMouseLeave

BOOL CButtonST::OnClicked() 
{    
    SetFocus();

    if (m_bIsCheckBox)
    {
        m_nCheck = !m_nCheck;
        Invalidate();
    } // if
    else
    {
        // Handle the menu (if any)
#ifdef    BTNST_USE_BCMENU
        if (m_menuPopup.m_hMenu)
#else
        if (m_hMenu)
#endif
        {
            CRect    rWnd;
            GetWindowRect(rWnd);

            m_bMenuDisplayed = TRUE;
            Invalidate();

#ifdef    BTNST_USE_BCMENU
            BCMenu *psub = (BCMenu*)m_menuPopup.GetSubMenu(0);
            DWORD dwRetValue = psub->TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_NONOTIFY | TPM_RETURNCMD, rWnd.left, rWnd.bottom, this, NULL);
#else
            HMENU hSubMenu = ::GetSubMenu(m_hMenu, 0);
            //DWORD dwRetValue = ::TrackPopupMenuEx(hSubMenu, TPM_LEFTALIGN | TPM_LEFTBUTTON, rWnd.left, rWnd.bottom, m_hParentWndMenu, NULL);
            DWORD dwRetValue = ::TrackPopupMenuEx(hSubMenu, TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_NONOTIFY | TPM_RETURNCMD, rWnd.left, rWnd.bottom, m_hParentWndMenu, NULL);
#endif

            m_bMenuDisplayed = FALSE;
            Invalidate();

            if (dwRetValue)
                ::PostMessage(m_hParentWndMenu, WM_COMMAND, MAKEWPARAM(dwRetValue, 0), (LPARAM)NULL);
        } // if
        else
        {
            // Handle the URL (if any)
            if (_tcslen(m_szURL) > 0)
            {
                SHELLEXECUTEINFO    csSEI;

                memset(&csSEI, 0, sizeof(csSEI));
                csSEI.cbSize = sizeof(SHELLEXECUTEINFO);
                csSEI.fMask = SEE_MASK_FLAG_NO_UI;
                csSEI.lpVerb = _T("open");
                csSEI.lpFile = m_szURL;
                csSEI.nShow = SW_SHOWMAXIMIZED;
                ::ShellExecuteEx(&csSEI);
            } // if
        } // else
    } // else

    return FALSE;
} // End of OnClicked

void CButtonST::DrawItem(LPDRAWITEMSTRUCT lpDIS)
{

    CDC*    pDC = CDC::FromHandle(lpDIS->hDC);
    CPen*    pOldPen;

    // Checkbox?
    if (m_bIsCheckBox)
    {
        m_bIsPressed  =  (lpDIS->itemState & ODS_SELECTED) || (m_nCheck != 0);
    } // if
    else    // Normal button OR other button style ...
    {
        m_bIsPressed = (lpDIS->itemState & ODS_SELECTED);

        // If there is a menu and it's displayed, draw the button as pressed
        if (
#ifdef    BTNST_USE_BCMENU
            m_menuPopup.m_hMenu 
#else
            m_hMenu 
#endif
            && m_bMenuDisplayed)    m_bIsPressed = TRUE;
    } // else

    m_bIsFocused  = (lpDIS->itemState & ODS_FOCUS);
    m_bIsDisabled = (lpDIS->itemState & ODS_DISABLED);

    CRect itemRect = lpDIS->rcItem;

    pDC->SetBkMode(TRANSPARENT);

    if (m_bIsFlat == FALSE)
    {
        if (m_bIsFocused || m_bIsDefault)
        {
            CBrush br(RGB(0,0,0));  
            pDC->FrameRect(&itemRect, &br);
            itemRect.DeflateRect(1, 1);
        } // if
    } // if

    // Prepare draw... paint button background

    // Draw transparent?
    if (m_bDrawTransparent)
        PaintBk(pDC);
    else
        OnDrawBackground(pDC, &itemRect);

    // Draw pressed button
    if (m_bIsPressed)
    {
        if (m_bIsFlat)
        {
            if (m_bDrawBorder)
                OnDrawBorder(pDC, &itemRect);
        }
        else    
        {
            CBrush brBtnShadow(GetSysColor(COLOR_BTNSHADOW));
            pDC->FrameRect(&itemRect, &brBtnShadow);
        }
    }
    else // ...else draw non pressed button
    {
        CPen penBtnHiLight(PS_SOLID, 0, GetSysColor(COLOR_BTNHILIGHT)); // White
        CPen pen3DLight(PS_SOLID, 0, GetSysColor(COLOR_3DLIGHT));       // Light gray
        CPen penBtnShadow(PS_SOLID, 0, GetSysColor(COLOR_BTNSHADOW));   // Dark gray
        CPen pen3DDKShadow(PS_SOLID, 0, GetSysColor(COLOR_3DDKSHADOW)); // Black

        if (m_bIsFlat)
        {
            if (m_bMouseOnButton && m_bDrawBorder)
                OnDrawBorder(pDC, &itemRect);
        }
        else
        {
            // Draw top-left borders
            // White line
            pOldPen = pDC->SelectObject(&penBtnHiLight);
            pDC->MoveTo(itemRect.left, itemRect.bottom-1);
            pDC->LineTo(itemRect.left, itemRect.top);
            pDC->LineTo(itemRect.right, itemRect.top);
            // Light gray line
            pDC->SelectObject(pen3DLight);
            pDC->MoveTo(itemRect.left+1, itemRect.bottom-1);
            pDC->LineTo(itemRect.left+1, itemRect.top+1);
            pDC->LineTo(itemRect.right, itemRect.top+1);
            // Draw bottom-right borders
            // Black line
            pDC->SelectObject(pen3DDKShadow);
            pDC->MoveTo(itemRect.left, itemRect.bottom-1);
            pDC->LineTo(itemRect.right-1, itemRect.bottom-1);
            pDC->LineTo(itemRect.right-1, itemRect.top-1);
            // Dark gray line
            pDC->SelectObject(penBtnShadow);
            pDC->MoveTo(itemRect.left+1, itemRect.bottom-2);
            pDC->LineTo(itemRect.right-2, itemRect.bottom-2);
            pDC->LineTo(itemRect.right-2, itemRect.top);
            //
            pDC->SelectObject(pOldPen);
        } // else
    } // else

    // Read the button's title
    CString sTitle;
    GetWindowText(sTitle);

    CRect captionRect = lpDIS->rcItem;

    // Draw the icon
    if (m_csIcons[0].hIcon)
    {
        DrawTheIcon(pDC, !sTitle.IsEmpty(), &lpDIS->rcItem, &captionRect, m_bIsPressed, m_bIsDisabled);
    } // if

    if (m_csBitmaps[0].hBitmap)
    {
        pDC->SetBkColor(RGB(255,255,255));
        DrawTheBitmap(pDC, !sTitle.IsEmpty(), &lpDIS->rcItem, &captionRect, m_bIsPressed, m_bIsDisabled);
    } // if

    // Write the button title (if any)
    if (sTitle.IsEmpty() == FALSE)
    {
        // Draw the button's title
        // If button is pressed then "press" title also
        if (m_bIsPressed && m_bIsCheckBox == FALSE)
            captionRect.OffsetRect(1, 1);

        // ONLY FOR DEBUG 
        //CBrush brBtnShadow(RGB(255, 0, 0));
        //pDC->FrameRect(&captionRect, &brBtnShadow);

        // Center text
        CRect centerRect = captionRect;
        pDC->DrawText(sTitle, -1, captionRect, DT_WORDBREAK | DT_CENTER | DT_CALCRECT);
        captionRect.OffsetRect((centerRect.Width() - captionRect.Width())/2, (centerRect.Height() - captionRect.Height())/2);
        /* RFU
        captionRect.OffsetRect(0, (centerRect.Height() - captionRect.Height())/2);
        captionRect.OffsetRect((centerRect.Width() - captionRect.Width())-4, (centerRect.Height() - captionRect.Height())/2);
        */

        pDC->SetBkMode(TRANSPARENT);
        /*
        pDC->DrawState(captionRect.TopLeft(), captionRect.Size(), (LPCTSTR)sTitle, (bIsDisabled ? DSS_DISABLED : DSS_NORMAL), 
                        TRUE, 0, (CBrush*)NULL);
        */
        if (m_bIsDisabled)
        {
            captionRect.OffsetRect(1, 1);
            pDC->SetTextColor(::GetSysColor(COLOR_3DHILIGHT));
            pDC->DrawText(sTitle, -1, captionRect, DT_WORDBREAK | DT_CENTER);
            captionRect.OffsetRect(-1, -1);
            pDC->SetTextColor(::GetSysColor(COLOR_3DSHADOW));
            pDC->DrawText(sTitle, -1, captionRect, DT_WORDBREAK | DT_CENTER);
        } // if
        else
        {
            if (m_bMouseOnButton || m_bIsPressed) 
            {
                pDC->SetTextColor(m_crColors[BTNST_COLOR_FG_IN]);
                pDC->SetBkColor(m_crColors[BTNST_COLOR_BK_IN]);
            } // if
            else 
            {
                pDC->SetTextColor(m_crColors[BTNST_COLOR_FG_OUT]);
                pDC->SetBkColor(m_crColors[BTNST_COLOR_BK_OUT]);
            } // else
            pDC->DrawText(sTitle, -1, captionRect, DT_WORDBREAK | DT_CENTER);
        } // if
    } // if

    if (m_bIsFlat == FALSE || (m_bIsFlat && m_bDrawFlatFocus))
    {
        // Draw the focus rect
        if (m_bIsFocused)
        {
            CRect focusRect = itemRect;
            focusRect.DeflateRect(3, 3);
            pDC->DrawFocusRect(&focusRect);
        } // if
    } // if
} // End of DrawItem

void CButtonST::PaintBk(CDC* pDC)
{
    CClientDC clDC(GetParent());
    CRect rect;
    CRect rect1;

    GetClientRect(rect);

    GetWindowRect(rect1);
    GetParent()->ScreenToClient(rect1);

    if (m_dcBk.m_hDC == NULL)
    {
        m_dcBk.CreateCompatibleDC(&clDC);
        m_bmpBk.CreateCompatibleBitmap(&clDC, rect.Width(), rect.Height());
        m_pbmpOldBk = m_dcBk.SelectObject(&m_bmpBk);
        m_dcBk.BitBlt(0, 0, rect.Width(), rect.Height(), &clDC, rect1.left, rect1.top, SRCCOPY);
    } // if

    pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &m_dcBk, 0, 0, SRCCOPY);
} // End of PaintBk

HBITMAP CButtonST::CreateBitmapMask(HBITMAP hSourceBitmap, DWORD dwWidth, DWORD dwHeight, COLORREF crTransColor)
{
    HBITMAP        hMask        = NULL;
    HDC            hdcSrc        = NULL;
    HDC            hdcDest        = NULL;
    HBITMAP        hbmSrcT        = NULL;
    HBITMAP        hbmDestT    = NULL;
    COLORREF    crSaveBk;
    COLORREF    crSaveDestText;

    hMask = ::CreateBitmap(dwWidth, dwHeight, 1, 1, NULL);
    if (hMask == NULL)    return NULL;

    hdcSrc    = ::CreateCompatibleDC(NULL);
    hdcDest    = ::CreateCompatibleDC(NULL);

    hbmSrcT = (HBITMAP)::SelectObject(hdcSrc, hSourceBitmap);
    hbmDestT = (HBITMAP)::SelectObject(hdcDest, hMask);

    crSaveBk = ::SetBkColor(hdcSrc, crTransColor);

    ::BitBlt(hdcDest, 0, 0, dwWidth, dwHeight, hdcSrc, 0, 0, SRCCOPY);

    crSaveDestText = ::SetTextColor(hdcSrc, RGB(255, 255, 255));
    ::SetBkColor(hdcSrc,RGB(0, 0, 0));

    ::BitBlt(hdcSrc, 0, 0, dwWidth, dwHeight, hdcDest, 0, 0, SRCAND);

    SetTextColor(hdcDest, crSaveDestText);

    ::SetBkColor(hdcSrc, crSaveBk);
    ::SelectObject(hdcSrc, hbmSrcT);
    ::SelectObject(hdcDest, hbmDestT);

    ::DeleteDC(hdcSrc);
    ::DeleteDC(hdcDest);

    return hMask;
} // End of CreateBitmapMask

//
// Parameters:
//        [IN]    bHasTitle
//                TRUE if the button has a text
//        [IN]    rpItem
//                A pointer to a RECT structure indicating the allowed paint area
//        [IN/OUT]rpTitle
//                A pointer to a CRect object indicating the paint area reserved for the
//                text. This structure will be modified if necessary.
//        [IN]    bIsPressed
//                TRUE if the button is currently pressed
//        [IN]    dwWidth
//                Width of the image (icon or bitmap)
//        [IN]    dwHeight
//                Height of the image (icon or bitmap)
//        [OUT]    rpImage
//                A pointer to a CRect object that will receive the area available to the image
//
void CButtonST::PrepareImageRect(BOOL bHasTitle, RECT* rpItem, CRect* rpTitle, BOOL bIsPressed, DWORD dwWidth, DWORD dwHeight, CRect* rpImage)
{
    CRect rBtn;

    rpImage->CopyRect(rpItem);

    switch (m_byAlign)
    {
        case ST_ALIGN_HORIZ:
            if (bHasTitle == FALSE)
            {
                // Center image horizontally
                rpImage->left += ((rpImage->Width() - (long)dwWidth)/2);
            }
            else
            {
                // Image must be placed just inside the focus rect
                rpImage->left += 3;  
                rpTitle->left += dwWidth + 3;
            }
            // Center image vertically
            rpImage->top += ((rpImage->Height() - (long)dwHeight)/2);
            break;

        case ST_ALIGN_HORIZ_RIGHT:
            GetClientRect(&rBtn);
            if (bHasTitle == FALSE)
            {
                // Center image horizontally
                rpImage->left += ((rpImage->Width() - (long)dwWidth)/2);
            }
            else
            {
                // Image must be placed just inside the focus rect
                rpTitle->right = rpTitle->Width() - dwWidth - 3;
                rpTitle->left = 3;
                rpImage->left = rBtn.right - dwWidth - 3;
                // Center image vertically
                rpImage->top += ((rpImage->Height() - (long)dwHeight)/2);
            }
            break;

        case ST_ALIGN_VERT:
            // Center image horizontally
            rpImage->left += ((rpImage->Width() - (long)dwWidth)/2);
            if (bHasTitle == FALSE)
            {
                // Center image vertically
                rpImage->top += ((rpImage->Height() - (long)dwHeight)/2);           
            }
            else
            {
                rpImage->top = 3;
                rpTitle->top += dwHeight;
            }
            break;
    }

    // If button is pressed then press image also
    if (bIsPressed && m_bIsCheckBox == FALSE)
        rpImage->OffsetRect(1, 1);
} // End of PrepareImageRect

void CButtonST::DrawTheIcon(CDC* pDC, BOOL bHasTitle, RECT* rpItem, CRect* rpTitle, BOOL bIsPressed, BOOL bIsDisabled)
{
    BYTE        byIndex        = 0;

    // Select the icon to use
    if ((m_bIsCheckBox && bIsPressed) || (!m_bIsCheckBox && (bIsPressed || m_bMouseOnButton)))
        byIndex = 0;
    else
        byIndex = (m_csIcons[1].hIcon == NULL ? 0 : 1);

    CRect    rImage;
    PrepareImageRect(bHasTitle, rpItem, rpTitle, bIsPressed, m_csIcons[byIndex].dwWidth, m_csIcons[byIndex].dwHeight, &rImage);

    // Ole'!
    pDC->DrawState(    rImage.TopLeft(),
                    rImage.Size(), 
                    m_csIcons[byIndex].hIcon,
                    (bIsDisabled ? DSS_DISABLED : DSS_NORMAL), 
                    (CBrush*)NULL);
} // End of DrawTheIcon

void CButtonST::DrawTheBitmap(CDC* pDC, BOOL bHasTitle, RECT* rItem, CRect *rCaption, BOOL bIsPressed, BOOL bIsDisabled)
{
    HDC            hdcBmpMem    = NULL;
    HBITMAP        hbmOldBmp    = NULL;
    HDC            hdcMem        = NULL;
    HBITMAP        hbmT        = NULL;

    BYTE        byIndex        = 0;

    // Select the bitmap to use
    if ((m_bIsCheckBox && bIsPressed) || (!m_bIsCheckBox && (bIsPressed || m_bMouseOnButton)))
        byIndex = 0;
    else
        byIndex = (m_csBitmaps[1].hBitmap == NULL ? 0 : 1);

    CRect    rImage;
    PrepareImageRect(bHasTitle, rItem, rCaption, bIsPressed, m_csBitmaps[byIndex].dwWidth, m_csBitmaps[byIndex].dwHeight, &rImage);

    hdcBmpMem = ::CreateCompatibleDC(pDC->m_hDC);

    hbmOldBmp = (HBITMAP)::SelectObject(hdcBmpMem, m_csBitmaps[byIndex].hBitmap);

    hdcMem = ::CreateCompatibleDC(NULL);

    hbmT = (HBITMAP)::SelectObject(hdcMem, m_csBitmaps[byIndex].hMask);

    if (bIsDisabled && m_bShowDisabledBitmap)
    {
        HDC        hDC = NULL;
        HBITMAP    hBitmap = NULL;

        hDC = ::CreateCompatibleDC(pDC->m_hDC);
        hBitmap = ::CreateCompatibleBitmap(pDC->m_hDC, m_csBitmaps[byIndex].dwWidth, m_csBitmaps[byIndex].dwHeight);
        HBITMAP    hOldBmp2 = (HBITMAP)::SelectObject(hDC, hBitmap);

        RECT    rRect;
        rRect.left = 0;
        rRect.top = 0;
        rRect.right = rImage.right + 1;
        rRect.bottom = rImage.bottom + 1;
        ::FillRect(hDC, &rRect, (HBRUSH)RGB(255, 255, 255));

        COLORREF crOldColor = ::SetBkColor(hDC, RGB(255,255,255));

        ::BitBlt(hDC, 0, 0, m_csBitmaps[byIndex].dwWidth, m_csBitmaps[byIndex].dwHeight, hdcMem, 0, 0, SRCAND);
        ::BitBlt(hDC, 0, 0, m_csBitmaps[byIndex].dwWidth, m_csBitmaps[byIndex].dwHeight, hdcBmpMem, 0, 0, SRCPAINT);

        ::SetBkColor(hDC, crOldColor);
        ::SelectObject(hDC, hOldBmp2);
        ::DeleteDC(hDC);

        pDC->DrawState(    CPoint(rImage.left/*+1*/, rImage.top), 
                        CSize(m_csBitmaps[byIndex].dwWidth, m_csBitmaps[byIndex].dwHeight), 
                        hBitmap, DST_BITMAP | DSS_DISABLED);

        ::DeleteObject(hBitmap);
    } // if
    else
    {
        ::BitBlt(pDC->m_hDC, rImage.left, rImage.top, m_csBitmaps[byIndex].dwWidth, m_csBitmaps[byIndex].dwHeight, hdcMem, 0, 0, SRCAND);

        ::BitBlt(pDC->m_hDC, rImage.left, rImage.top, m_csBitmaps[byIndex].dwWidth, m_csBitmaps[byIndex].dwHeight, hdcBmpMem, 0, 0, SRCPAINT);
    } // else

    ::SelectObject(hdcMem, hbmT);
    ::DeleteDC(hdcMem);

    ::SelectObject(hdcBmpMem, hbmOldBmp);
    ::DeleteDC(hdcBmpMem);
} // End of DrawTheBitmap

// This function creates a grayscale icon starting from a given icon.
// The resulting icon will have the same size of the original one.
//
// Parameters:
//        [IN]    hIcon
//                Handle to the original icon.
//
// Return value:
//        If the function succeeds, the return value is the handle to the newly created
//        grayscale icon.
//        If the function fails, the return value is NULL.
//
HICON CButtonST::CreateGrayscaleIcon(HICON hIcon)
{
    HICON        hGrayIcon = NULL;
    HDC            hMainDC = NULL, hMemDC1 = NULL, hMemDC2 = NULL;
    BITMAP        bmp;
    HBITMAP        hOldBmp1 = NULL, hOldBmp2 = NULL;
    ICONINFO    csII, csGrayII;
    BOOL        bRetValue = FALSE;

    bRetValue = ::GetIconInfo(hIcon, &csII);
    if (bRetValue == FALSE)    return NULL;

    hMainDC = ::GetDC(m_hWnd);
    hMemDC1 = ::CreateCompatibleDC(hMainDC);
    hMemDC2 = ::CreateCompatibleDC(hMainDC);
    if (hMainDC == NULL || hMemDC1 == NULL || hMemDC2 == NULL)    return NULL;

    if (::GetObject(csII.hbmColor, sizeof(BITMAP), &bmp))
    {
        csGrayII.hbmColor = ::CreateBitmap(csII.xHotspot*2, csII.yHotspot*2, bmp.bmPlanes, bmp.bmBitsPixel, NULL);
        if (csGrayII.hbmColor)
        {
            hOldBmp1 = (HBITMAP)::SelectObject(hMemDC1, csII.hbmColor);
            hOldBmp2 = (HBITMAP)::SelectObject(hMemDC2, csGrayII.hbmColor);

            ::BitBlt(hMemDC2, 0, 0, csII.xHotspot*2, csII.yHotspot*2, hMemDC1, 0, 0, SRCCOPY);

            DWORD        dwLoopY = 0, dwLoopX = 0;
            COLORREF    crPixel = 0;
            BYTE        byNewPixel = 0;

            for (dwLoopY = 0; dwLoopY < csII.yHotspot*2; dwLoopY++)
            {
                for (dwLoopX = 0; dwLoopX < csII.xHotspot*2; dwLoopX++)
                {
                    crPixel = ::GetPixel(hMemDC2, dwLoopX, dwLoopY);

                    byNewPixel = (BYTE)((GetRValue(crPixel) * 0.299) + (GetGValue(crPixel) * 0.587) + (GetBValue(crPixel) * 0.114));
                    if (crPixel)    ::SetPixel(hMemDC2, dwLoopX, dwLoopY, RGB(byNewPixel, byNewPixel, byNewPixel));
                } // for
            } // for

            ::SelectObject(hMemDC1, hOldBmp1);
            ::SelectObject(hMemDC2, hOldBmp2);

            csGrayII.hbmMask = csII.hbmMask;

            csGrayII.fIcon = TRUE;
            hGrayIcon = ::CreateIconIndirect(&csGrayII);
        } // if

        ::DeleteObject(csGrayII.hbmColor);
        //::DeleteObject(csGrayII.hbmMask);
    } // if

    ::DeleteObject(csII.hbmColor);
    ::DeleteObject(csII.hbmMask);
    ::DeleteDC(hMemDC1);
    ::DeleteDC(hMemDC2);
    ::ReleaseDC(m_hWnd, hMainDC);

    return hGrayIcon;
} // End of CreateGrayscaleIcon

// This function assigns icons to the button.
// Any previous icon or bitmap will be removed.
//
// Parameters:
//        [IN]    nIconIn
//                ID number of the icon resource to show when the mouse is over the button.
//                Pass NULL to remove any icon from the button.
//        [IN]    nIconOut
//                ID number of the icon resource to show when the mouse is outside the button.
//                Can be NULL.
//
// Return value:
//        BTNST_OK
//            Function executed successfully.
//        BTNST_INVALIDRESOURCE
//            Failed loading the specified resource.
//
DWORD CButtonST::SetIcon(int nIconIn, int nIconOut)
{
    HICON        hIconIn            = NULL;
    HICON        hIconOut        = NULL;
    HINSTANCE    hInstResource    = NULL;

    // Find correct resource handle
    hInstResource = AfxFindResourceHandle(MAKEINTRESOURCE(nIconIn), RT_GROUP_ICON);

    // Set icon when the mouse is IN the button
    hIconIn = (HICON)::LoadImage(hInstResource, MAKEINTRESOURCE(nIconIn), IMAGE_ICON, 0, 0, 0);

      // Set icon when the mouse is OUT the button
    if (nIconOut)
    {
        if (nIconOut == (int)BTNST_AUTO_GRAY)
            hIconOut = BTNST_AUTO_GRAY;
        else
            hIconOut = (HICON)::LoadImage(hInstResource, MAKEINTRESOURCE(nIconOut), IMAGE_ICON, 0, 0, 0);
    } // if

    return SetIcon(hIconIn, hIconOut);
} // End of SetIcon

// This function assigns icons to the button.
// Any previous icon or bitmap will be removed.
//
// Parameters:
//        [IN]    hIconIn
//                Handle fo the icon to show when the mouse is over the button.
//                Pass NULL to remove any icon from the button.
//        [IN]    hIconOut
//                Handle to the icon to show when the mouse is outside the button.
//                Can be NULL.
//
// Return value:
//        BTNST_OK
//            Function executed successfully.
//        BTNST_INVALIDRESOURCE
//            Failed loading the specified resource.
//
DWORD CButtonST::SetIcon(HICON hIconIn, HICON hIconOut)
{
    BOOL        bRetValue;
    ICONINFO    ii;

    // Free any loaded resource
    FreeResources();

    if (hIconIn)
    {
        // Icon when mouse over button?
        m_csIcons[0].hIcon = hIconIn;
        // Get icon dimension
        ::ZeroMemory(&ii, sizeof(ICONINFO));
        bRetValue = ::GetIconInfo(hIconIn, &ii);
        if (bRetValue == FALSE)
        {
            FreeResources();
            return BTNST_INVALIDRESOURCE;
        } // if

        m_csIcons[0].dwWidth    = (DWORD)(ii.xHotspot * 2);
        m_csIcons[0].dwHeight    = (DWORD)(ii.yHotspot * 2);
        ::DeleteObject(ii.hbmMask);
        ::DeleteObject(ii.hbmColor);

        // Icon when mouse outside button?
        if (hIconOut)
        {
            if (hIconOut == BTNST_AUTO_GRAY)
            {
                hIconOut = CreateGrayscaleIcon(hIconIn);
            } // if

            m_csIcons[1].hIcon = hIconOut;
            // Get icon dimension
            ::ZeroMemory(&ii, sizeof(ICONINFO));
            bRetValue = ::GetIconInfo(hIconOut, &ii);
            if (bRetValue == FALSE)
            {
                FreeResources();
                return BTNST_INVALIDRESOURCE;
            } // if

            m_csIcons[1].dwWidth    = (DWORD)(ii.xHotspot * 2);
            m_csIcons[1].dwHeight    = (DWORD)(ii.yHotspot * 2);
            ::DeleteObject(ii.hbmMask);
            ::DeleteObject(ii.hbmColor);
        } // if
    } // if

    Invalidate();

    return BTNST_OK;
} // End of SetIcon

// This function assigns bitmaps to the button.
// Any previous icon or bitmap will be removed.
//
// Parameters:
//        [IN]    nBitmapIn
//                ID number of the bitmap resource to show when the mouse is over the button.
//                Pass NULL to remove any bitmap from the button.
//        [IN]    crTransColorIn
//                Color (inside nBitmapIn) to be used as transparent color.
//        [IN]    nBitmapOut
//                ID number of the bitmap resource to show when the mouse is outside the button.
//                Can be NULL.
//        [IN]    crTransColorOut
//                Color (inside nBitmapOut) to be used as transparent color.
//
// Return value:
//        BTNST_OK
//            Function executed successfully.
//        BTNST_INVALIDRESOURCE
//            Failed loading the specified resource.
//        BTNST_FAILEDMASK
//            Failed creating mask bitmap.
//
DWORD CButtonST::SetBitmaps(int nBitmapIn, COLORREF crTransColorIn, int nBitmapOut, COLORREF crTransColorOut)
{
    HBITMAP        hBitmapIn        = NULL;
    HBITMAP        hBitmapOut        = NULL;
    HINSTANCE    hInstResource    = NULL;

    // Find correct resource handle
    hInstResource = AfxFindResourceHandle(MAKEINTRESOURCE(nBitmapIn), RT_BITMAP);

    // Load bitmap In
    hBitmapIn = (HBITMAP)::LoadImage(hInstResource, MAKEINTRESOURCE(nBitmapIn), IMAGE_BITMAP, 0, 0, 0);

    // Load bitmap Out
    if (nBitmapOut)
        hBitmapOut = (HBITMAP)::LoadImage(hInstResource, MAKEINTRESOURCE(nBitmapOut), IMAGE_BITMAP, 0, 0, 0);

    return SetBitmaps(hBitmapIn, crTransColorIn, hBitmapOut, crTransColorOut);
} // End of SetBitmaps

// This function assigns bitmaps to the button.
// Any previous icon or bitmap will be removed.
//
// Parameters:
//        [IN]    hBitmapIn
//                Handle fo the bitmap to show when the mouse is over the button.
//                Pass NULL to remove any bitmap from the button.
//        [IN]    crTransColorIn
//                Color (inside hBitmapIn) to be used as transparent color.
//        [IN]    hBitmapOut
//                Handle to the bitmap to show when the mouse is outside the button.
//                Can be NULL.
//        [IN]    crTransColorOut
//                Color (inside hBitmapOut) to be used as transparent color.
//
// Return value:
//        BTNST_OK
//            Function executed successfully.
//        BTNST_INVALIDRESOURCE
//            Failed loading the specified resource.
//        BTNST_FAILEDMASK
//            Failed creating mask bitmap.
//
DWORD CButtonST::SetBitmaps(HBITMAP hBitmapIn, COLORREF crTransColorIn, HBITMAP hBitmapOut, COLORREF crTransColorOut)
{
    int        nRetValue;
    BITMAP    csBitmapSize;

    // Free any loaded resource
    FreeResources();

    if (hBitmapIn)
    {
        m_csBitmaps[0].hBitmap = hBitmapIn;
        m_csBitmaps[0].crTransparent = crTransColorIn;
        // Get bitmap size
        nRetValue = ::GetObject(hBitmapIn, sizeof(csBitmapSize), &csBitmapSize);
        if (nRetValue == 0)
        {
            FreeResources();
            return BTNST_INVALIDRESOURCE;
        } // if
        m_csBitmaps[0].dwWidth = (DWORD)csBitmapSize.bmWidth;
        m_csBitmaps[0].dwHeight = (DWORD)csBitmapSize.bmHeight;

        // Create mask for bitmap In
        m_csBitmaps[0].hMask = CreateBitmapMask(hBitmapIn, m_csBitmaps[0].dwWidth, m_csBitmaps[0].dwHeight, crTransColorIn);
        if (m_csBitmaps[0].hMask == NULL)
        {
            FreeResources();
            return BTNST_FAILEDMASK;
        } // if

        if (hBitmapOut)
        {
            m_csBitmaps[1].hBitmap = hBitmapOut;
            m_csBitmaps[1].crTransparent = crTransColorOut;
            // Get bitmap size
            nRetValue = ::GetObject(hBitmapOut, sizeof(csBitmapSize), &csBitmapSize);
            if (nRetValue == 0)
            {
                FreeResources();
                return BTNST_INVALIDRESOURCE;
            } // if
            m_csBitmaps[1].dwWidth = (DWORD)csBitmapSize.bmWidth;
            m_csBitmaps[1].dwHeight = (DWORD)csBitmapSize.bmHeight;

            // Create mask for bitmap Out
            m_csBitmaps[1].hMask = CreateBitmapMask(hBitmapOut, m_csBitmaps[1].dwWidth, m_csBitmaps[1].dwHeight, crTransColorOut);
            if (m_csBitmaps[1].hMask == NULL)
            {
                FreeResources();
                return BTNST_FAILEDMASK;
            } // if
        } // if
    } // if

    Invalidate();

    return BTNST_OK;
} // End of SetBitmaps

// This functions sets the button to have a standard or flat style.
//
// Parameters:
//        [IN]    bFlat
//                If TRUE the button will have a flat style, else
//                will have a standard style.
//                By default, CButtonST buttons are flat.
//        [IN]    bRepaint
//                If TRUE the control will be repainted.
//
// Return value:
//        BTNST_OK
//            Function executed successfully.
//
DWORD CButtonST::SetFlat(BOOL bFlat, BOOL bRepaint)
{
    m_bIsFlat = bFlat;
    if (bRepaint)    Invalidate();

    return BTNST_OK;
} // End of SetFlat

// This function sets the alignment type between icon/bitmap and text.
//
// Parameters:
//        [IN]    byAlign
//                Alignment type. Can be one of the following values:
//                ST_ALIGN_HORIZ            Icon/bitmap on the left, text on the right
//                ST_ALIGN_VERT            Icon/bitmap on the top, text on the bottom
//                ST_ALIGN_HORIZ_RIGHT    Icon/bitmap on the right, text on the left
//                By default, CButtonST buttons have ST_ALIGN_HORIZ alignment.
//        [IN]    bRepaint
//                If TRUE the control will be repainted.
//
// Return value:
//        BTNST_OK
//            Function executed successfully.
//        BTNST_INVALIDALIGN
//            Alignment type not supported.
//
DWORD CButtonST::SetAlign(BYTE byAlign, BOOL bRepaint)
{
    switch (byAlign)
    {    
        case ST_ALIGN_HORIZ:
        case ST_ALIGN_HORIZ_RIGHT:
        case ST_ALIGN_VERT:
            m_byAlign = byAlign;
            if (bRepaint)    Invalidate();
            return BTNST_OK;
            break;
    } // switch

    return BTNST_INVALIDALIGN;
} // End of SetAlign

// This function sets the state of the checkbox.
// If the button is not a checkbox, this function has no meaning.
//
// Parameters:
//        [IN]    nCheck
//                1 to check the checkbox.
//                0 to un-check the checkbox.
//        [IN]    bRepaint
//                If TRUE the control will be repainted.
//
// Return value:
//        BTNST_OK
//            Function executed successfully.
//
DWORD CButtonST::SetCheck(int nCheck, BOOL bRepaint)
{
    if (m_bIsCheckBox)
    {
        if (nCheck == 0) m_nCheck = 0;
        else m_nCheck = 1;

        if (bRepaint) Invalidate();
    } // if

    return BTNST_OK;
} // End of SetCheck

// This function returns the current state of the checkbox.
// If the button is not a checkbox, this function has no meaning.
//
// Return value:
//        The current state of the checkbox.
//            1 if checked.
//            0 if not checked or the button is not a checkbox.
//
int CButtonST::GetCheck()
{
    return m_nCheck;
} // End of GetCheck

// This function sets all colors to a default value.
//
// Parameters:
//        [IN]    bRepaint
//                If TRUE the control will be repainted.
//
// Return value:
//        BTNST_OK
//            Function executed successfully.
//
DWORD CButtonST::SetDefaultColors(BOOL bRepaint)
{
    m_crColors[BTNST_COLOR_BK_IN]        = ::GetSysColor(COLOR_BTNFACE);
    m_crColors[BTNST_COLOR_FG_IN]        = ::GetSysColor(COLOR_BTNTEXT);
    m_crColors[BTNST_COLOR_BK_OUT]        = ::GetSysColor(COLOR_BTNFACE);
    m_crColors[BTNST_COLOR_FG_OUT]        = ::GetSysColor(COLOR_BTNTEXT);
    m_crColors[BTNST_COLOR_BK_FOCUS]    = ::GetSysColor(COLOR_BTNFACE);
    m_crColors[BTNST_COLOR_FG_FOCUS]    = ::GetSysColor(COLOR_BTNTEXT);

    if (bRepaint)    Invalidate();

    return BTNST_OK;
} // End of SetDefaultColors

// This function sets the color to use for a particular state.
//
// Parameters:
//        [IN]    byColorIndex
//                Index of the color to set. Can be one of the following values:
//                BTNST_COLOR_BK_IN        Background color when mouse is over the button
//                BTNST_COLOR_FG_IN        Text color when mouse is over the button
//                BTNST_COLOR_BK_OUT        Background color when mouse is outside the button
//                BTNST_COLOR_FG_OUT        Text color when mouse is outside the button
//                BTNST_COLOR_BK_FOCUS    Background color when the button is focused
//                BTNST_COLOR_FG_FOCUS    Text color when the button is focused
//        [IN]    crColor
//                New color.
//        [IN]    bRepaint
//                If TRUE the control will be repainted.
//
// Return value:
//        BTNST_OK
//            Function executed successfully.
//        BTNST_INVALIDINDEX
//            Invalid color index.
//
DWORD CButtonST::SetColor(BYTE byColorIndex, COLORREF crColor, BOOL bRepaint)
{
    if (byColorIndex >= BTNST_MAX_COLORS)    return BTNST_INVALIDINDEX;

    // Set new color
    m_crColors[byColorIndex] = crColor;

    if (bRepaint)    Invalidate();

    return BTNST_OK;
} // End of SetColor

// This functions returns the color used for a particular state.
//
// Parameters:
//        [IN]    byColorIndex
//                Index of the color to get.
//                See SetColor for the list of available colors.
//        [OUT]    crpColor
//                A pointer to a COLORREF that will receive the color.
//
// Return value:
//        BTNST_OK
//            Function executed successfully.
//        BTNST_INVALIDINDEX
//            Invalid color index.
//
DWORD CButtonST::GetColor(BYTE byColorIndex, COLORREF* crpColor)
{
    if (byColorIndex >= BTNST_MAX_COLORS)    return BTNST_INVALIDINDEX;

    // Get color
    *crpColor = m_crColors[byColorIndex];

    return BTNST_OK;
} // End of GetColor

// This function applies an offset to the RGB components of the specified color.
// This function can be seen as an easy way to make a color darker or lighter than
// its default value.
//
// Parameters:
//        [IN]    byColorIndex
//                Index of the color to set.
//                See SetColor for the list of available colors.
//        [IN]    shOffsetColor
//                A short value indicating the offset to apply to the color.
//                This value must be between -255 and 255.
//        [IN]    bRepaint
//                If TRUE the control will be repainted.
//
// Return value:
//        BTNST_OK
//            Function executed successfully.
//        BTNST_INVALIDINDEX
//            Invalid color index.
//        BTNST_BADPARAM
//            The specified offset is out of range.
//
DWORD CButtonST::OffsetColor(BYTE byColorIndex, short shOffset, BOOL bRepaint)
{
    BYTE    byRed = 0;
    BYTE    byGreen = 0;
    BYTE    byBlue = 0;
    short    shOffsetR = shOffset;
    short    shOffsetG = shOffset;
    short    shOffsetB = shOffset;

    if (byColorIndex >= BTNST_MAX_COLORS)    return BTNST_INVALIDINDEX;
    if (shOffset < -255 || shOffset > 255)    return BTNST_BADPARAM;

    // Get RGB components of specified color
    byRed = GetRValue(m_crColors[byColorIndex]);
    byGreen = GetGValue(m_crColors[byColorIndex]);
    byBlue = GetBValue(m_crColors[byColorIndex]);

    // Calculate max. allowed real offset
    if (shOffset > 0)
    {
        if (byRed + shOffset > 255)        shOffsetR = 255 - byRed;
        if (byGreen + shOffset > 255)    shOffsetG = 255 - byGreen;
        if (byBlue + shOffset > 255)    shOffsetB = 255 - byBlue;

        shOffset = min(min(shOffsetR, shOffsetG), shOffsetB);
    } // if
    else
    {
        if (byRed + shOffset < 0)        shOffsetR = -byRed;
        if (byGreen + shOffset < 0)        shOffsetG = -byGreen;
        if (byBlue + shOffset < 0)        shOffsetB = -byBlue;

        shOffset = max(max(shOffsetR, shOffsetG), shOffsetB);
    } // else

    // Set new color
    m_crColors[byColorIndex] = RGB(byRed + shOffset, byGreen + shOffset, byBlue + shOffset);

    if (bRepaint)    Invalidate();

    return BTNST_OK;
} // End of OffsetColor

// This function sets the hilight logic for the button.
// Applies only to flat buttons.
//
// Parameters:
//        [IN]    bAlwaysTrack
//                If TRUE the button will be hilighted even if the window that owns it, is
//                not the active window.
//                If FALSE the button will be hilighted only if the window that owns it,
//                is the active window.
//
// Return value:
//        BTNST_OK
//            Function executed successfully.
//
DWORD CButtonST::SetAlwaysTrack(BOOL bAlwaysTrack)
{
    m_bAlwaysTrack = bAlwaysTrack;
    return BTNST_OK;
} // End of SetAlwaysTrack

// This function sets the cursor to be used when the mouse is over the button.
//
// Parameters:
//        [IN]    nCursorId
//                ID number of the cursor resource.
//                Pass NULL to remove a previously loaded cursor.
//        [IN]    bRepaint
//                If TRUE the control will be repainted.
//
// Return value:
//        BTNST_OK
//            Function executed successfully.
//        BTNST_INVALIDRESOURCE
//            Failed loading the specified resource.
//
DWORD CButtonST::SetBtnCursor(int nCursorId, BOOL bRepaint)
{
    HINSTANCE    hInstResource = NULL;
    // Destroy any previous cursor
    if (m_hCursor)
    {
        ::DestroyCursor(m_hCursor);
        m_hCursor = NULL;
    } // if

    // Load cursor
    if (nCursorId)
    {
        hInstResource = AfxFindResourceHandle(MAKEINTRESOURCE(nCursorId), RT_GROUP_CURSOR);
        // Load cursor resource
        m_hCursor = (HCURSOR)::LoadImage(hInstResource, MAKEINTRESOURCE(nCursorId), IMAGE_CURSOR, 0, 0, 0);
        // Repaint the button
        if (bRepaint) Invalidate();
        // If something wrong
        if (m_hCursor == NULL) return BTNST_INVALIDRESOURCE;
    } // if

    return BTNST_OK;
} // End of SetBtnCursor

// This function sets if the button border must be drawn.
// Applies only to flat buttons.
//
// Parameters:
//        [IN]    bDrawBorder
//                If TRUE the border will be drawn.
//        [IN]    bRepaint
//                If TRUE the control will be repainted.
//
// Return value:
//        BTNST_OK
//            Function executed successfully.
//
DWORD CButtonST::DrawBorder(BOOL bDrawBorder, BOOL bRepaint)
{
    m_bDrawBorder = bDrawBorder;
    // Repaint the button
    if (bRepaint) Invalidate();

    return BTNST_OK;
} // End of DrawBorder

// This function sets if the focus rectangle must be drawn for flat buttons.
//
// Parameters:
//        [IN]    bDrawFlatFocus
//                If TRUE the focus rectangle will be drawn also for flat buttons.
//        [IN]    bRepaint
//                If TRUE the control will be repainted.
//
// Return value:
//        BTNST_OK
//            Function executed successfully.
//
DWORD CButtonST::DrawFlatFocus(BOOL bDrawFlatFocus, BOOL bRepaint)
{
    m_bDrawFlatFocus = bDrawFlatFocus;
    // Repaint the button
    if (bRepaint) Invalidate();

    return BTNST_OK;
} // End of DrawFlatFocus

void CButtonST::InitToolTip()
{
    if (m_ToolTip.m_hWnd == NULL)
    {
        // Create ToolTip control
        m_ToolTip.Create(this);
        // Create inactive
        m_ToolTip.Activate(FALSE);
        // Enable multiline
        m_ToolTip.SendMessage(TTM_SETMAXTIPWIDTH, 0, 400);
    } // if
} // End of InitToolTip

// This function sets the text to show in the button tooltip.
//
// Parameters:
//        [IN]    nText
//                ID number of the string resource containing the text to show.
//        [IN]    bActivate
//                If TRUE the tooltip will be created active.
//
void CButtonST::SetTooltipText(int nText, BOOL bActivate)
{
    CString sText;

    // Load string resource
    sText.LoadString(nText);
    // If string resource is not empty
    if (sText.IsEmpty() == FALSE) SetTooltipText((LPCTSTR)sText, bActivate);
} // End of SetTooltipText

// This function sets the text to show in the button tooltip.
//
// Parameters:
//        [IN]    lpszText
//                Pointer to a null-terminated string containing the text to show.
//        [IN]    bActivate
//                If TRUE the tooltip will be created active.
//
void CButtonST::SetTooltipText(LPCTSTR lpszText, BOOL bActivate)
{
    // We cannot accept NULL pointer
    if (lpszText == NULL) return;

    // Initialize ToolTip
    InitToolTip();

    // If there is no tooltip defined then add it
    if (m_ToolTip.GetToolCount() == 0)
    {
        CRect rectBtn; 
        GetClientRect(rectBtn);
        m_ToolTip.AddTool(this, lpszText, rectBtn, 1);
    } // if

    // Set text for tooltip
    m_ToolTip.UpdateTipText(lpszText, this, 1);
    m_ToolTip.Activate(bActivate);
} // End of SetTooltipText

// This function enables or disables the button tooltip.
//
// Parameters:
//        [IN]    bActivate
//                If TRUE the tooltip will be activated.
//
void CButtonST::ActivateTooltip(BOOL bActivate)
{
    // If there is no tooltip then do nothing
    if (m_ToolTip.GetToolCount() == 0) return;

    // Activate tooltip
    m_ToolTip.Activate(bActivate);
} // End of EnableTooltip

// This function returns if the button is the default button.
//
// Return value:
//        TRUE
//            The button is the default button.
//        FALSE
//            The button is not the default button.
//
BOOL CButtonST::GetDefault()
{
    return m_bIsDefault;
} // End of GetDefault

// This function enables the transparent mode.
// Note: this operation is not reversible.
// DrawTransparent should be called just after the button is created.
// Do not use trasparent buttons until you really need it (you have a bitmapped
// background) since each transparent button makes a copy in memory of its background.
// This may bring unnecessary memory use and execution overload.
//
// Parameters:
//        [IN]    bRepaint
//                If TRUE the control will be repainted.
//
void CButtonST::DrawTransparent(BOOL bRepaint)
{
    m_bDrawTransparent = TRUE;

    // Restore old bitmap (if any)
    if (m_dcBk.m_hDC != NULL && m_pbmpOldBk != NULL)
    {
        m_dcBk.SelectObject(m_pbmpOldBk);
    } // if

    m_bmpBk.DeleteObject();
    m_dcBk.DeleteDC();

    // Repaint the button
    if (bRepaint) Invalidate();
} // End of DrawTransparent

// This function sets the URL that will be opened when the button is clicked.
//
// Parameters:
//        [IN]    lpszURL
//                Pointer to a null-terminated string that contains the URL.
//                Pass NULL to removed any previously specified URL.
//
// Return value:
//        BTNST_OK
//            Function executed successfully.
//
DWORD CButtonST::SetURL(LPCTSTR lpszURL)
{
    // Remove any existing URL
    memset(m_szURL, 0, sizeof(m_szURL));

    if (lpszURL)
    {
        // Store the URL
        _tcsncpy(m_szURL, lpszURL, _MAX_PATH);
    } // if

    return BTNST_OK;
} // End of SetURL

// This function associates a menu to the button.
// The menu will be displayed clicking the button.
//
// Parameters:
//        [IN]    nMenu
//                ID number of the menu resource.
//                Pass NULL to remove any menu from the button.
//        [IN]    hParentWnd
//                Handle to the window that owns the menu.
//                This window receives all messages from the menu.
//        [IN]    bRepaint
//                If TRUE the control will be repainted.
//
// Return value:
//        BTNST_OK
//            Function executed successfully.
//        BTNST_INVALIDRESOURCE
//            Failed loading the specified resource.
//
#ifndef    BTNST_USE_BCMENU
DWORD CButtonST::SetMenu(UINT nMenu, HWND hParentWnd, BOOL bRepaint)
{
    HINSTANCE    hInstResource    = NULL;

    // Destroy any previous menu
    if (m_hMenu)
    {
        ::DestroyMenu(m_hMenu);
        m_hMenu = NULL;
        m_hParentWndMenu = NULL;
        m_bMenuDisplayed = FALSE;
    } // if

    // Load menu
    if (nMenu)
    {
        // Find correct resource handle
        hInstResource = AfxFindResourceHandle(MAKEINTRESOURCE(nMenu), RT_MENU);
        // Load menu resource
        m_hMenu = ::LoadMenu(hInstResource, MAKEINTRESOURCE(nMenu));
        m_hParentWndMenu = hParentWnd;
        // If something wrong
        if (m_hMenu == NULL) return BTNST_INVALIDRESOURCE;
    } // if

    // Repaint the button
    if (bRepaint) Invalidate();

    return BTNST_OK;
} // End of SetMenu
#endif

// This function associates a menu to the button.
// The menu will be displayed clicking the button.
// The menu will be handled by the BCMenu class.
//
// Parameters:
//        [IN]    nMenu
//                ID number of the menu resource.
//                Pass NULL to remove any menu from the button.
//        [IN]    hParentWnd
//                Handle to the window that owns the menu.
//                This window receives all messages from the menu.
//        [IN]    bWinXPStyle
//                If TRUE the menu will be displayed using the new Windows XP style.
//                If FALSE the menu will be displayed using the standard style.
//        [IN]    nToolbarID
//                Resource ID of the toolbar to be associated to the menu.
//        [IN]    sizeToolbarIcon
//                A CSize object indicating the size (in pixels) of each icon into the toolbar.
//                All icons into the toolbar must have the same size.
//        [IN]    crToolbarBk
//                A COLORREF value indicating the color to use as background for the icons into the toolbar.
//                This color will be used as the "transparent" color.
//        [IN]    bRepaint
//                If TRUE the control will be repainted.
//
// Return value:
//        BTNST_OK
//            Function executed successfully.
//        BTNST_INVALIDRESOURCE
//            Failed loading the specified resource.
//
#ifdef    BTNST_USE_BCMENU
DWORD CButtonST::SetMenu(UINT nMenu, HWND hParentWnd, BOOL bWinXPStyle, UINT nToolbarID, CSize sizeToolbarIcon, COLORREF crToolbarBk, BOOL bRepaint)
{
    BOOL    bRetValue = FALSE;

    // Destroy any previous menu
    if (m_menuPopup.m_hMenu)
    {
        m_menuPopup.DestroyMenu();
        m_hParentWndMenu = NULL;
        m_bMenuDisplayed = FALSE;
    } // if

    // Load menu
    if (nMenu)
    {
        m_menuPopup.SetMenuDrawMode(bWinXPStyle);
        // Load menu
        bRetValue = m_menuPopup.LoadMenu(nMenu);
        // If something wrong
        if (bRetValue == FALSE) return BTNST_INVALIDRESOURCE;

        // Load toolbar
        if (nToolbarID)
        {
            m_menuPopup.SetBitmapBackground(crToolbarBk);
            m_menuPopup.SetIconSize(sizeToolbarIcon.cx, sizeToolbarIcon.cy);

            bRetValue = m_menuPopup.LoadToolbar(nToolbarID);
            // If something wrong
            if (bRetValue == FALSE) 
            {
                m_menuPopup.DestroyMenu();
                return BTNST_INVALIDRESOURCE;
            } // if
        } // if

        m_hParentWndMenu = hParentWnd;
    } // if

    // Repaint the button
    if (bRepaint) Invalidate();

    return BTNST_OK;
} // End of SetMenu
#endif

// This function is called every time the button background needs to be painted.
// If the button is in transparent mode this function will NOT be called.
// This is a virtual function that can be rewritten in CButtonST-derived classes
// to produce a whole range of buttons not available by default.
//
// Parameters:
//        [IN]    pDC
//                Pointer to a CDC object that indicates the device context.
//        [IN]    pRect
//                Pointer to a CRect object that indicates the bounds of the
//                area to be painted.
//
// Return value:
//        BTNST_OK
//            Function executed successfully.
//
DWORD CButtonST::OnDrawBackground(CDC* pDC, LPCRECT pRect)
{
    COLORREF    crColor;

    if (m_bMouseOnButton || m_bIsPressed)
        crColor = m_crColors[BTNST_COLOR_BK_IN];
    else
    {
        if (m_bIsFocused)
            crColor = m_crColors[BTNST_COLOR_BK_FOCUS];
        else
            crColor = m_crColors[BTNST_COLOR_BK_OUT];
    } // else

    CBrush        brBackground(crColor);

    pDC->FillRect(pRect, &brBackground);

    return BTNST_OK;
} // End of OnDrawBackground

// This function is called every time the button border needs to be painted.
// If the button is in standard (not flat) mode this function will NOT be called.
// This is a virtual function that can be rewritten in CButtonST-derived classes
// to produce a whole range of buttons not available by default.
//
// Parameters:
//        [IN]    pDC
//                Pointer to a CDC object that indicates the device context.
//        [IN]    pRect
//                Pointer to a CRect object that indicates the bounds of the
//                area to be painted.
//
// Return value:
//        BTNST_OK
//            Function executed successfully.
//
DWORD CButtonST::OnDrawBorder(CDC* pDC, LPCRECT pRect)
{
    if (m_bIsPressed)
        pDC->Draw3dRect(pRect, ::GetSysColor(COLOR_BTNSHADOW), ::GetSysColor(COLOR_BTNHILIGHT));
    else
        pDC->Draw3dRect(pRect, ::GetSysColor(COLOR_BTNHILIGHT), ::GetSysColor(COLOR_BTNSHADOW));

    return BTNST_OK;
} // End of OnDrawBorder

#undef BS_TYPEMASK

//
//    Class:        CButtonST
//
//    Compiler:    Visual C++
//    Tested on:    Visual C++ 5.0
//                Visual C++ 6.0
//
//    Version:    See GetVersionC() or GetVersionI()
//
//    Created:    xx/xxxx/1998
//    Updated:    18/April/2002
//
//    Author:        Davide Calabro'        davide_calabro@yahoo.com
//                                    http://www.softechsoftware.it
//
//    Note:        Code for the PreSubclassWindow and OnSetStyle functions
//                has been taken from the COddButton class
//                published by Paolo Messina and Jerzy Kaczorowski
//
//    Disclaimer
//    ----------
//    THIS SOFTWARE AND THE ACCOMPANYING FILES ARE DISTRIBUTED "AS IS" AND WITHOUT
//    ANY WARRANTIES WHETHER EXPRESSED OR IMPLIED. NO REPONSIBILITIES FOR POSSIBLE
//    DAMAGES OR EVEN FUNCTIONALITY CAN BE TAKEN. THE USER MUST ASSUME THE ENTIRE
//    RISK OF USING THIS SOFTWARE.
//
//    Terms of use
//    ------------
//    THIS SOFTWARE IS FREE FOR PERSONAL USE OR FREEWARE APPLICATIONS.
//    IF YOU USE THIS SOFTWARE IN COMMERCIAL OR SHAREWARE APPLICATIONS YOU
//    ARE GENTLY ASKED TO DONATE 1$ (ONE U.S. DOLLAR) TO THE AUTHOR:
//
//        Davide Calabro'
//        P.O. Box 65
//        21019 Somma Lombardo (VA)
//        Italy
//
#ifndef _BTNST_H
#define _BTNST_H

// Uncomment the following 2 lines to enable support for BCMenu class
#define    BTNST_USE_BCMENU
#include "BCMenu.h"

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000

// Return values
#ifndef    BTNST_OK
#define    BTNST_OK                        0
#endif
#ifndef    BTNST_INVALIDRESOURCE
#define    BTNST_INVALIDRESOURCE            1
#endif
#ifndef    BTNST_FAILEDMASK
#define    BTNST_FAILEDMASK                2
#endif
#ifndef    BTNST_INVALIDINDEX
#define    BTNST_INVALIDINDEX                3
#endif
#ifndef    BTNST_INVALIDALIGN
#define    BTNST_INVALIDALIGN                4
#endif
#ifndef    BTNST_BADPARAM
#define    BTNST_BADPARAM                    5
#endif

// Dummy identifier for grayscale icon
#ifndef    BTNST_AUTO_GRAY
#define    BTNST_AUTO_GRAY                    (HICON)(0xffffffff - 1L)
#endif

class CButtonST : public CButton
{
public:
    CButtonST();
    ~CButtonST();

    enum    {    ST_ALIGN_HORIZ    = 0,            // Icon/bitmap on the left, text on the right
                ST_ALIGN_VERT,                    // Icon/bitmap on the top, text on the bottom
                ST_ALIGN_HORIZ_RIGHT            // Icon/bitmap on the right, text on the left
            };

    enum    {    BTNST_COLOR_BK_IN    = 0,        // Background color when mouse is INside
                BTNST_COLOR_FG_IN,                // Text color when mouse is INside
                BTNST_COLOR_BK_OUT,                // Background color when mouse is OUTside
                BTNST_COLOR_FG_OUT,                // Text color when mouse is OUTside
                BTNST_COLOR_BK_FOCUS,            // Background color when the button is focused
                BTNST_COLOR_FG_FOCUS,            // Text color when the button is focused

                BTNST_MAX_COLORS
            };

    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CButtonST)
    public:
    virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
    virtual BOOL PreTranslateMessage(MSG* pMsg);
    protected:
    virtual void PreSubclassWindow();
    virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam);
    //}}AFX_VIRTUAL

public:
    DWORD SetDefaultColors(BOOL bRepaint = TRUE);
    DWORD SetColor(BYTE byColorIndex, COLORREF crColor, BOOL bRepaint = TRUE);
    DWORD GetColor(BYTE byColorIndex, COLORREF* crpColor);
    DWORD OffsetColor(BYTE byColorIndex, short shOffset, BOOL bRepaint = TRUE);

    DWORD SetCheck(int nCheck, BOOL bRepaint = TRUE);
    int GetCheck();

    DWORD SetURL(LPCTSTR lpszURL = NULL);
    void DrawTransparent(BOOL bRepaint = FALSE);

    BOOL GetDefault();
    DWORD SetAlwaysTrack(BOOL bAlwaysTrack = TRUE);

    void SetTooltipText(int nText, BOOL bActivate = TRUE);
    void SetTooltipText(LPCTSTR lpszText, BOOL bActivate = TRUE);
    void ActivateTooltip(BOOL bEnable = TRUE);

    DWORD SetBtnCursor(int nCursorId = NULL, BOOL bRepaint = TRUE);

    DWORD SetFlat(BOOL bFlat = TRUE, BOOL bRepaint = TRUE);
    DWORD SetAlign(BYTE byAlign, BOOL bRepaint = TRUE);

    DWORD DrawBorder(BOOL bDrawBorder = TRUE, BOOL bRepaint = TRUE);
    DWORD DrawFlatFocus(BOOL bDrawFlatFocus, BOOL bRepaint = TRUE);

    DWORD SetIcon(int nIconIn, int nIconOut = NULL);
    DWORD SetIcon(HICON hIconIn, HICON hIconOut = NULL);

    DWORD SetBitmaps(int nBitmapIn, COLORREF crTransColorIn, int nBitmapOut = NULL, COLORREF crTransColorOut = 0);
    DWORD SetBitmaps(HBITMAP hBitmapIn, COLORREF crTransColorIn, HBITMAP hBitmapOut = NULL, COLORREF crTransColorOut = 0);

#ifdef    BTNST_USE_BCMENU
    DWORD SetMenu(UINT nMenu, HWND hParentWnd, BOOL bWinXPStyle = TRUE, UINT nToolbarID = NULL, CSize sizeToolbarIcon = CSize(16, 16), COLORREF crToolbarBk = RGB(255, 0, 255), BOOL bRepaint = TRUE);
#else
    DWORD SetMenu(UINT nMenu, HWND hParentWnd, BOOL bRepaint = TRUE);
#endif

    static short GetVersionI()        {return 35;}
    static LPCTSTR GetVersionC()    {return (LPCTSTR)_T("3.5");}

    BOOL    m_bShowDisabledBitmap;

protected:
    //{{AFX_MSG(CButtonST)
    afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
    afx_msg void OnKillFocus(CWnd* pNewWnd);
    afx_msg void OnMouseMove(UINT nFlags, CPoint point);
    afx_msg void OnSysColorChange();
    afx_msg BOOL OnClicked();
    afx_msg void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized);
    afx_msg void OnEnable(BOOL bEnable);
    afx_msg void OnCancelMode();
    afx_msg UINT OnGetDlgCode();
    //}}AFX_MSG

#ifdef    BTNST_USE_BCMENU
    afx_msg LRESULT OnMenuChar(UINT nChar, UINT nFlags, CMenu* pMenu);
    afx_msg void OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct);
#endif

    afx_msg HBRUSH CtlColor(CDC* pDC, UINT nCtlColor);
    HICON CreateGrayscaleIcon(HICON hIcon);
    virtual DWORD OnDrawBackground(CDC* pDC, LPCRECT pRect);
    virtual DWORD OnDrawBorder(CDC* pDC, LPCRECT pRect);

    BOOL        m_bIsFlat;            // Is a flat button?
    BOOL        m_bMouseOnButton;    // Is mouse over the button?
    BOOL        m_bDrawTransparent;    // Draw transparent?
    BOOL        m_bIsPressed;        // Is button pressed?
    BOOL        m_bIsFocused;        // Is button focused?
    BOOL        m_bIsDisabled;        // Is button disabled?
    BOOL        m_bIsDefault;        // Is default button?
    BOOL        m_bIsCheckBox;        // Is the button a checkbox?
    BYTE        m_byAlign;            // Align mode
    BOOL        m_bDrawBorder;        // Draw border?
    BOOL        m_bDrawFlatFocus;    // Draw focus rectangle for flat button?
    COLORREF    m_crColors[BTNST_MAX_COLORS];    // Colors to be used
    HWND        m_hParentWndMenu;    // Handle to window for menu selection
    BOOL        m_bMenuDisplayed;    // Is menu displayed ?

#ifdef    BTNST_USE_BCMENU
    BCMenu        m_menuPopup;        // BCMenu class instance
#else
    HMENU        m_hMenu;            // Handle to associated menu
#endif

private:
    LRESULT OnSetCheck(WPARAM wParam, LPARAM lParam);
    LRESULT OnGetCheck(WPARAM wParam, LPARAM lParam);
    LRESULT OnSetStyle(WPARAM wParam, LPARAM lParam);
    LRESULT OnMouseLeave(WPARAM wParam, LPARAM lParam);

    void CancelHover();
    void FreeResources(BOOL bCheckForNULL = TRUE);
    void PrepareImageRect(BOOL bHasTitle, RECT* rpItem, CRect* rpTitle, BOOL bIsPressed, DWORD dwWidth, DWORD dwHeight, CRect* rpImage);
    HBITMAP CreateBitmapMask(HBITMAP hSourceBitmap, DWORD dwWidth, DWORD dwHeight, COLORREF crTransColor);
    void DrawTheIcon(CDC* pDC, BOOL bHasTitle, RECT* rpItem, CRect* rpTitle, BOOL bIsPressed, BOOL bIsDisabled);
    void DrawTheBitmap(CDC* pDC, BOOL bHasTitle, RECT *rItem, CRect *rCaption, BOOL bIsPressed, BOOL bIsDisabled);
    void PaintBk(CDC* pDC);

    void InitToolTip();

    HCURSOR        m_hCursor;            // Handle to cursor
    CToolTipCtrl m_ToolTip;            // Tooltip

    CDC            m_dcBk;
    CBitmap        m_bmpBk;
    CBitmap*    m_pbmpOldBk;

    BOOL        m_bAlwaysTrack;        // Always hilight button?
    int            m_nCheck;            // Current value for checkbox
    UINT        m_nTypeStyle;        // Button style

    TCHAR        m_szURL[_MAX_PATH];    // URL to open when clicked

#pragma pack(1)
    typedef struct _STRUCT_ICONS
    {
        HICON        hIcon;            // Handle to icon
        DWORD        dwWidth;        // Width of icon
        DWORD        dwHeight;        // Height of icon
    } STRUCT_ICONS;
#pragma pack()

#pragma pack(1)
    typedef struct _STRUCT_BITMAPS
    {
        HBITMAP        hBitmap;        // Handle to bitmap
        DWORD        dwWidth;        // Width of bitmap
        DWORD        dwHeight;        // Height of bitmap
        HBITMAP        hMask;            // Handle to mask bitmap
        COLORREF    crTransparent;    // Transparent color
    } STRUCT_BITMAPS;
#pragma pack()

    STRUCT_ICONS    m_csIcons[2];
    STRUCT_BITMAPS    m_csBitmaps[2];

    DECLARE_MESSAGE_MAP()
};

//{{AFX_INSERT_LOCATION}}
// Microsoft Developer Studio will insert additional declarations immediately before the previous line.

#endif

//*************************************************************************
// BCMenu.h : header file
// Version : 3.02
// Date : March 2002
// Author : Brent Corkum
// Email :  corkum@rocscience.com
// Latest Version : http://www.rocscience.com/~corkum/BCMenu.html
// 
// Bug Fixes and portions of code supplied by:
//
// Ben Ashley,Girish Bharadwaj,Jean-Edouard Lachand-Robert,
// Robert Edward Caldecott,Kenny Goers,Leonardo Zide,
// Stefan Kuhr,Reiner Jung,Martin Vladic,Kim Yoo Chul,
// Oz Solomonovich,Tongzhe Cui,Stephane Clog,Warren Stevens,
// Damir Valiulin,David Kinder,Marc Loiry
//
// You are free to use/modify this code but leave this header intact.
// This class is public domain so you are free to use it any of
// your applications (Freeware,Shareware,Commercial). All I ask is
// that you let me know so that if you have a real winner I can
// brag to my buddies that some of my code is in your app. I also
// wouldn't mind if you sent me a copy of your application since I
// like to play with new stuff.
//*************************************************************************

#ifndef BCMenu_H
#define BCMenu_H

#include <afxtempl.h>

// BCMenuData class. Fill this class structure to define a single menu item:
class BCMenuData
{
    wchar_t *m_szMenuText;
public:
    BCMenuData () {menuIconNormal=-1;xoffset=-1;bitmap=NULL;pContext=NULL;
    nFlags=0;nID=0;syncflag=0;m_szMenuText=NULL;global_offset=-1;threeD=FALSE;};
    void SetAnsiString(LPCSTR szAnsiString);
    void SetWideString(const wchar_t *szWideString);
    const wchar_t *GetWideString(void) {return m_szMenuText;};
    ~BCMenuData ();
    CString GetString(void);//returns the menu text in ANSI or UNICODE
    int xoffset,global_offset;
    BOOL threeD;
    int menuIconNormal;
    UINT nFlags,nID,syncflag;
    CImageList *bitmap;
    void *pContext; // used to attach user data
};

//struct CMenuItemInfo : public MENUITEMINFO {
struct CMenuItemInfo : public 
//MENUITEMINFO 
#ifndef UNICODE   //SK: this fixes warning C4097: typedef-name 'MENUITEMINFO' used as synonym for class-name 'tagMENUITEMINFOA'
tagMENUITEMINFOA
#else
tagMENUITEMINFOW
#endif
{
    CMenuItemInfo()
    {
        memset(this, 0, sizeof(MENUITEMINFO));
        cbSize = sizeof(MENUITEMINFO);
    }
};

// how the menu's are drawn, either original or XP style
typedef enum {BCMENU_DRAWMODE_ORIGINAL,BCMENU_DRAWMODE_XP} BC_MenuDrawMode;

// how seperators are handled when removing a menu (Tongzhe Cui)
typedef enum {BCMENU_NONE, BCMENU_HEAD, BCMENU_TAIL, BCMENU_BOTH} BC_Seperator;

// defines for unicode support
#ifndef UNICODE
#define AppendMenu AppendMenuA
#define InsertMenu InsertMenuA
#define InsertODMenu InsertODMenuA
#define AppendODMenu AppendODMenuA
#define AppendODPopupMenu AppendODPopupMenuA
#define ModifyODMenu ModifyODMenuA
#else
#define AppendMenu AppendMenuW
#define InsertMenu InsertMenuW
#define InsertODMenu InsertODMenuW
#define AppendODMenu AppendODMenuW
#define ModifyODMenu ModifyODMenuW
#define AppendODPopupMenu AppendODPopupMenuW
#endif


class BCMenu : public CMenu
{
    DECLARE_DYNAMIC( BCMenu )
public:
    BCMenu(); 
    virtual ~BCMenu();

    // Functions for loading and applying bitmaps to menus (see example application)
    virtual BOOL LoadMenu(LPCTSTR lpszResourceName);
    virtual BOOL LoadMenu(int nResource);
    BOOL LoadToolbar(UINT nToolBar);
    BOOL LoadToolbars(const UINT *arID,int n);
    void AddFromToolBar(CToolBar* pToolBar, int nResourceID);
    BOOL LoadFromToolBar(UINT nID,UINT nToolBar,int& xoffset);
    BOOL AddBitmapToImageList(CImageList *list,UINT nResourceID);
    static HBITMAP LoadSysColorBitmap(int nResourceId);
    void LoadCheckmarkBitmap(int unselect,int select); // custom check mark bitmaps

    // functions for appending a menu option, use the AppendMenu call (see above define)
    BOOL AppendMenuA(UINT nFlags,UINT nIDNewItem=0,const char *lpszNewItem=NULL,int nIconNormal=-1);
    BOOL AppendMenuA(UINT nFlags,UINT nIDNewItem,const char *lpszNewItem,CImageList *il,int xoffset);
    BOOL AppendMenuA(UINT nFlags,UINT nIDNewItem,const char *lpszNewItem,CBitmap *bmp);
    BOOL AppendMenuW(UINT nFlags,UINT nIDNewItem=0,wchar_t *lpszNewItem=NULL,int nIconNormal=-1);
    BOOL AppendMenuW(UINT nFlags,UINT nIDNewItem,wchar_t *lpszNewItem,CImageList *il,int xoffset);
    BOOL AppendMenuW(UINT nFlags,UINT nIDNewItem,wchar_t *lpszNewItem,CBitmap *bmp);
    BOOL AppendODMenuA(LPCSTR lpstrText,UINT nFlags = MF_OWNERDRAW,UINT nID = 0,int nIconNormal = -1);  
    BOOL AppendODMenuW(wchar_t *lpstrText,UINT nFlags = MF_OWNERDRAW,UINT nID = 0,int nIconNormal = -1);  
    BOOL AppendODMenuA(LPCSTR lpstrText,UINT nFlags,UINT nID,CImageList *il,int xoffset);
    BOOL AppendODMenuW(wchar_t *lpstrText,UINT nFlags,UINT nID,CImageList *il,int xoffset);

    // for appending a popup menu (see example application)
    BCMenu* AppendODPopupMenuA(LPCSTR lpstrText);
    BCMenu* AppendODPopupMenuW(wchar_t *lpstrText);

    // functions for inserting a menu option, use the InsertMenu call (see above define)
    BOOL InsertMenuA(UINT nPosition,UINT nFlags,UINT nIDNewItem=0,const char *lpszNewItem=NULL,int nIconNormal=-1);
    BOOL InsertMenuA(UINT nPosition,UINT nFlags,UINT nIDNewItem,const char *lpszNewItem,CImageList *il,int xoffset);
    BOOL InsertMenuA(UINT nPosition,UINT nFlags,UINT nIDNewItem,const char *lpszNewItem,CBitmap *bmp);
    BOOL InsertMenuW(UINT nPosition,UINT nFlags,UINT nIDNewItem=0,wchar_t *lpszNewItem=NULL,int nIconNormal=-1);
    BOOL InsertMenuW(UINT nPosition,UINT nFlags,UINT nIDNewItem,wchar_t *lpszNewItem,CImageList *il,int xoffset);
    BOOL InsertMenuW(UINT nPosition,UINT nFlags,UINT nIDNewItem,wchar_t *lpszNewItem,CBitmap *bmp);
    BOOL InsertODMenuA(UINT nPosition,LPCSTR lpstrText,UINT nFlags = MF_OWNERDRAW,UINT nID = 0,int nIconNormal = -1); 
    BOOL InsertODMenuW(UINT nPosition,wchar_t *lpstrText,UINT nFlags = MF_OWNERDRAW,UINT nID = 0,int nIconNormal = -1);  
    BOOL InsertODMenuA(UINT nPosition,LPCSTR lpstrText,UINT nFlags,UINT nID,CImageList *il,int xoffset);
    BOOL InsertODMenuW(UINT nPosition,wchar_t *lpstrText,UINT nFlags,UINT nID,CImageList *il,int xoffset);

    // functions for modifying a menu option, use the ModifyODMenu call (see above define)
    BOOL ModifyODMenuA(const char *lpstrText,UINT nID=0,int nIconNormal=-1);
    BOOL ModifyODMenuA(const char *lpstrText,UINT nID,CImageList *il,int xoffset);
    BOOL ModifyODMenuA(const char *lpstrText,UINT nID,CBitmap *bmp);
    BOOL ModifyODMenuA(const char *lpstrText,const char *OptionText,int nIconNormal);
    BOOL ModifyODMenuW(wchar_t *lpstrText,UINT nID=0,int nIconNormal=-1);
    BOOL ModifyODMenuW(wchar_t *lpstrText,UINT nID,CImageList *il,int xoffset);
    BOOL ModifyODMenuW(wchar_t *lpstrText,UINT nID,CBitmap *bmp);
    BOOL ModifyODMenuW(wchar_t *lpstrText,wchar_t *OptionText,int nIconNormal);
    // use this method for adding a solid/hatched colored square beside a menu option
    // courtesy of Warren Stevens
    BOOL ModifyODMenuA(const char *lpstrText,UINT nID,COLORREF fill,COLORREF border,int hatchstyle=-1,CSize *pSize=NULL);
    BOOL ModifyODMenuW(wchar_t *lpstrText,UINT nID,COLORREF fill,COLORREF border,int hatchstyle=-1,CSize *pSize=NULL);

    // for deleting and removing menu options
    BOOL    RemoveMenu(UINT uiId,UINT nFlags);
    BOOL    DeleteMenu(UINT uiId,UINT nFlags);
    // sPos means Seperator's position, since we have no way to find the seperator's position in the menu
    // we have to specify them when we call the RemoveMenu to make sure the unused seperators are removed;
    // sPos  = None no seperator removal;
    //       = Head  seperator in front of this menu item;
    //       = Tail  seperator right after this menu item;
    //       = Both  seperators at both ends;
    // remove the menu item based on their text, return -1 if not found, otherwise return the menu position;
    int RemoveMenu(char* pText, BC_Seperator sPos=BCMENU_NONE);
    int RemoveMenu(wchar_t* pText, BC_Seperator sPos=BCMENU_NONE);
    int DeleteMenu(char* pText, BC_Seperator sPos=BCMENU_NONE);
    int DeleteMenu(wchar_t* pText, BC_Seperator sPos=BCMENU_NONE);

    // Destoying
    virtual BOOL DestroyMenu();

    // function for retrieving and setting a menu options text (use this function
    // because it is ownerdrawn)
    BOOL GetMenuText(UINT id,CString &string,UINT nFlags = MF_BYPOSITION);
    BOOL SetMenuText(UINT id,CString string, UINT nFlags = MF_BYPOSITION);

    // Getting a submenu from it's name or position
    BCMenu* GetSubBCMenu(char* lpszSubMenuName);
    BCMenu* GetSubBCMenu(wchar_t* lpszSubMenuName);
    CMenu* GetSubMenu (LPCTSTR lpszSubMenuName);
    CMenu* GetSubMenu (int nPos);
    int GetMenuPosition(char* pText);
    int GetMenuPosition(wchar_t* pText);

    // Drawing: 
    virtual void DrawItem( LPDRAWITEMSTRUCT);  // Draw an item
    virtual void MeasureItem( LPMEASUREITEMSTRUCT );  // Measure an item

    // Static functions used for handling menu's in the mainframe
    static void UpdateMenu(CMenu *pmenu);
    static BOOL IsMenu(CMenu *submenu);
    static BOOL IsMenu(HMENU submenu);
    static LRESULT FindKeyboardShortcut(UINT nChar,UINT nFlags,CMenu *pMenu);

    // Function to set how menu is drawn, either original or XP style
    static void SetMenuDrawMode(UINT mode){
        BCMenu::original_drawmode=mode;
        BCMenu::xp_drawmode=mode;
    };
    // Function to set how disabled items are drawn (mode=FALSE means they are not drawn selected)
    static void SetSelectDisableMode(BOOL mode){
        BCMenu::original_select_disabled=mode;
        BCMenu::xp_select_disabled=mode;
    };
    static int BCMenu::GetMenuDrawMode(void);
    static BOOL BCMenu::GetSelectDisableMode(void);

    // how the bitmaps are drawn in XP Luna mode
    static void SetXPBitmap3D(BOOL val){
        BCMenu::xp_draw_3D_bitmaps=val;
    };
    static BOOL GetXPBitmap3D(void){return BCMenu::xp_draw_3D_bitmaps;}

    // Customizing:
    // Set icon size
    void SetIconSize (int, int); 
    // set the color in the bitmaps that is the background transparent color
    void SetBitmapBackground(COLORREF color);
    void UnSetBitmapBackground(void);
    // obsolete functions for setting how menu images are dithered for disabled menu options
    BOOL GetDisableOldStyle(void);
    void SetDisableOldStyle(void);
    void UnSetDisableOldStyle(void);
    static COLORREF LightenColor(COLORREF col,double factor);
    static COLORREF DarkenColor(COLORREF col,double factor);

// Miscellaneous Protected Member functions
protected:
    static BOOL IsNewShell(void);
    static BOOL IsWinXPLuna(void);
    static BOOL IsLunaMenuStyle(void);
    static BOOL IsWindowsClassicTheme(void);
    BCMenuData *BCMenu::FindMenuItem(UINT nID);
    BCMenu *FindMenuOption(int nId,int& nLoc);
    BCMenu *FindAnotherMenuOption(int nId,int& nLoc,CArray<BCMenu*,BCMenu*>&bcsubs,
                                  CArray<int,int&>&bclocs);
    BCMenuData *FindMenuOption(wchar_t *lpstrText);
    void InsertSpaces(void);
    void DrawCheckMark(CDC *pDC,int x,int y,COLORREF color);
    void DrawRadioDot(CDC *pDC,int x,int y,COLORREF color);
    BCMenuData *NewODMenu(UINT pos,UINT nFlags,UINT nID,CString string);
    void SynchronizeMenu(void);
    void BCMenu::InitializeMenuList(int value);
    void BCMenu::DeleteMenuList(void);
    BCMenuData *BCMenu::FindMenuList(UINT nID);
    void DrawItem_Win9xNT2000 (LPDRAWITEMSTRUCT lpDIS);
    void DrawItem_WinXP (LPDRAWITEMSTRUCT lpDIS);
    BOOL Draw3DCheckmark(CDC *dc, const CRect& rc,BOOL bSelected,HBITMAP hbmCheck);
    BOOL DrawXPCheckmark(CDC *dc, const CRect& rc, HBITMAP hbmCheck,COLORREF &colorout);
    void DitherBlt(HDC hdcDest, int nXDest, int nYDest, int nWidth, 
        int nHeight, HBITMAP hbm, int nXSrc, int nYSrc,COLORREF bgcolor);
    void DitherBlt2(CDC *drawdc, int nXDest, int nYDest, int nWidth, 
        int nHeight, CBitmap &bmp, int nXSrc, int nYSrc,COLORREF bgcolor);
    BOOL GetBitmapFromImageList(CDC* pDC,CImageList *imglist,int nIndex,CBitmap &bmp);
    BOOL ImageListDuplicate(CImageList *il,int xoffset,CImageList *newlist);
    static WORD NumBitmapColors(LPBITMAPINFOHEADER lpBitmap);
    void ColorBitmap(CDC* pDC, CBitmap& bmp,CSize bitmap_size,CSize icon_size,COLORREF fill,COLORREF border,int hatchstyle=-1);
    void RemoveTopLevelOwnerDraw(void);
    int GetMenuStart(void);
    void GetFadedBitmap(CBitmap &bmp);
    void GetShadowBitmap(CBitmap &bmp);
    int AddToGlobalImageList(CImageList *il,int xoffset,int nID);
    int GlobalImageListOffset(int nID);
    BOOL CanDraw3DImageList(int offset);

// Member Variables
protected:
    CTypedPtrArray<CPtrArray, BCMenuData*> m_MenuList;  // Stores list of menu items 
    // When loading an owner-drawn menu using a Resource, BCMenu must keep track of
    // the popup menu's that it creates. Warning, this list *MUST* be destroyed
    // last item first :)
    CTypedPtrArray<CPtrArray, HMENU>  m_SubMenus;  // Stores list of sub-menus 
    // Stores a list of all BCMenu's ever created 
    static CTypedPtrArray<CPtrArray, HMENU>  m_AllSubMenus;
    // Global ImageList
    static CImageList m_AllImages;
    static CArray<int,int&> m_AllImagesID;
    // icon size
    int m_iconX,m_iconY;
    COLORREF m_bitmapBackground;
    BOOL m_bitmapBackgroundFlag;
    BOOL disable_old_style;
    static UINT original_drawmode;
    static BOOL original_select_disabled;
    static UINT xp_drawmode;
    static BOOL xp_select_disabled;
    static BOOL xp_draw_3D_bitmaps;
    CImageList *checkmaps;
    BOOL checkmapsshare;
    int m_selectcheck;
    int m_unselectcheck;
    BOOL m_bDynIcons;
    BOOL m_loadmenu;
}; 

class BCMenuToolBar : public CToolBar{
public:
    BCMenuToolBar() : CToolBar() {m_iconX=m_iconY=0;}
    BOOL LoadToolBar(LPCTSTR lpszResourceName);
    BOOL LoadToolBar(UINT nIDResource){
        return LoadToolBar(MAKEINTRESOURCE(nIDResource));
    }
    BOOL LoadBitmap(LPCTSTR lpszResourceName);
    void GetIconSize(int &iconx,int &icony){iconx=m_iconX;icony=m_iconY;}
protected:
    int m_iconX,m_iconY;
};

#define BCMENU_USE_MEMDC

#ifdef BCMENU_USE_MEMDC
//////////////////////////////////////////////////
// BCMenuMemDC - memory DC
//
// Author: Keith Rule
// Email:  keithr@europa.com
// Copyright 1996-1997, Keith Rule
//
// You may freely use or modify this code provided this
// Copyright is included in all derived versions.
//
// History - 10/3/97 Fixed scrolling bug.
//                   Added print support.
//           25 feb 98 - fixed minor assertion bug
//
// This class implements a memory Device Context

class BCMenuMemDC : public CDC
{
public:

    // constructor sets up the memory DC
    BCMenuMemDC(CDC* pDC,LPCRECT lpSrcRect) : CDC()
    {
        ASSERT(pDC != NULL);

        m_rect.CopyRect(lpSrcRect);
        m_pDC = pDC;
        m_pOldBitmap = NULL;
        m_bMemDC = !pDC->IsPrinting();

        if (m_bMemDC)    // Create a Memory DC
        {
            CreateCompatibleDC(pDC);
            m_bitmap.CreateCompatibleBitmap(pDC, m_rect.Width(), m_rect.Height());
            m_pOldBitmap = SelectObject(&m_bitmap);
            SetWindowOrg(m_rect.left, m_rect.top);
        }
        else        // Make a copy of the relevent parts of the current DC for printing
        {
            m_bPrinting = pDC->m_bPrinting;
            m_hDC       = pDC->m_hDC;
            m_hAttribDC = pDC->m_hAttribDC;
        }
    }

    // Destructor copies the contents of the mem DC to the original DC
    ~BCMenuMemDC()
    {
        if (m_bMemDC) 
        {    
            // Copy the offscreen bitmap onto the screen.
            m_pDC->BitBlt(m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(),
                          this, m_rect.left, m_rect.top, SRCCOPY);

            //Swap back the original bitmap.
            SelectObject(m_pOldBitmap);
        } else {
            // All we need to do is replace the DC with an illegal value,
            // this keeps us from accidently deleting the handles associated with
            // the CDC that was passed to the constructor.
            m_hDC = m_hAttribDC = NULL;
        }
    }

    // Allow usage as a pointer
    BCMenuMemDC* operator->() {return this;}

    // Allow usage as a pointer
    operator BCMenuMemDC*() {return this;}

private:
    CBitmap  m_bitmap;      // Offscreen bitmap
    CBitmap* m_pOldBitmap;  // bitmap originally found in BCMenuMemDC
    CDC*     m_pDC;         // Saves CDC passed in constructor
    CRect    m_rect;        // Rectangle of drawing area.
    BOOL     m_bMemDC;      // TRUE if CDC really is a Memory DC.
};

#endif

#endif

//*************************************************************************

//*************************************************************************
// BCMenu.cpp : implementation file
// Version : 3.02
// Date : March 2002
// Author : Brent Corkum
// Email :  corkum@rocscience.com
// Latest Version : http://www.rocscience.com/~corkum/BCMenu.html
// 
// Bug Fixes and portions of code supplied by:
//
// Ben Ashley,Girish Bharadwaj,Jean-Edouard Lachand-Robert,
// Robert Edward Caldecott,Kenny Goers,Leonardo Zide,
// Stefan Kuhr,Reiner Jung,Martin Vladic,Kim Yoo Chul,
// Oz Solomonovich,Tongzhe Cui,Stephane Clog,Warren Stevens,
// Damir Valiulin,David Kinder,Marc Loiry
//
// You are free to use/modify this code but leave this header intact.
// This class is public domain so you are free to use it any of
// your applications (Freeware,Shareware,Commercial). All I ask is
// that you let me know so that if you have a real winner I can
// brag to my buddies that some of my code is in your app. I also
// wouldn't mind if you sent me a copy of your application since I
// like to play with new stuff.
//*************************************************************************

#include "stdafx.h"        // Standard windows header file
#include "BCMenu.h"        // BCMenu class declaration
#include <afxpriv.h>       //SK: makes A2W and other spiffy AFX macros work

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define BCMENU_GAP 1
#ifndef OBM_CHECK
#define OBM_CHECK 32760 // from winuser.h
#endif

#if _MFC_VER <0x400
#error This code does not work on Versions of MFC prior to 4.0
#endif

static CPINFO CPInfo;
// how the menu's are drawn in win9x/NT/2000
UINT BCMenu::original_drawmode=BCMENU_DRAWMODE_ORIGINAL;
BOOL BCMenu::original_select_disabled=TRUE;
// how the menu's are drawn in winXP
UINT BCMenu::xp_drawmode=BCMENU_DRAWMODE_XP;
BOOL BCMenu::xp_select_disabled=FALSE;
BOOL BCMenu::xp_draw_3D_bitmaps=TRUE;

CImageList BCMenu::m_AllImages;
CArray<int,int&> BCMenu::m_AllImagesID;

enum Win32Type{
    Win32s,
    WinNT3,
    Win95,
    Win98,
    WinME,
    WinNT4,
    Win2000,
    WinXP
};


Win32Type IsShellType()
{
    Win32Type  ShellType;
    DWORD winVer;
    OSVERSIONINFO *osvi;

    winVer=GetVersion();
    if(winVer<0x80000000){/*NT */
        ShellType=WinNT3;
        osvi= (OSVERSIONINFO *)malloc(sizeof(OSVERSIONINFO));
        if (osvi!=NULL){
            memset(osvi,0,sizeof(OSVERSIONINFO));
            osvi->dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
            GetVersionEx(osvi);
            if(osvi->dwMajorVersion==4L)ShellType=WinNT4;
            else if(osvi->dwMajorVersion==5L&&osvi->dwMinorVersion==0L)ShellType=Win2000;
            else if(osvi->dwMajorVersion==5L&&osvi->dwMinorVersion==1L)ShellType=WinXP;
            free(osvi);
        }
    }
    else if  (LOBYTE(LOWORD(winVer))<4)
        ShellType=Win32s;
    else{
        ShellType=Win95;
        osvi= (OSVERSIONINFO *)malloc(sizeof(OSVERSIONINFO));
        if (osvi!=NULL){
            memset(osvi,0,sizeof(OSVERSIONINFO));
            osvi->dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
            GetVersionEx(osvi);
            if(osvi->dwMajorVersion==4L&&osvi->dwMinorVersion==10L)ShellType=Win98;
            else if(osvi->dwMajorVersion==4L&&osvi->dwMinorVersion==90L)ShellType=WinME;
            free(osvi);
        }
    }
    return ShellType;
}

static Win32Type g_Shell=IsShellType();

void BCMenuData::SetAnsiString(LPCSTR szAnsiString)
{
    USES_CONVERSION;
    SetWideString(A2W(szAnsiString));  //SK:  see MFC Tech Note 059
}

CString BCMenuData::GetString(void)//returns the menu text in ANSI or UNICODE
//depending on the MFC-Version we are using
{
    CString strText;
    if (m_szMenuText)
    {
#ifdef UNICODE
        strText = m_szMenuText;
#else
        USES_CONVERSION;
        strText=W2A(m_szMenuText);     //SK:  see MFC Tech Note 059
#endif    
    }
    return strText;
}

CTypedPtrArray<CPtrArray, HMENU> BCMenu::m_AllSubMenus;  // Stores list of all sub-menus

IMPLEMENT_DYNAMIC( BCMenu, CMenu )

/*
===============================================================================
BCMenu::BCMenu()
BCMenu::~BCMenu()
-----------------

Constructor and Destructor.

===============================================================================
*/

BCMenu::BCMenu()
{
    m_bDynIcons = FALSE;     // O.S. - no dynamic icons by default
    disable_old_style=FALSE;
    m_iconX = 16;            // Icon sizes default to 16 x 16
    m_iconY = 15;            // ...
    m_selectcheck = -1;
    m_unselectcheck = -1;
    checkmaps=NULL;
    checkmapsshare=FALSE;
    // set the color used for the transparent background in all bitmaps
    m_bitmapBackground=/*RGB(0,0,0);*/RGB(192,192,192); //gray
    m_bitmapBackgroundFlag=FALSE;
    GetCPInfo(CP_ACP,&CPInfo);
    m_loadmenu=FALSE;
}


BCMenu::~BCMenu()
{
    DestroyMenu();
}

BOOL BCMenu::IsNewShell ()
{
    return (g_Shell>=Win95);
}

BOOL BCMenu::IsWinXPLuna()
{
    if(g_Shell==WinXP){
        if(IsWindowsClassicTheme())return(FALSE);
        else return(TRUE);
    }
    return(FALSE);
}

BOOL BCMenu::IsLunaMenuStyle()
{
    if(IsWinXPLuna()){
        if(xp_drawmode==BCMENU_DRAWMODE_XP)return(TRUE);
    }
    else{
        if(original_drawmode==BCMENU_DRAWMODE_XP)return(TRUE);
    }
    return(FALSE);
}

BCMenuData::~BCMenuData()
{
    if(bitmap)
        delete(bitmap);

    delete[] m_szMenuText; //Need not check for NULL because ANSI X3J16 allows "delete NULL"
}


void BCMenuData::SetWideString(const wchar_t *szWideString)
{
    delete[] m_szMenuText;//Need not check for NULL because ANSI X3J16 allows "delete NULL"

    if (szWideString)
    {
        m_szMenuText = new wchar_t[sizeof(wchar_t)*(wcslen(szWideString)+1)];
        if (m_szMenuText)
            wcscpy(m_szMenuText,szWideString);
    }
    else
        m_szMenuText=NULL;//set to NULL so we need not bother about dangling non-NULL Ptrs
}

BOOL BCMenu::IsMenu(CMenu *submenu)
{
    int m;
    int numSubMenus = m_AllSubMenus.GetUpperBound();
    for(m=0;m<=numSubMenus;++m){
        if(submenu->m_hMenu==m_AllSubMenus[m])return(TRUE);
    }
    return(FALSE);
}

BOOL BCMenu::IsMenu(HMENU submenu)
{
    int m;
    int numSubMenus = m_AllSubMenus.GetUpperBound();
    for(m=0;m<=numSubMenus;++m){
        if(submenu==m_AllSubMenus[m])return(TRUE);
    }
    return(FALSE);
}

BOOL BCMenu::DestroyMenu()
{
    // Destroy Sub menus:
    int m,n;
    int numAllSubMenus = m_AllSubMenus.GetUpperBound();
    for(n = numAllSubMenus; n>= 0; n--){
        if(m_AllSubMenus[n]==this->m_hMenu)m_AllSubMenus.RemoveAt(n);
    }
    int numSubMenus = m_SubMenus.GetUpperBound();
    for(m = numSubMenus; m >= 0; m--){
        numAllSubMenus = m_AllSubMenus.GetUpperBound();
        for(n = numAllSubMenus; n>= 0; n--){
            if(m_AllSubMenus[n]==m_SubMenus[m])m_AllSubMenus.RemoveAt(n);
        }
        CMenu *ptr=FromHandle(m_SubMenus[m]);
        BOOL flag=ptr->IsKindOf(RUNTIME_CLASS( BCMenu ));
        if(flag)delete((BCMenu *)ptr);
    }
    m_SubMenus.RemoveAll();
    // Destroy menu data
    int numItems = m_MenuList.GetUpperBound();
    for(m = 0; m <= numItems; m++)delete(m_MenuList[m]);
    m_MenuList.RemoveAll();
    if(checkmaps&&!checkmapsshare){
        delete checkmaps;
        checkmaps=NULL;
    }
    // Call base-class implementation last:
    return(CMenu::DestroyMenu());
};

int BCMenu::GetMenuDrawMode(void)
{
    if(IsWinXPLuna())return(xp_drawmode);
    return(original_drawmode);
}

BOOL BCMenu::GetSelectDisableMode(void)
{
    if(IsLunaMenuStyle())return(xp_select_disabled);
    return(original_select_disabled);
}


/*
==========================================================================
void BCMenu::DrawItem(LPDRAWITEMSTRUCT)
---------------------------------------

  Called by the framework when a particular item needs to be drawn.  We
  overide this to draw the menu item in a custom-fashion, including icons
  and the 3D rectangle bar.
  ==========================================================================
*/

void BCMenu::DrawItem (LPDRAWITEMSTRUCT lpDIS)
{
    ASSERT(lpDIS != NULL);
    CDC* pDC = CDC::FromHandle(lpDIS->hDC);
    if(pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE)DrawItem_Win9xNT2000(lpDIS);
    else{
        if(IsWinXPLuna()){
            if(xp_drawmode==BCMENU_DRAWMODE_XP) DrawItem_WinXP(lpDIS);
            else DrawItem_Win9xNT2000(lpDIS);
        }
        else{
            if(original_drawmode==BCMENU_DRAWMODE_XP) DrawItem_WinXP(lpDIS);
            else DrawItem_Win9xNT2000(lpDIS);
        }    
    }
}

void BCMenu::DrawItem_Win9xNT2000 (LPDRAWITEMSTRUCT lpDIS)
{
    ASSERT(lpDIS != NULL);
    CDC* pDC = CDC::FromHandle(lpDIS->hDC);
    CRect rect;
    UINT state = (((BCMenuData*)(lpDIS->itemData))->nFlags);
    CBrush m_brBackground;
    COLORREF m_clrBack;

    if(IsWinXPLuna())m_clrBack=GetSysColor(COLOR_3DFACE);
    else m_clrBack=GetSysColor(COLOR_MENU);

    m_brBackground.CreateSolidBrush(m_clrBack);

    // remove the selected bit if it's grayed out
    if(lpDIS->itemState & ODS_GRAYED&&!original_select_disabled){
        if(lpDIS->itemState & ODS_SELECTED)lpDIS->itemState=lpDIS->itemState & ~ODS_SELECTED;
    }

    if(state & MF_SEPARATOR){
        rect.CopyRect(&lpDIS->rcItem);
        pDC->FillRect (rect,&m_brBackground);
        rect.top += (rect.Height()>>1);
        pDC->DrawEdge(&rect,EDGE_ETCHED,BF_TOP);
    }
    else{
        CRect rect2;
        BOOL standardflag=FALSE,selectedflag=FALSE,disableflag=FALSE;
        BOOL checkflag=FALSE;
        COLORREF crText = GetSysColor(COLOR_MENUTEXT);
        CBrush m_brSelect;
        CPen m_penBack;
        int x0,y0,dy;
        int nIconNormal=-1,xoffset=-1,global_offset=-1;
        CImageList *bitmap=NULL;

        // set some colors
        m_penBack.CreatePen (PS_SOLID,0,m_clrBack);
        m_brSelect.CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT));

        // draw the colored rectangle portion

        rect.CopyRect(&lpDIS->rcItem);
        rect2=rect;

        // draw the up/down/focused/disabled state

        UINT state = lpDIS->itemState;
        CString strText;

        if(lpDIS->itemData != NULL){
            nIconNormal = (((BCMenuData*)(lpDIS->itemData))->menuIconNormal);
            xoffset = (((BCMenuData*)(lpDIS->itemData))->xoffset);
            global_offset = (((BCMenuData*)(lpDIS->itemData))->global_offset);
            bitmap = (((BCMenuData*)(lpDIS->itemData))->bitmap);
            strText = ((BCMenuData*) (lpDIS->itemData))->GetString();

            if(nIconNormal<0&&global_offset>=0){
                xoffset=global_offset;
                nIconNormal=0;
                bitmap = &m_AllImages;
            }

            if(state&ODS_CHECKED && nIconNormal<0){
                if(state&ODS_SELECTED && m_selectcheck>0)checkflag=TRUE;
                else if(m_unselectcheck>0) checkflag=TRUE;
            }
            else if(nIconNormal != -1){
                standardflag=TRUE;
                if(state&ODS_SELECTED && !(state&ODS_GRAYED))selectedflag=TRUE;
                else if(state&ODS_GRAYED) disableflag=TRUE;
            }
        }
        else{
            strText.Empty();
        }

        if(state&ODS_SELECTED){ // draw the down edges

            CPen *pOldPen = pDC->SelectObject (&m_penBack);

            // You need only Text highlight and thats what you get

            if(checkflag||standardflag||selectedflag||disableflag||state&ODS_CHECKED)
                rect2.SetRect(rect.left+m_iconX+4+BCMENU_GAP,rect.top,rect.right,rect.bottom);
            pDC->FillRect (rect2,&m_brSelect);

            pDC->SelectObject (pOldPen);
            crText = GetSysColor(COLOR_HIGHLIGHTTEXT);
        }
        else {
            CPen *pOldPen = pDC->SelectObject (&m_penBack);
            pDC->FillRect (rect,&m_brBackground);
            pDC->SelectObject (pOldPen);

            // draw the up edges    
            pDC->Draw3dRect (rect,m_clrBack,m_clrBack);
        }

        // draw the text if there is any
        //We have to paint the text only if the image is nonexistant

        dy = (rect.Height()-4-m_iconY)/2;
        dy = dy<0 ? 0 : dy;

        if(checkflag||standardflag||selectedflag||disableflag){
            rect2.SetRect(rect.left+1,rect.top+1+dy,rect.left+m_iconX+3,
                rect.top+m_iconY+3+dy);
            pDC->Draw3dRect (rect2,m_clrBack,m_clrBack);
            if(checkflag && checkmaps){
                pDC->FillRect (rect2,&m_brBackground);
                rect2.SetRect(rect.left,rect.top+dy,rect.left+m_iconX+4,
                    rect.top+m_iconY+4+dy);

                pDC->Draw3dRect (rect2,m_clrBack,m_clrBack);
                CPoint ptImage(rect.left+2,rect.top+2+dy);

                if(state&ODS_SELECTED)checkmaps->Draw(pDC,1,ptImage,ILD_TRANSPARENT);
                else checkmaps->Draw(pDC,0,ptImage,ILD_TRANSPARENT);
            }
            else if(disableflag){
                if(!selectedflag){
                    CBitmap bitmapstandard;
                    GetBitmapFromImageList(pDC,bitmap,xoffset,bitmapstandard);
                    rect2.SetRect(rect.left,rect.top+dy,rect.left+m_iconX+4,
                        rect.top+m_iconY+4+dy);
                    pDC->Draw3dRect (rect2,m_clrBack,m_clrBack);
                    if(disable_old_style)
                        DitherBlt(lpDIS->hDC,rect.left+2,rect.top+2+dy,m_iconX,m_iconY,
                        (HBITMAP)(bitmapstandard),0,0,m_clrBack);
                    else
                        DitherBlt2(pDC,rect.left+2,rect.top+2+dy,m_iconX,m_iconY,
                        bitmapstandard,0,0,m_clrBack);
                    bitmapstandard.DeleteObject();
                }
            }
            else if(selectedflag){
                pDC->FillRect (rect2,&m_brBackground);
                rect2.SetRect(rect.left,rect.top+dy,rect.left+m_iconX+4,
                    rect.top+m_iconY+4+dy);
                if (IsNewShell()){
                    if(state&ODS_CHECKED)
                        pDC->Draw3dRect(rect2,GetSysColor(COLOR_3DSHADOW),
                        GetSysColor(COLOR_3DHILIGHT));
                    else
                        pDC->Draw3dRect(rect2,GetSysColor(COLOR_3DHILIGHT),
                        GetSysColor(COLOR_3DSHADOW));
                }
                CPoint ptImage(rect.left+2,rect.top+2+dy);
                if(bitmap)bitmap->Draw(pDC,xoffset,ptImage,ILD_TRANSPARENT);
            }
            else{
                if(state&ODS_CHECKED){
                    CBrush brush;
                    COLORREF col = m_clrBack;
                    col = LightenColor(col,0.6);
                    brush.CreateSolidBrush(col);
                    pDC->FillRect(rect2,&brush);
                    brush.DeleteObject();
                    rect2.SetRect(rect.left,rect.top+dy,rect.left+m_iconX+4,
                        rect.top+m_iconY+4+dy);
                    if (IsNewShell())
                        pDC->Draw3dRect(rect2,GetSysColor(COLOR_3DSHADOW),
                        GetSysColor(COLOR_3DHILIGHT));
                }
                else{
                    pDC->FillRect (rect2,&m_brBackground);
                    rect2.SetRect(rect.left,rect.top+dy,rect.left+m_iconX+4,
                        rect.top+m_iconY+4+dy);
                    pDC->Draw3dRect (rect2,m_clrBack,m_clrBack);
                }
                CPoint ptImage(rect.left+2,rect.top+2+dy);
                if(bitmap)bitmap->Draw(pDC,xoffset,ptImage,ILD_TRANSPARENT);
            }
        }
        if(nIconNormal<0 && state&ODS_CHECKED && !checkflag){
            rect2.SetRect(rect.left+1,rect.top+2+dy,rect.left+m_iconX+1,
                rect.top+m_iconY+2+dy);
            CMenuItemInfo info;
            info.fMask = MIIM_CHECKMARKS;
            ::GetMenuItemInfo((HMENU)lpDIS->hwndItem,lpDIS->itemID,
                MF_BYCOMMAND, &info);
            if(state&ODS_CHECKED || info.hbmpUnchecked) {
                Draw3DCheckmark(pDC, rect2, state&ODS_SELECTED,
                    state&ODS_CHECKED ? info.hbmpChecked :
                info.hbmpUnchecked);
            }
        }

        //This is needed always so that we can have the space for check marks

        x0=rect.left;y0=rect.top;
        rect.left = rect.left + m_iconX + 8 + BCMENU_GAP; 

        if(!strText.IsEmpty()){

            CRect rectt(rect.left,rect.top-1,rect.right,rect.bottom-1);

            //   Find tabs

            CString leftStr,rightStr;
            leftStr.Empty();rightStr.Empty();
            int tablocr=strText.ReverseFind(_T('\t'));
            if(tablocr!=-1){
                rightStr=strText.Mid(tablocr+1);
                leftStr=strText.Left(strText.Find(_T('\t')));
                rectt.right-=m_iconX;
            }
            else leftStr=strText;

            int iOldMode = pDC->GetBkMode();
            pDC->SetBkMode( TRANSPARENT);

            // Draw the text in the correct colour:

            UINT nFormat  = DT_LEFT|DT_SINGLELINE|DT_VCENTER;
            UINT nFormatr = DT_RIGHT|DT_SINGLELINE|DT_VCENTER;
            if(!(lpDIS->itemState & ODS_GRAYED)){
                pDC->SetTextColor(crText);
                pDC->DrawText (leftStr,rectt,nFormat);
                if(tablocr!=-1) pDC->DrawText (rightStr,rectt,nFormatr);
            }
            else{

                // Draw the disabled text
                if(!(state & ODS_SELECTED)){
                    RECT offset = *rectt;
                    offset.left+=1;
                    offset.right+=1;
                    offset.top+=1;
                    offset.bottom+=1;
                    pDC->SetTextColor(GetSysColor(COLOR_BTNHILIGHT));
                    pDC->DrawText(leftStr,&offset, nFormat);
                    if(tablocr!=-1) pDC->DrawText (rightStr,&offset,nFormatr);
                    pDC->SetTextColor(GetSysColor(COLOR_GRAYTEXT));
                    pDC->DrawText(leftStr,rectt, nFormat);
                    if(tablocr!=-1) pDC->DrawText (rightStr,rectt,nFormatr);
                }
                else{
                    // And the standard Grey text:
                    pDC->SetTextColor(m_clrBack);
                    pDC->DrawText(leftStr,rectt, nFormat);
                    if(tablocr!=-1) pDC->DrawText (rightStr,rectt,nFormatr);
                }
            }
            pDC->SetBkMode( iOldMode );
        }

        m_penBack.DeleteObject();
        m_brSelect.DeleteObject();
    }
    m_brBackground.DeleteObject();
}

COLORREF BCMenu::LightenColor(COLORREF col,double factor)
{
    if(factor>0.0&&factor<=1.0){
        BYTE red,green,blue,lightred,lightgreen,lightblue;
        red = GetRValue(col);
        green = GetGValue(col);
        blue = GetBValue(col);
        lightred = (BYTE)((factor*(255-red)) + red);
        lightgreen = (BYTE)((factor*(255-green)) + green);
        lightblue = (BYTE)((factor*(255-blue)) + blue);
        col = RGB(lightred,lightgreen,lightblue);
    }
    return(col);
}

COLORREF BCMenu::DarkenColor(COLORREF col,double factor)
{
    if(factor>0.0&&factor<=1.0){
        BYTE red,green,blue,lightred,lightgreen,lightblue;
        red = GetRValue(col);
        green = GetGValue(col);
        blue = GetBValue(col);
        lightred = (BYTE)(red-(factor*red));
        lightgreen = (BYTE)(green-(factor*green));
        lightblue = (BYTE)(blue-(factor*blue));
        col = RGB(lightred,lightgreen,lightblue);
    }
    return(col);
}


void BCMenu::DrawItem_WinXP (LPDRAWITEMSTRUCT lpDIS)
{
    ASSERT(lpDIS != NULL);
    CDC* pDC = CDC::FromHandle(lpDIS->hDC);
#ifdef BCMENU_USE_MEMDC
    BCMenuMemDC *pMemDC=NULL;
#endif
    CRect rect,rect2;
    UINT state = (((BCMenuData*)(lpDIS->itemData))->nFlags);
    COLORREF m_newclrBack=GetSysColor(COLOR_3DFACE);
    COLORREF m_clrBack=GetSysColor(COLOR_WINDOW);
    CFont m_fontMenu,*pFont=NULL;
    LOGFONT m_lf;
    if(!IsWinXPLuna())m_newclrBack=LightenColor(m_newclrBack,0.25);
    CBrush m_newbrBackground,m_brBackground;
    m_brBackground.CreateSolidBrush(m_clrBack);
    m_newbrBackground.CreateSolidBrush(m_newclrBack);
    int BCMENU_PAD=4;
    if(xp_draw_3D_bitmaps)BCMENU_PAD=7;
    int barwidth=m_iconX+BCMENU_PAD;

    // remove the selected bit if it's grayed out
    if(lpDIS->itemState & ODS_GRAYED&&!xp_select_disabled){
        if(lpDIS->itemState & ODS_SELECTED)lpDIS->itemState=lpDIS->itemState & ~ODS_SELECTED;
#ifdef BCMENU_USE_MEMDC
        pMemDC=new BCMenuMemDC(pDC,&lpDIS->rcItem);
        pDC = pMemDC;
        ZeroMemory ((PVOID) &m_lf,sizeof (LOGFONT));
        NONCLIENTMETRICS nm;
        nm.cbSize = sizeof (NONCLIENTMETRICS);
        VERIFY (SystemParametersInfo(SPI_GETNONCLIENTMETRICS,nm.cbSize,&nm,0)); 
        m_lf =  nm.lfMenuFont;
        m_fontMenu.CreateFontIndirect (&m_lf);
        pFont = pDC->SelectObject (&m_fontMenu);
#endif

    }

    if(state & MF_SEPARATOR){
        rect.CopyRect(&lpDIS->rcItem);
        pDC->FillRect (rect,&m_brBackground);
        rect2.SetRect(rect.left,rect.top,rect.left+barwidth,rect.bottom);
        rect.top+=rect.Height()>>1;
        rect.left = rect2.right+BCMENU_PAD;
        pDC->DrawEdge(&rect,EDGE_ETCHED,BF_TOP);
        pDC->FillRect (rect2,&m_newbrBackground);
        pDC->Draw3dRect (rect2,m_newclrBack,m_newclrBack);
    }
    else{
        BOOL standardflag=FALSE,selectedflag=FALSE,disableflag=FALSE;
        BOOL checkflag=FALSE;
        COLORREF crText = GetSysColor(COLOR_MENUTEXT);
        COLORREF crSelect = GetSysColor(COLOR_HIGHLIGHT);
        COLORREF crSelectFill;
        if(!IsWinXPLuna())crSelectFill=LightenColor(crSelect,0.85);
        else crSelectFill=LightenColor(crSelect,0.7);
        CBrush m_brSelect;
        CPen m_penBack;
        int x0,y0,dx,dy;
        int nIconNormal=-1,xoffset=-1,global_offset=-1;
        int faded_offset=1,shadow_offset=2;
        CImageList *bitmap=NULL;
        BOOL CanDraw3D=FALSE;

        // set some colors
        m_penBack.CreatePen (PS_SOLID,0,m_clrBack);
        m_brSelect.CreateSolidBrush(crSelectFill);

        // draw the colored rectangle portion

        rect.CopyRect(&lpDIS->rcItem);
        rect2=rect;

        // draw the up/down/focused/disabled state

        UINT state = lpDIS->itemState;
        CString strText;

        if(lpDIS->itemData != NULL){
            nIconNormal = (((BCMenuData*)(lpDIS->itemData))->menuIconNormal);
            xoffset = (((BCMenuData*)(lpDIS->itemData))->xoffset);
            bitmap = (((BCMenuData*)(lpDIS->itemData))->bitmap);
            strText = ((BCMenuData*) (lpDIS->itemData))->GetString();
            global_offset = (((BCMenuData*)(lpDIS->itemData))->global_offset);

            if(xoffset==0&&xp_draw_3D_bitmaps&&bitmap&&bitmap->GetImageCount()>2)CanDraw3D=TRUE;

            if(nIconNormal<0&&xoffset<0&&global_offset>=0){
                xoffset=global_offset;
                nIconNormal=0;
                bitmap = &m_AllImages;
                if(xp_draw_3D_bitmaps&&CanDraw3DImageList(global_offset)){
                    CanDraw3D=TRUE;
                    faded_offset=global_offset+1;
                    shadow_offset=global_offset+2;
                }
            }


            if(state&ODS_CHECKED && nIconNormal<0){
                if(state&ODS_SELECTED && m_selectcheck>0)checkflag=TRUE;
                else if(m_unselectcheck>0) checkflag=TRUE;
            }
            else if(nIconNormal != -1){
                standardflag=TRUE;
                if(state&ODS_SELECTED && !(state&ODS_GRAYED))selectedflag=TRUE;
                else if(state&ODS_GRAYED) disableflag=TRUE;
            }
        }
        else{
            strText.Empty();
        }

        if(state&ODS_SELECTED){ // draw the down edges

            CPen *pOldPen = pDC->SelectObject (&m_penBack);

            pDC->FillRect (rect,&m_brSelect);
            pDC->Draw3dRect (rect,crSelect,crSelect);

            pDC->SelectObject (pOldPen);
        }
        else {
            rect2.SetRect(rect.left,rect.top,rect.left+barwidth,rect.bottom);
            CPen *pOldPen = pDC->SelectObject (&m_penBack);
            pDC->FillRect (rect,&m_brBackground);
            pDC->FillRect (rect2,&m_newbrBackground);
            pDC->SelectObject (pOldPen);

            // draw the up edges

            pDC->Draw3dRect (rect,m_clrBack,m_clrBack);
            pDC->Draw3dRect (rect2,m_newclrBack,m_newclrBack);
        }

        // draw the text if there is any
        //We have to paint the text only if the image is nonexistant

        dy = (int)(0.5+(rect.Height()-m_iconY)/2.0);
        dy = dy<0 ? 0 : dy;
        dx = (int)(0.5+(barwidth-m_iconX)/2.0);
        dx = dx<0 ? 0 : dx;

        if(checkflag||standardflag||selectedflag||disableflag){
            rect2.SetRect(rect.left+1,rect.top+1,rect.left+barwidth-1,
                rect.bottom-1);
            if(checkflag && checkmaps){
                pDC->FillRect (rect2,&m_newbrBackground);
                CPoint ptImage(rect.left+dx,rect.top+dy);        
                if(state&ODS_SELECTED)checkmaps->Draw(pDC,1,ptImage,ILD_TRANSPARENT);
                else checkmaps->Draw(pDC,0,ptImage,ILD_TRANSPARENT);
            }
            else if(disableflag){
                if(!selectedflag){
                    CBitmap bitmapstandard;
                    GetBitmapFromImageList(pDC,bitmap,xoffset,bitmapstandard);
                    COLORREF transparentcol=m_newclrBack;
                    if(state&ODS_SELECTED)transparentcol=crSelectFill;
                    if(disable_old_style)
                        DitherBlt(lpDIS->hDC,rect.left+dx,rect.top+dy,m_iconX,m_iconY,
                        (HBITMAP)(bitmapstandard),0,0,transparentcol);
                    else
                        DitherBlt2(pDC,rect.left+dx,rect.top+dy,m_iconX,m_iconY,
                        bitmapstandard,0,0,transparentcol);
                    if(state&ODS_SELECTED)pDC->Draw3dRect (rect,crSelect,crSelect);
                    bitmapstandard.DeleteObject();
                }
            }
            else if(selectedflag){
                pDC->FillRect (rect2,&m_brSelect);
                CPoint ptImage(rect.left+dx,rect.top+dy);
                if(state&ODS_CHECKED){
                    pDC->Draw3dRect(rect2,crSelect,crSelect);
                    ptImage.x-=1;ptImage.y-=1;
                }
                if(bitmap){
                    if(CanDraw3D&&!(state&ODS_CHECKED)){
                        CPoint ptImage1(ptImage.x+1,ptImage.y+1);
                        CPoint ptImage2(ptImage.x-1,ptImage.y-1);
                        bitmap->Draw(pDC,shadow_offset,ptImage1,ILD_TRANSPARENT);
                        bitmap->Draw(pDC,xoffset,ptImage2,ILD_TRANSPARENT);
                    }
                    else bitmap->Draw(pDC,xoffset,ptImage,ILD_TRANSPARENT);
                }
            }
            else{
                if(state&ODS_CHECKED){
                    CBrush brushin;
                    brushin.CreateSolidBrush(LightenColor(crSelect,0.85));
                    pDC->FillRect(rect2,&brushin);
                    brushin.DeleteObject();
                    pDC->Draw3dRect(rect2,crSelect,crSelect);
                    CPoint ptImage(rect.left+dx-1,rect.top+dy-1);
                    if(bitmap)bitmap->Draw(pDC,xoffset,ptImage,ILD_TRANSPARENT);
                }
                else{
                    pDC->FillRect (rect2,&m_newbrBackground);
                    pDC->Draw3dRect (rect2,m_newclrBack,m_newclrBack);
                    CPoint ptImage(rect.left+dx,rect.top+dy);
                    if(bitmap){
                        if(CanDraw3D)
                            bitmap->Draw(pDC,faded_offset,ptImage,ILD_TRANSPARENT);
                        else
                            bitmap->Draw(pDC,xoffset,ptImage,ILD_TRANSPARENT);
                    }
                }
            }
        }
        if(nIconNormal<0 && state&ODS_CHECKED && !checkflag){
            dy = (int)(0.5+(rect.Height()-16)/2.0);
            dy = dy<0 ? 0 : dy;
            dx = (int)(0.5+(barwidth-16)/2.0);
            dx = dx<0 ? 0 : dx;
            CMenuItemInfo info;
            info.fMask = MIIM_CHECKMARKS;
            ::GetMenuItemInfo((HMENU)lpDIS->hwndItem,lpDIS->itemID,
                MF_BYCOMMAND, &info);
            if(state&ODS_CHECKED || info.hbmpUnchecked) {
                rect2.SetRect(rect.left+dx,rect.top+dy,rect.left+dx+16,rect.top+dy+16);
                DrawXPCheckmark(pDC, rect2,state&ODS_CHECKED ? info.hbmpChecked :
                info.hbmpUnchecked,crSelect);
            }
        }

        //This is needed always so that we can have the space for check marks

        x0=rect.left;y0=rect.top;
        rect.left = rect.left + barwidth + 8; 

        if(!strText.IsEmpty()){

            CRect rectt(rect.left,rect.top-1,rect.right,rect.bottom-1);

            //   Find tabs

            CString leftStr,rightStr;
            leftStr.Empty();rightStr.Empty();
            int tablocr=strText.ReverseFind(_T('\t'));
            if(tablocr!=-1){
                rightStr=strText.Mid(tablocr+1);
                leftStr=strText.Left(strText.Find(_T('\t')));
                rectt.right-=m_iconX;
            }
            else leftStr=strText;

            int iOldMode = pDC->GetBkMode();
            pDC->SetBkMode( TRANSPARENT);

            // Draw the text in the correct colour:

            UINT nFormat  = DT_LEFT|DT_SINGLELINE|DT_VCENTER;
            UINT nFormatr = DT_RIGHT|DT_SINGLELINE|DT_VCENTER;
            if(!(lpDIS->itemState & ODS_GRAYED)){
                pDC->SetTextColor(crText);
                pDC->DrawText (leftStr,rectt,nFormat);
                if(tablocr!=-1) pDC->DrawText (rightStr,rectt,nFormatr);
            }
            else{
                RECT offset = *rectt;
                offset.left+=1;
                offset.right+=1;
                offset.top+=1;
                offset.bottom+=1;
                if(!IsWinXPLuna()){
                    COLORREF graycol=GetSysColor(COLOR_GRAYTEXT);
                    if(!(state&ODS_SELECTED))graycol = LightenColor(graycol,0.4);
                    pDC->SetTextColor(graycol);
                }
                else pDC->SetTextColor(GetSysColor(COLOR_GRAYTEXT));
                pDC->DrawText(leftStr,rectt, nFormat);
                if(tablocr!=-1) pDC->DrawText (rightStr,rectt,nFormatr);
            }
            pDC->SetBkMode( iOldMode );
        }

        m_penBack.DeleteObject();
        m_brSelect.DeleteObject();
    }
    m_brBackground.DeleteObject();
    m_newbrBackground.DeleteObject();
#ifdef BCMENU_USE_MEMDC
    if(pFont)pDC->SelectObject (pFont); //set it to the old font
    m_fontMenu.DeleteObject();
    if(pMemDC)delete pMemDC;
#endif
}

BOOL BCMenu::GetBitmapFromImageList(CDC* pDC,CImageList *imglist,int nIndex,CBitmap &bmp)
{
    HICON hIcon = imglist->ExtractIcon(nIndex);
    CDC dc;
    dc.CreateCompatibleDC(pDC);
    bmp.CreateCompatibleBitmap(pDC,m_iconX,m_iconY);
    CBitmap* pOldBmp = dc.SelectObject(&bmp);
    CBrush brush ;
    COLORREF m_newclrBack;
    m_newclrBack=GetSysColor(COLOR_3DFACE);
    brush.CreateSolidBrush(m_newclrBack);
    ::DrawIconEx(
        dc.GetSafeHdc(),
        0,
        0,
        hIcon,
        m_iconX,
        m_iconY,
        0,
        (HBRUSH)brush,
        DI_NORMAL
        );
    dc.SelectObject( pOldBmp );
    dc.DeleteDC();
    // the icon is not longer needed
    ::DestroyIcon(hIcon);
    return(TRUE);
}

/*
==========================================================================
void BCMenu::MeasureItem(LPMEASUREITEMSTRUCT)
---------------------------------------------

  Called by the framework when it wants to know what the width and height
  of our item will be.  To accomplish this we provide the width of the
  icon plus the width of the menu text, and then the height of the icon.

    ==========================================================================
*/

void BCMenu::MeasureItem( LPMEASUREITEMSTRUCT lpMIS )
{
    UINT state = (((BCMenuData*)(lpMIS->itemData))->nFlags);
    int BCMENU_PAD=4;
    if(IsLunaMenuStyle()&&xp_draw_3D_bitmaps)BCMENU_PAD=7;
    if(state & MF_SEPARATOR){
        lpMIS->itemWidth = 0;
        int temp = GetSystemMetrics(SM_CYMENU)>>1;
        lpMIS->itemHeight = temp>(m_iconY+BCMENU_PAD)/2 ? temp : (m_iconY+BCMENU_PAD)/2;
    }
    else{
        CFont m_fontMenu;
        LOGFONT m_lf;
        ZeroMemory ((PVOID) &m_lf,sizeof (LOGFONT));
        NONCLIENTMETRICS nm;
        nm.cbSize = sizeof (NONCLIENTMETRICS);
        VERIFY(SystemParametersInfo(SPI_GETNONCLIENTMETRICS,
            nm.cbSize,&nm,0)); 
        m_lf =  nm.lfMenuFont;
        m_fontMenu.CreateFontIndirect (&m_lf);

        // Obtain the width of the text:
        CWnd *pWnd = AfxGetMainWnd();            // Get main window
        if (pWnd == NULL) pWnd = CWnd::GetDesktopWindow();
        CDC *pDC = pWnd->GetDC();              // Get device context
        CFont* pFont=NULL;    // Select menu font in...

        if (IsNewShell())
            pFont = pDC->SelectObject (&m_fontMenu);// Select menu font in...

        //Get pointer to text SK
        const wchar_t *lpstrText = ((BCMenuData*)(lpMIS->itemData))->GetWideString();//SK: we use const to prevent misuse

        SIZE size;
        size.cx=size.cy=0;

        if (Win32s!=g_Shell)
            VERIFY(::GetTextExtentPoint32W(pDC->m_hDC,lpstrText,
            wcslen(lpstrText),&size)); //SK should also work on 95
#ifndef UNICODE //can't be UNICODE for Win32s
        else{//it's Win32suckx
            RECT rect;
            rect.left=rect.top=0;
            size.cy=DrawText(pDC->m_hDC,(LPCTSTR)lpstrText,
                wcslen(lpstrText),&rect,
                DT_SINGLELINE|DT_LEFT|DT_VCENTER|DT_CALCRECT);
            //+3 makes at least three pixels space to the menu border
            size.cx=rect.right-rect.left+3;
            size.cx += 3*(size.cx/wcslen(lpstrText));
        }
#endif    

        CSize t = CSize(size);
        if(IsNewShell())
            pDC->SelectObject (pFont);  // Select old font in
        pWnd->ReleaseDC(pDC);  // Release the DC

        // Set width and height:

        if(IsLunaMenuStyle())lpMIS->itemWidth = m_iconX+BCMENU_PAD+8+t.cx;
        else lpMIS->itemWidth = m_iconX + t.cx + m_iconX + BCMENU_GAP;
        int temp = GetSystemMetrics(SM_CYMENU);
        lpMIS->itemHeight = temp>m_iconY+BCMENU_PAD ? temp : m_iconY+BCMENU_PAD;
        m_fontMenu.DeleteObject();
    }
}

void BCMenu::SetIconSize (int width, int height)
{
    m_iconX = width;
    m_iconY = height;
}

BOOL BCMenu::AppendODMenuA(LPCSTR lpstrText,UINT nFlags,UINT nID,
                           int nIconNormal)
{
    USES_CONVERSION;
    return AppendODMenuW(A2W(lpstrText),nFlags,nID,nIconNormal);//SK: See MFC Tech Note 059
}


BOOL BCMenu::AppendODMenuW(wchar_t *lpstrText,UINT nFlags,UINT nID,
                           int nIconNormal)
{
    // Add the MF_OWNERDRAW flag if not specified:
    if(!nID){
        if(nFlags&MF_BYPOSITION)nFlags=MF_SEPARATOR|MF_OWNERDRAW|MF_BYPOSITION;
        else nFlags=MF_SEPARATOR|MF_OWNERDRAW;
    }
    else if(!(nFlags & MF_OWNERDRAW))nFlags |= MF_OWNERDRAW;

    if(nFlags & MF_POPUP){
        m_AllSubMenus.Add((HMENU)nID);
        m_SubMenus.Add((HMENU)nID);
    }

    BCMenuData *mdata = new BCMenuData;
    m_MenuList.Add(mdata);
    mdata->SetWideString(lpstrText);    //SK: modified for dynamic allocation

    mdata->menuIconNormal = -1;
    mdata->xoffset = -1;

    if(nIconNormal>=0){
        CImageList bitmap;
        int xoffset=0;
        LoadFromToolBar(nID,nIconNormal,xoffset);
        if(mdata->bitmap){
            mdata->bitmap->DeleteImageList();
            mdata->bitmap=NULL;
        }
        bitmap.Create(m_iconX,m_iconY,ILC_COLORDDB|ILC_MASK,1,1);
        if(AddBitmapToImageList(&bitmap,nIconNormal)){
            mdata->global_offset = AddToGlobalImageList(&bitmap,xoffset,nID);
        }
    }
    else mdata->global_offset = GlobalImageListOffset(nID);

    mdata->nFlags = nFlags;
    mdata->nID = nID;
    BOOL returnflag=CMenu::AppendMenu(nFlags, nID, (LPCTSTR)mdata);
    if(m_loadmenu)RemoveTopLevelOwnerDraw();
    return(returnflag);
}

BOOL BCMenu::AppendODMenuA(LPCSTR lpstrText,UINT nFlags,UINT nID,
                           CImageList *il,int xoffset)
{
    USES_CONVERSION;
    return AppendODMenuW(A2W(lpstrText),nFlags,nID,il,xoffset);
}

BOOL BCMenu::AppendODMenuW(wchar_t *lpstrText,UINT nFlags,UINT nID,
                           CImageList *il,int xoffset)
{
    // Add the MF_OWNERDRAW flag if not specified:
    if(!nID){
        if(nFlags&MF_BYPOSITION)nFlags=MF_SEPARATOR|MF_OWNERDRAW|MF_BYPOSITION;
        else nFlags=MF_SEPARATOR|MF_OWNERDRAW;
    }
    else if(!(nFlags & MF_OWNERDRAW))nFlags |= MF_OWNERDRAW;

    if(nFlags & MF_POPUP){
        m_AllSubMenus.Add((HMENU)nID);
        m_SubMenus.Add((HMENU)nID);
    }

    BCMenuData *mdata = new BCMenuData;
    m_MenuList.Add(mdata);
    mdata->SetWideString(lpstrText);    //SK: modified for dynamic allocation

    if(il){
        mdata->menuIconNormal = 0;
        mdata->xoffset=0;
        if(mdata->bitmap)mdata->bitmap->DeleteImageList();
        else mdata->bitmap=new(CImageList);
        ImageListDuplicate(il,xoffset,mdata->bitmap);
    }
    else{
        mdata->menuIconNormal = -1;
        mdata->xoffset = -1;
    }
    mdata->nFlags = nFlags;
    mdata->nID = nID;
    return(CMenu::AppendMenu(nFlags, nID, (LPCTSTR)mdata));
}

BOOL BCMenu::InsertODMenuA(UINT nPosition,LPCSTR lpstrText,UINT nFlags,UINT nID,
                           int nIconNormal)
{
    USES_CONVERSION;
    return InsertODMenuW(nPosition,A2W(lpstrText),nFlags,nID,nIconNormal);
}


BOOL BCMenu::InsertODMenuW(UINT nPosition,wchar_t *lpstrText,UINT nFlags,UINT nID,
                           int nIconNormal)
{
    if(!(nFlags & MF_BYPOSITION)){
        int iPosition =0;
        BCMenu* pMenu = FindMenuOption(nPosition,iPosition);
        if(pMenu){
            return(pMenu->InsertODMenuW(iPosition,lpstrText,nFlags|MF_BYPOSITION,nID,nIconNormal));
        }
        else return(FALSE);
    }

    if(!nID)nFlags=MF_SEPARATOR|MF_OWNERDRAW|MF_BYPOSITION;
    else if(!(nFlags & MF_OWNERDRAW))nFlags |= MF_OWNERDRAW;

    int menustart=0;

    if(nFlags & MF_POPUP){
        if(m_loadmenu){
            menustart=GetMenuStart();
            if(nPosition<(UINT)menustart)menustart=0;
        }
        m_AllSubMenus.Add((HMENU)nID);
        m_SubMenus.InsertAt(nPosition,(HMENU)nID);
    }

    //Stephane Clog suggested adding this, believe it or not it's in the help 
    if(nPosition==(UINT)-1)nPosition=GetMenuItemCount();

    BCMenuData *mdata = new BCMenuData;
    m_MenuList.InsertAt(nPosition-menustart,mdata);
    mdata->SetWideString(lpstrText);    //SK: modified for dynamic allocation

    mdata->menuIconNormal = nIconNormal;
    mdata->xoffset=-1;
    if(nIconNormal>=0){
        CImageList bitmap;
        int xoffset=0;
        LoadFromToolBar(nID,nIconNormal,xoffset);
        if(mdata->bitmap){
            mdata->bitmap->DeleteImageList();
            mdata->bitmap=NULL;
        }
        bitmap.Create(m_iconX,m_iconY,ILC_COLORDDB|ILC_MASK,1,1);
        if(AddBitmapToImageList(&bitmap,nIconNormal)){
            mdata->global_offset = AddToGlobalImageList(&bitmap,xoffset,nID);
        }
    }
    else mdata->global_offset = GlobalImageListOffset(nID);
    mdata->nFlags = nFlags;
    mdata->nID = nID;
    BOOL returnflag=CMenu::InsertMenu(nPosition,nFlags,nID,(LPCTSTR)mdata);
    if(m_loadmenu)RemoveTopLevelOwnerDraw();
    return(returnflag);
}

BOOL BCMenu::InsertODMenuA(UINT nPosition,LPCSTR lpstrText,UINT nFlags,UINT nID,
                           CImageList *il,int xoffset)
{
    USES_CONVERSION;
    return InsertODMenuW(nPosition,A2W(lpstrText),nFlags,nID,il,xoffset);
}

BOOL BCMenu::InsertODMenuW(UINT nPosition,wchar_t *lpstrText,UINT nFlags,UINT nID,
                           CImageList *il,int xoffset)
{
    if(!(nFlags & MF_BYPOSITION)){
        int iPosition =0;
        BCMenu* pMenu = FindMenuOption(nPosition,iPosition);
        if(pMenu){
            return(pMenu->InsertODMenuW(iPosition,lpstrText,nFlags|MF_BYPOSITION,nID,il,xoffset));
        }
        else return(FALSE);
    }

    if(!nID)nFlags=MF_SEPARATOR|MF_OWNERDRAW|MF_BYPOSITION;
    else if(!(nFlags & MF_OWNERDRAW))nFlags |= MF_OWNERDRAW;

    if(nFlags & MF_POPUP){
        m_AllSubMenus.Add((HMENU)nID);
        m_SubMenus.InsertAt(nPosition,(HMENU)nID);
    }

    //Stephane Clog suggested adding this, believe it or not it's in the help 
    if(nPosition==(UINT)-1)nPosition=GetMenuItemCount();

    BCMenuData *mdata = new BCMenuData;
    m_MenuList.InsertAt(nPosition,mdata);
    mdata->SetWideString(lpstrText);    //SK: modified for dynamic allocation

    mdata->menuIconNormal = -1;
    mdata->xoffset = -1;

    if(il){
        if(mdata->bitmap){
            mdata->bitmap->DeleteImageList();
            mdata->bitmap=NULL;
        }
        mdata->global_offset = AddToGlobalImageList(il,xoffset,nID);
    }
    mdata->nFlags = nFlags;
    mdata->nID = nID;
    return(CMenu::InsertMenu(nPosition,nFlags,nID,(LPCTSTR)mdata));
}

BOOL BCMenu::ModifyODMenuA(const char * lpstrText,UINT nID,int nIconNormal)
{
    USES_CONVERSION;
    return ModifyODMenuW(A2W(lpstrText),nID,nIconNormal);//SK: see MFC Tech Note 059
}

BOOL BCMenu::ModifyODMenuW(wchar_t *lpstrText,UINT nID,int nIconNormal)
{
    int nLoc;
    BCMenuData *mdata;
    CArray<BCMenu*,BCMenu*>bcsubs;
    CArray<int,int&>bclocs;

    // Find the old BCMenuData structure:
    BCMenu *psubmenu = FindMenuOption(nID,nLoc);
    do{
        if(psubmenu && nLoc>=0)mdata = psubmenu->m_MenuList[nLoc];
        else{
            // Create a new BCMenuData structure:
            mdata = new BCMenuData;
            m_MenuList.Add(mdata);
        }

        ASSERT(mdata);
        if(lpstrText)
            mdata->SetWideString(lpstrText);  //SK: modified for dynamic allocation
        mdata->menuIconNormal = -1;
        mdata->xoffset = -1;
        if(nIconNormal>=0){
            CImageList bitmap;
            int xoffset=0;
            LoadFromToolBar(nID,nIconNormal,xoffset);
            if(mdata->bitmap){
                mdata->bitmap->DeleteImageList();
                mdata->bitmap=NULL;
            }
            bitmap.Create(m_iconX,m_iconY,ILC_COLORDDB|ILC_MASK,1,1);
            if(AddBitmapToImageList(&bitmap,nIconNormal)){
                mdata->global_offset = AddToGlobalImageList(&bitmap,xoffset,nID);
            }
        }
        else mdata->global_offset = GlobalImageListOffset(nID);
        mdata->nFlags &= ~(MF_BYPOSITION);
        mdata->nFlags |= MF_OWNERDRAW;
        mdata->nID = nID;
        bcsubs.Add(psubmenu);
        bclocs.Add(nLoc);
        if(psubmenu && nLoc>=0)psubmenu = FindAnotherMenuOption(nID,nLoc,bcsubs,bclocs);
        else psubmenu=NULL;
    }while(psubmenu);
    return (CMenu::ModifyMenu(nID,mdata->nFlags,nID,(LPCTSTR)mdata));
}

BOOL BCMenu::ModifyODMenuA(const char * lpstrText,UINT nID,CImageList *il,int xoffset)
{
    USES_CONVERSION;
    return ModifyODMenuW(A2W(lpstrText),nID,il,xoffset);
}

BOOL BCMenu::ModifyODMenuW(wchar_t *lpstrText,UINT nID,CImageList *il,int xoffset)
{
    int nLoc;
    BCMenuData *mdata;
    CArray<BCMenu*,BCMenu*>bcsubs;
    CArray<int,int&>bclocs;

    // Find the old BCMenuData structure:
    BCMenu *psubmenu = FindMenuOption(nID,nLoc);
    do{
        if(psubmenu && nLoc>=0)mdata = psubmenu->m_MenuList[nLoc];
        else{
            // Create a new BCMenuData structure:
            mdata = new BCMenuData;
            m_MenuList.Add(mdata);
        }

        ASSERT(mdata);
        if(lpstrText)
            mdata->SetWideString(lpstrText);  //SK: modified for dynamic allocation
        mdata->menuIconNormal = -1;
        mdata->xoffset = -1;
        if(il){
            if(mdata->bitmap){
                mdata->bitmap->DeleteImageList();
                mdata->bitmap=NULL;
            }
            mdata->global_offset = AddToGlobalImageList(il,xoffset,nID);
        }
        mdata->nFlags &= ~(MF_BYPOSITION);
        mdata->nFlags |= MF_OWNERDRAW;
        mdata->nID = nID;
        bcsubs.Add(psubmenu);
        bclocs.Add(nLoc);
        if(psubmenu && nLoc>=0)psubmenu = FindAnotherMenuOption(nID,nLoc,bcsubs,bclocs);
        else psubmenu=NULL;
    }while(psubmenu);
    return (CMenu::ModifyMenu(nID,mdata->nFlags,nID,(LPCTSTR)mdata));
}

BOOL BCMenu::ModifyODMenuA(const char * lpstrText,UINT nID,CBitmap *bmp)
{
    USES_CONVERSION;
    return ModifyODMenuW(A2W(lpstrText),nID,bmp);
}

BOOL BCMenu::ModifyODMenuW(wchar_t *lpstrText,UINT nID,CBitmap *bmp)
{
    if(bmp){
        CImageList temp;
        temp.Create(m_iconX,m_iconY,ILC_COLORDDB|ILC_MASK,1,1);
        if(m_bitmapBackgroundFlag)temp.Add(bmp,m_bitmapBackground);
        else temp.Add(bmp,GetSysColor(COLOR_3DFACE));
        return ModifyODMenuW(lpstrText,nID,&temp,0);
    }
    return ModifyODMenuW(lpstrText,nID,NULL,0);
}

// courtesy of Warren Stevens
BOOL BCMenu::ModifyODMenuA(const char * lpstrText,UINT nID,COLORREF fill,COLORREF border,int hatchstyle,CSize *pSize)
{
    USES_CONVERSION;
    return ModifyODMenuW(A2W(lpstrText),nID,fill,border,hatchstyle,pSize);
}

BOOL BCMenu::ModifyODMenuW(wchar_t *lpstrText,UINT nID,COLORREF fill,COLORREF border,int hatchstyle,CSize *pSize)
{
    CWnd *pWnd = AfxGetMainWnd();            // Get main window
    CDC *pDC = pWnd->GetDC();              // Get device context
    SIZE sz;
    if(!pSize){
        sz.cx = m_iconX;
        sz.cy = m_iconY;
    }
    else{
        sz.cx = pSize->cx;
        sz.cy = pSize->cy;
    }
    CSize bitmap_size(sz);
    CSize icon_size(m_iconX,m_iconY);
    CBitmap bmp;
    ColorBitmap(pDC,bmp,bitmap_size,icon_size,fill,border,hatchstyle);        
    pWnd->ReleaseDC(pDC);
    return ModifyODMenuW(lpstrText,nID,&bmp);
}


BOOL BCMenu::ModifyODMenuA(const char *lpstrText,const char *OptionText,
                           int nIconNormal)
{
    USES_CONVERSION;
    return ModifyODMenuW(A2W(lpstrText),A2W(OptionText),nIconNormal);//SK: see MFC  Tech Note 059
}

BOOL BCMenu::ModifyODMenuW(wchar_t *lpstrText,wchar_t *OptionText,
                           int nIconNormal)
{
    BCMenuData *mdata;

    // Find the old BCMenuData structure:
    CString junk(OptionText);
    mdata=FindMenuOption(OptionText);
    if(mdata){
        if(lpstrText)
            mdata->SetWideString(lpstrText);//SK: modified for dynamic allocation
        mdata->menuIconNormal = nIconNormal;
        mdata->xoffset=-1;
        if(nIconNormal>=0){
            mdata->xoffset=0;
            if(mdata->bitmap)mdata->bitmap->DeleteImageList();
            else mdata->bitmap=new(CImageList);
            mdata->bitmap->Create(m_iconX,m_iconY,ILC_COLORDDB|ILC_MASK,1,1);
            if(!AddBitmapToImageList(mdata->bitmap,nIconNormal)){
                mdata->bitmap->DeleteImageList();
                delete mdata->bitmap;
                mdata->bitmap=NULL;
                mdata->menuIconNormal = nIconNormal = -1;
                mdata->xoffset = -1;
            }
        }
        return(TRUE);
    }
    return(FALSE);
}

BCMenuData *BCMenu::NewODMenu(UINT pos,UINT nFlags,UINT nID,CString string)
{
    BCMenuData *mdata;

    mdata = new BCMenuData;
    mdata->menuIconNormal = -1;
    mdata->xoffset=-1;
#ifdef UNICODE
    mdata->SetWideString((LPCTSTR)string);//SK: modified for dynamic allocation
#else
    mdata->SetAnsiString(string);
#endif
    mdata->nFlags = nFlags;
    mdata->nID = nID;

//    if(nFlags & MF_POPUP)m_AllSubMenus.Add((HMENU)nID);

    if (nFlags&MF_OWNERDRAW){
        ASSERT(!(nFlags&MF_STRING));
        ModifyMenu(pos,nFlags,nID,(LPCTSTR)mdata);
    }
    else if (nFlags&MF_STRING){
        ASSERT(!(nFlags&MF_OWNERDRAW));
        ModifyMenu(pos,nFlags,nID,mdata->GetString());
    }
    else{
        ASSERT(nFlags&MF_SEPARATOR);
        ModifyMenu(pos,nFlags,nID);
    }

    return(mdata);
};

BOOL BCMenu::LoadToolbars(const UINT *arID,int n)
{
    ASSERT(arID);
    BOOL returnflag=TRUE;
    for(int i=0;i<n;++i){
        if(!LoadToolbar(arID[i]))returnflag=FALSE;
    }
    return(returnflag);
}

BOOL BCMenu::LoadToolbar(UINT nToolBar)
{
    UINT nID,nStyle;
    BOOL returnflag=FALSE;
    BCMenuToolBar bar;
    int xoffset=-1,xset;
    int iconx,icony;

    CWnd* pWnd = AfxGetMainWnd();
    if (pWnd == NULL)pWnd = CWnd::GetDesktopWindow();
    bar.Create(pWnd);
    if(bar.LoadToolBar(nToolBar)){
        bar.GetIconSize(iconx,icony);
        if(iconx>m_iconX)m_iconX=iconx;
        if(icony>m_iconY)m_iconY=icony;
        CImageList imglist;
        imglist.Create(m_iconX,m_iconY,ILC_COLORDDB|ILC_MASK,1,1);
        if(AddBitmapToImageList(&imglist,nToolBar)){
            returnflag=TRUE;
            for(int i=0;i<bar.GetCount();++i){
                nID = bar.GetItemID(i); 
                if(nID && GetMenuState(nID, MF_BYCOMMAND)
                    !=0xFFFFFFFF){
                    xoffset=bar.CommandToIndex(nID);
                    if(xoffset>=0){
                        bar.GetButtonInfo(xoffset,nID,nStyle,xset);
                        if(xset>0)xoffset=xset;
                    }
                    ModifyODMenu(NULL,nID,&imglist,xoffset);
                }
            }
        }
    }
    return(returnflag);
}

BOOL BCMenu::LoadFromToolBar(UINT nID,UINT nToolBar,int& xoffset)
{
    int xset,offset;
    UINT nStyle;
    BOOL returnflag=FALSE;
    CToolBar bar;

    CWnd* pWnd = AfxGetMainWnd();
    if (pWnd == NULL)pWnd = CWnd::GetDesktopWindow();
    bar.Create(pWnd);
    if(bar.LoadToolBar(nToolBar)){
        offset=bar.CommandToIndex(nID);
        if(offset>=0){
            bar.GetButtonInfo(offset,nID,nStyle,xset);
            if(xset>0)xoffset=xset;
            returnflag=TRUE;
        }
    }
    return(returnflag);
}

// O.S.
BCMenuData *BCMenu::FindMenuItem(UINT nID)
{
    BCMenuData *pData = NULL;
    int i;

    for(i = 0; i <= m_MenuList.GetUpperBound(); i++){
        if (m_MenuList[i]->nID == nID){
            pData = m_MenuList[i];
            break;
        }
    }
    if (!pData){
        int loc;
        BCMenu *pMenu = FindMenuOption(nID, loc);
        ASSERT(pMenu != this);
        if (loc >= 0){
            return pMenu->FindMenuItem(nID);
        }
    }
    return pData;
}


BCMenu *BCMenu::FindAnotherMenuOption(int nId,int& nLoc,CArray<BCMenu*,BCMenu*>&bcsubs,
                                      CArray<int,int&>&bclocs)
{
    int i,numsubs,j;
    BCMenu *psubmenu,*pgoodmenu;
    BOOL foundflag;

    for(i=0;i<(int)(GetMenuItemCount());++i){
#ifdef _CPPRTTI 
        psubmenu=dynamic_cast<BCMenu *>(GetSubMenu(i));
#else
        psubmenu=(BCMenu *)GetSubMenu(i);
#endif
        if(psubmenu){
            pgoodmenu=psubmenu->FindAnotherMenuOption(nId,nLoc,bcsubs,bclocs);
            if(pgoodmenu)return(pgoodmenu);
        }
        else if(nId==(int)GetMenuItemID(i)){
            numsubs=bcsubs.GetSize();
            foundflag=TRUE;
            for(j=0;j<numsubs;++j){
                if(bcsubs[j]==this&&bclocs[j]==i){
                    foundflag=FALSE;
                    break;
                }
            }
            if(foundflag){
                nLoc=i;
                return(this);
            }
        }
    }
    nLoc = -1;
    return(NULL);
}

BCMenu *BCMenu::FindMenuOption(int nId,int& nLoc)
{
    int i;
    BCMenu *psubmenu,*pgoodmenu;

    for(i=0;i<(int)(GetMenuItemCount());++i){
#ifdef _CPPRTTI 
        psubmenu=dynamic_cast<BCMenu *>(GetSubMenu(i));
#else
        psubmenu=(BCMenu *)GetSubMenu(i);
#endif
        if(psubmenu){
            pgoodmenu=psubmenu->FindMenuOption(nId,nLoc);
            if(pgoodmenu)return(pgoodmenu);
        }
        else if(nId==(int)GetMenuItemID(i)){
            nLoc=i;
            return(this);
        }
    }
    nLoc = -1;
    return(NULL);
}

BCMenuData *BCMenu::FindMenuOption(wchar_t *lpstrText)
{
    int i,j;
    BCMenu *psubmenu;
    BCMenuData *pmenulist;

    for(i=0;i<(int)(GetMenuItemCount());++i){
#ifdef _CPPRTTI 
        psubmenu=dynamic_cast<BCMenu *>(GetSubMenu(i));
#else
        psubmenu=(BCMenu *)GetSubMenu(i);
#endif
        if(psubmenu){
            pmenulist=psubmenu->FindMenuOption(lpstrText);
            if(pmenulist)return(pmenulist);
        }
        else{
            const wchar_t *szWide;//SK: we use const to prevent misuse of this Ptr
            for(j=0;j<=m_MenuList.GetUpperBound();++j){     
                szWide = m_MenuList[j]->GetWideString ();
                if(szWide && !wcscmp(lpstrText,szWide))//SK: modified for dynamic allocation
                    return(m_MenuList[j]);
            }
        }
    }
    return(NULL);
}


BOOL BCMenu::LoadMenu(int nResource)
{
    return(BCMenu::LoadMenu(MAKEINTRESOURCE(nResource)));
};

BOOL BCMenu::LoadMenu(LPCTSTR lpszResourceName)
{
    ASSERT_VALID(this);
    ASSERT(lpszResourceName != NULL);

    // Find the Menu Resource:
    HINSTANCE hInst = AfxFindResourceHandle(lpszResourceName,RT_MENU);
    HRSRC hRsrc = ::FindResource(hInst,lpszResourceName,RT_MENU);
    if (hRsrc == NULL){
        hInst = NULL;
        hRsrc = ::FindResource(hInst,lpszResourceName,RT_MENU);
    }
    if(hRsrc == NULL)return FALSE;

    // Load the Menu Resource:

    HGLOBAL hGlobal = LoadResource(hInst, hRsrc);
    if(hGlobal == NULL)return FALSE;

    // first destroy the menu if we're trying to loadmenu again
    DestroyMenu();

    // Attempt to create us as a menu...
    if(!CMenu::CreateMenu())return FALSE;

    // Get Item template Header, and calculate offset of MENUITEMTEMPLATES

    MENUITEMTEMPLATEHEADER *pTpHdr=
        (MENUITEMTEMPLATEHEADER*)LockResource(hGlobal);
    BYTE* pTp=(BYTE*)pTpHdr + 
        (sizeof(MENUITEMTEMPLATEHEADER) + pTpHdr->offset);


    // Variables needed during processing of Menu Item Templates:

    int j=0;
    WORD    dwFlags = 0;              // Flags of the Menu Item
    WORD    dwID  = 0;              // ID of the Menu Item
    UINT    uFlags;                  // Actual Flags.
    wchar_t *szCaption=NULL;
    int      nLen   = 0;                // Length of caption
    CTypedPtrArray<CPtrArray, BCMenu*>  m_Stack;    // Popup menu stack
    CArray<BOOL,BOOL>  m_StackEnd;    // Popup menu stack
    m_Stack.Add(this);                  // Add it to this...
    m_StackEnd.Add(FALSE);

    do{
        // Obtain Flags and (if necessary), the ID...
        memcpy(&dwFlags, pTp, sizeof(WORD));pTp+=sizeof(WORD);// Obtain Flags
        if(!(dwFlags & MF_POPUP)){
            memcpy(&dwID, pTp, sizeof(WORD)); // Obtain ID
            pTp+=sizeof(WORD);
        }
        else dwID = 0;

        uFlags = (UINT)dwFlags; // Remove MF_END from the flags that will
        if(uFlags & MF_END) // be passed to the Append(OD)Menu functions.
            uFlags -= MF_END;

        // Obtain Caption (and length)

        nLen = 0;
        szCaption=new wchar_t[wcslen((wchar_t *)pTp)+1];
        wcscpy(szCaption,(wchar_t *)pTp);
        pTp=&pTp[(wcslen((wchar_t *)pTp)+1)*sizeof(wchar_t)];//modified SK

        // Handle popup menus first....

        //WideCharToMultiByte
        if(dwFlags & MF_POPUP){
            if(dwFlags & MF_END)m_StackEnd.SetAt(m_Stack.GetUpperBound(),TRUE);
            BCMenu* pSubMenu = new BCMenu;
            pSubMenu->m_unselectcheck=m_unselectcheck;
            pSubMenu->m_selectcheck=m_selectcheck;
            pSubMenu->checkmaps=checkmaps;
            pSubMenu->checkmapsshare=TRUE;
            pSubMenu->CreatePopupMenu();

            // Append it to the top of the stack:

            m_Stack[m_Stack.GetUpperBound()]->AppendODMenuW(szCaption,uFlags,
                (UINT)pSubMenu->m_hMenu, -1);
            m_Stack.Add(pSubMenu);
            m_StackEnd.Add(FALSE);
        }
        else {
            m_Stack[m_Stack.GetUpperBound()]->AppendODMenuW(szCaption, uFlags,
                dwID, -1);
            if(dwFlags & MF_END)m_StackEnd.SetAt(m_Stack.GetUpperBound(),TRUE);
            j = m_Stack.GetUpperBound();
            while(j>=0 && m_StackEnd.GetAt(j)){
                m_Stack[m_Stack.GetUpperBound()]->InsertSpaces();
                m_Stack.RemoveAt(j);
                m_StackEnd.RemoveAt(j);
                --j;
            }
        }

        delete[] szCaption;
    }while(m_Stack.GetUpperBound() != -1);

    for(int i=0;i<(int)GetMenuItemCount();++i){
        CString str=m_MenuList[i]->GetString();
        if(GetSubMenu(i)){
            m_MenuList[i]->nFlags=MF_POPUP|MF_BYPOSITION;
            ModifyMenu(i,MF_POPUP|MF_BYPOSITION,
                (UINT)GetSubMenu(i)->m_hMenu,str);
        }
        else{
            m_MenuList[i]->nFlags=MF_STRING|MF_BYPOSITION;
            ModifyMenu(i,MF_STRING|MF_BYPOSITION,m_MenuList[i]->nID,str);
        }
    }

    m_loadmenu=TRUE;

    return(TRUE);
}

int BCMenu::GetMenuStart(void)
{
    if(!m_loadmenu)return(0);

    CString name,str;
    int menuloc=-1,listloc=-1,menustart=0,i=0,j=0;
    int nummenulist=m_MenuList.GetSize();
    int nummenu=(int)GetMenuItemCount();

    while(i<nummenu&&menuloc==-1){
        GetMenuString (i, name, MF_BYPOSITION);
        if(name.GetLength()>0){
            for(j=0;j<nummenulist;++j){
                str=m_MenuList[j]->GetString();
                if(name==str){
                    menuloc=i;
                    listloc=j;
                    break;
                }
            }
        }
        ++i;
    }
    if(menuloc>=0&&listloc>=0&&menuloc>=listloc)menustart=menuloc-listloc;
    return(menustart);
}

void BCMenu::RemoveTopLevelOwnerDraw(void)
{
    CString str;
    int i=0,j=0;
    int nummenulist=m_MenuList.GetSize(),menustart;

    menustart=GetMenuStart();
    for(i=menustart,j=0;i<(int)GetMenuItemCount();++i,++j){
        if(j<nummenulist){
            str=m_MenuList[j]->GetString();
            if(GetSubMenu(i)){
                m_MenuList[j]->nFlags=MF_POPUP|MF_BYPOSITION;
                ModifyMenu(i,MF_POPUP|MF_BYPOSITION,
                    (UINT)GetSubMenu(i)->m_hMenu,str);
            }
        }
    }

}

void BCMenu::InsertSpaces(void)
{
    int i,j,numitems,maxlength;
    CString string,newstring;
    CSize t;
    CFont m_fontMenu;
    LOGFONT m_lf;

    ZeroMemory ((PVOID) &m_lf,sizeof (LOGFONT));
    NONCLIENTMETRICS nm;
    nm.cbSize = sizeof (NONCLIENTMETRICS);
    VERIFY (SystemParametersInfo (SPI_GETNONCLIENTMETRICS,nm.cbSize,&nm,0)); 
    m_lf =  nm.lfMenuFont;
    m_fontMenu.CreateFontIndirect (&m_lf);

    CWnd *pWnd = AfxGetMainWnd();  
    if (pWnd == NULL)pWnd = CWnd::GetDesktopWindow();
    CDC *pDC = pWnd->GetDC();
    CFont* pFont = pDC->SelectObject (&m_fontMenu);

    numitems=GetMenuItemCount();
    maxlength = -1;
    for(i=0;i<numitems;++i){
        string=m_MenuList[i]->GetString();
        j=string.Find((char)9);
        newstring.Empty();
        if(j!=-1)newstring=string.Left(j);
        else newstring=string;
        newstring+=_T(" ");//SK: modified for Unicode correctness. 
        LPCTSTR lpstrText = (LPCTSTR)newstring;
        t=pDC->GetTextExtent(lpstrText,_tcslen(lpstrText));
        if(t.cx>maxlength)maxlength = t.cx;
    }
    for(i=0;i<numitems;++i){
        string=m_MenuList[i]->GetString();
        j=string.Find((char)9);
        if(j!=-1){
            newstring.Empty();
            newstring=string.Left(j);
            LPCTSTR lpstrText = (LPCTSTR)(newstring);
            t=pDC->GetTextExtent(lpstrText,_tcslen(lpstrText));
            while(t.cx<maxlength){
                newstring+=_T(' ');//SK: modified for Unicode correctness
                LPCTSTR lpstrText = (LPCTSTR)(newstring);
                t=pDC->GetTextExtent(lpstrText,_tcslen(lpstrText));
            }
            newstring+=string.Mid(j);
#ifdef UNICODE      
            m_MenuList[i]->SetWideString(newstring);//SK: modified for dynamic allocation
#else
            m_MenuList[i]->SetAnsiString(newstring);
#endif
        }
    }
    pDC->SelectObject (pFont);              // Select old font in
    pWnd->ReleaseDC(pDC);       // Release the DC
    m_fontMenu.DeleteObject();
}

void BCMenu::LoadCheckmarkBitmap(int unselect, int select)
{
    if(unselect>0 && select>0){
        m_selectcheck=select;
        m_unselectcheck=unselect;
        if(checkmaps)checkmaps->DeleteImageList();
        else checkmaps=new(CImageList);
        checkmaps->Create(m_iconX,m_iconY,ILC_MASK,2,1);
        BOOL flag1=AddBitmapToImageList(checkmaps,unselect);
        BOOL flag2=AddBitmapToImageList(checkmaps,select);
        if(!flag1||!flag2){
            checkmaps->DeleteImageList();
            delete checkmaps;
            checkmaps=NULL;
        }
    }
}

//--------------------------------------------------------------------------
//[18.06.99 rj]
BOOL BCMenu::GetMenuText(UINT id, CString& string, UINT nFlags/*= MF_BYPOSITION*/)
{
    BOOL returnflag=FALSE;

    if(MF_BYPOSITION&nFlags){
        UINT numMenuItems = m_MenuList.GetUpperBound();
        if(id<=numMenuItems){
            string=m_MenuList[id]->GetString();
            returnflag=TRUE;
        }
    }
    else{
        int uiLoc;
        BCMenu* pMenu = FindMenuOption(id,uiLoc);
        if(NULL!=pMenu) returnflag = pMenu->GetMenuText(uiLoc,string);
    }
    return(returnflag);
}


void BCMenu::DrawRadioDot(CDC *pDC,int x,int y,COLORREF color)
{
    CRect rcDot(x,y,x+6,y+6);
    CBrush brush;
    CPen pen;
    brush.CreateSolidBrush(color);
    pen.CreatePen(PS_SOLID,0,color);
    CBrush *pOldBrush=pDC->SelectObject(&brush);
    CPen *pOldPen=pDC->SelectObject(&pen);
    pDC->Ellipse(&rcDot);
    pDC->SelectObject(pOldBrush);
    pDC->SelectObject(pOldPen);
    pen.DeleteObject();
    brush.DeleteObject();
}

void BCMenu::DrawCheckMark(CDC* pDC,int x,int y,COLORREF color)
{
    CPen m_penBack;
    m_penBack.CreatePen (PS_SOLID,0,color);
    CPen *pOldPen = pDC->SelectObject (&m_penBack);
    pDC->MoveTo(x,y+2);
    pDC->LineTo(x,y+5);

    pDC->MoveTo(x+1,y+3);
    pDC->LineTo(x+1,y+6);

    pDC->MoveTo(x+2,y+4);
    pDC->LineTo(x+2,y+7);

    pDC->MoveTo(x+3,y+3);
    pDC->LineTo(x+3,y+6);

    pDC->MoveTo(x+4,y+2);
    pDC->LineTo(x+4,y+5);

    pDC->MoveTo(x+5,y+1);
    pDC->LineTo(x+5,y+4);

    pDC->MoveTo(x+6,y);
    pDC->LineTo(x+6,y+3);

    pDC->SelectObject (pOldPen);
    m_penBack.DeleteObject();
}

BCMenuData *BCMenu::FindMenuList(UINT nID)
{
    for(int i=0;i<=m_MenuList.GetUpperBound();++i){
        if(m_MenuList[i]->nID==nID && !m_MenuList[i]->syncflag){
            m_MenuList[i]->syncflag=1;
            return(m_MenuList[i]);
        }
    }
    return(NULL);
}

void BCMenu::InitializeMenuList(int value)
{
    for(int i=0;i<=m_MenuList.GetUpperBound();++i)
        m_MenuList[i]->syncflag=value;
}

void BCMenu::DeleteMenuList(void)
{
    for(int i=0;i<=m_MenuList.GetUpperBound();++i){
        if(!m_MenuList[i]->syncflag){
            delete m_MenuList[i];
        }
    }
}

void BCMenu::SynchronizeMenu(void)
{
    CTypedPtrArray<CPtrArray, BCMenuData*> temp;
    BCMenuData *mdata;
    CString string;
    UINT submenu,nID=0,state,j;

    InitializeMenuList(0);
    for(j=0;j<GetMenuItemCount();++j){
        mdata=NULL;
        state=GetMenuState(j,MF_BYPOSITION);
        if(state&MF_POPUP){
            submenu=(UINT)GetSubMenu(j)->m_hMenu;
            mdata=FindMenuList(submenu);
            GetMenuString(j,string,MF_BYPOSITION);
            if(!mdata)mdata=NewODMenu(j,
                (state&0xFF)|MF_BYPOSITION|MF_POPUP|MF_OWNERDRAW,submenu,string);
            else if(string.GetLength()>0)
#ifdef UNICODE
                mdata->SetWideString(string);  //SK: modified for dynamic allocation
#else
            mdata->SetAnsiString(string);
#endif
        }
        else if(state&MF_SEPARATOR){
            mdata=FindMenuList(0);
            if(!mdata)mdata=NewODMenu(j,
                state|MF_BYPOSITION|MF_SEPARATOR|MF_OWNERDRAW,0,_T(""));//SK: modified for Unicode correctness
            else ModifyMenu(j,mdata->nFlags,nID,(LPCTSTR)mdata);
        }
        else{
            nID=GetMenuItemID(j);
            mdata=FindMenuList(nID);
            GetMenuString(j,string,MF_BYPOSITION);
            if(!mdata)mdata=NewODMenu(j,state|MF_BYPOSITION|MF_OWNERDRAW,
                nID,string);
            else{
                mdata->nFlags=state|MF_BYPOSITION|MF_OWNERDRAW;
                if(string.GetLength()>0)
#ifdef UNICODE
                    mdata->SetWideString(string);//SK: modified for dynamic allocation
#else
                mdata->SetAnsiString(string);
#endif

                ModifyMenu(j,mdata->nFlags,nID,(LPCTSTR)mdata);
            }
        }
        if(mdata)temp.Add(mdata);
    }
    DeleteMenuList();
    m_MenuList.RemoveAll();
    m_MenuList.Append(temp);
    temp.RemoveAll(); 
}

void BCMenu::UpdateMenu(CMenu *pmenu)
{
#ifdef _CPPRTTI 
    BCMenu *psubmenu = dynamic_cast<BCMenu *>(pmenu);
#else
    BCMenu *psubmenu = (BCMenu *)pmenu;
#endif
    if(psubmenu)psubmenu->SynchronizeMenu();
}

LRESULT BCMenu::FindKeyboardShortcut(UINT nChar, UINT nFlags,
                                     CMenu *pMenu)
{
#ifdef _CPPRTTI 
    BCMenu *pBCMenu = dynamic_cast<BCMenu *>(pMenu);
#else
    BCMenu *pBCMenu = (BCMenu *)pMenu;
#endif
    if(pBCMenu && nFlags&MF_POPUP){
        CString key(_T('&'),2);//SK: modified for Unicode correctness
        key.SetAt(1,(TCHAR)nChar);
        key.MakeLower();
        CString menutext;
        int menusize = (int)pBCMenu->GetMenuItemCount();
        if(menusize!=(pBCMenu->m_MenuList.GetUpperBound()+1))
            pBCMenu->SynchronizeMenu();
        for(int i=0;i<menusize;++i){
            if(pBCMenu->GetMenuText(i,menutext)){
                menutext.MakeLower();
                if(menutext.Find(key)>=0)return(MAKELRESULT(i,2));
            }
        }
    }
    return(0);
}

void BCMenu::DitherBlt (HDC hdcDest, int nXDest, int nYDest, int nWidth, 
                        int nHeight, HBITMAP hbm, int nXSrc, int nYSrc,
                        COLORREF bgcolor)
{
    ASSERT(hdcDest && hbm);
    ASSERT(nWidth > 0 && nHeight > 0);

    // Create a generic DC for all BitBlts
    HDC hDC = CreateCompatibleDC(hdcDest);
    ASSERT(hDC);

    if (hDC)
    {
        // Create a DC for the monochrome DIB section
        HDC bwDC = CreateCompatibleDC(hDC);
        ASSERT(bwDC);

        if (bwDC)
        {
            // Create the monochrome DIB section with a black and white palette
            struct {
                BITMAPINFOHEADER bmiHeader; 
                RGBQUAD      bmiColors[2]; 
            } RGBBWBITMAPINFO = {

                {    // a BITMAPINFOHEADER
                    sizeof(BITMAPINFOHEADER),  // biSize 
                        nWidth,         // biWidth; 
                        nHeight,        // biHeight; 
                        1,            // biPlanes; 
                        1,            // biBitCount 
                        BI_RGB,         // biCompression; 
                        0,            // biSizeImage; 
                        0,            // biXPelsPerMeter; 
                        0,            // biYPelsPerMeter; 
                        0,            // biClrUsed; 
                        0            // biClrImportant; 
                },    
                {
                    { 0x00, 0x00, 0x00, 0x00 }, { 0xFF, 0xFF, 0xFF, 0x00 }
                    } 
            };
            VOID *pbitsBW;
            HBITMAP hbmBW = CreateDIBSection(bwDC,
                (LPBITMAPINFO)&RGBBWBITMAPINFO, DIB_RGB_COLORS, &pbitsBW, NULL, 0);
            ASSERT(hbmBW);

            if (hbmBW)
            {
                // Attach the monochrome DIB section and the bitmap to the DCs
                HBITMAP olddib = (HBITMAP)SelectObject(bwDC, hbmBW);
                HBITMAP hdcolddib = (HBITMAP)SelectObject(hDC, hbm);

                // BitBlt the bitmap into the monochrome DIB section
                BitBlt(bwDC, 0, 0, nWidth, nHeight, hDC, nXSrc, nYSrc, SRCCOPY);

                // Paint the destination rectangle in gray
                FillRect(hdcDest, CRect(nXDest, nYDest, nXDest + nWidth, nYDest +
                    nHeight), GetSysColorBrush(bgcolor));
                //SK: looks better on the old shell
                // BitBlt the black bits in the monochrome bitmap into COLOR_3DHILIGHT
                // bits in the destination DC
                // The magic ROP comes from the Charles Petzold's book
                HBRUSH hb = CreateSolidBrush(GetSysColor(COLOR_3DHILIGHT));
                HBRUSH oldBrush = (HBRUSH)SelectObject(hdcDest, hb);
                BitBlt(hdcDest,nXDest+1,nYDest+1,nWidth,nHeight,bwDC,0,0,0xB8074A);

                // BitBlt the black bits in the monochrome bitmap into COLOR_3DSHADOW
                // bits in the destination DC
                hb = CreateSolidBrush(GetSysColor(COLOR_3DSHADOW));
                DeleteObject(SelectObject(hdcDest, hb));
                BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight,bwDC,0,0,0xB8074A);
                DeleteObject(SelectObject(hdcDest, oldBrush));
                VERIFY(DeleteObject(SelectObject(bwDC, olddib)));
                SelectObject(hDC, hdcolddib);
            }

            VERIFY(DeleteDC(bwDC));
        }

        VERIFY(DeleteDC(hDC));
    }
}

void BCMenu::GetFadedBitmap(CBitmap &bmp)
{
    CDC ddc;
    COLORREF bgcol,col;
    BITMAP BitMap;

    bmp.GetBitmap(&BitMap);
    ddc.CreateCompatibleDC(NULL);
    CBitmap * pddcOldBmp = ddc.SelectObject(&bmp);

    // use this to get the background color, takes into account color shifting
    CDC ddc2;
    CBrush brush;
    CBitmap bmp2;
    ddc2.CreateCompatibleDC(NULL);
    bmp2.CreateCompatibleBitmap(&ddc,BitMap.bmWidth,BitMap.bmHeight);
    col=GetSysColor(COLOR_3DFACE);
    brush.CreateSolidBrush(col);
    CBitmap * pddcOldBmp2 = ddc2.SelectObject(&bmp2);
    CRect rect(0,0,BitMap.bmWidth,BitMap.bmHeight);
    ddc2.FillRect(rect,&brush);
    bgcol=ddc2.GetPixel(1,1);
    brush.DeleteObject();
    ddc2.SelectObject(pddcOldBmp2);

    for(int i=0;i<BitMap.bmWidth;++i){
        for(int j=0;j<BitMap.bmHeight;++j){
            col=ddc.GetPixel(i,j);
            if(col!=bgcol)ddc.SetPixel(i,j,LightenColor(col,0.3));
        }
    }
    ddc.SelectObject(pddcOldBmp);
}

void BCMenu::GetShadowBitmap(CBitmap &bmp)
{
    CDC ddc;
    COLORREF bgcol,col,shadowcol=GetSysColor(COLOR_BTNSHADOW);
    BITMAP BitMap;

    if(!IsWinXPLuna())shadowcol=LightenColor(shadowcol,0.49);
    bmp.GetBitmap(&BitMap);
    ddc.CreateCompatibleDC(NULL);
    CBitmap * pddcOldBmp = ddc.SelectObject(&bmp);

    // use this to get the background color, takes into account color shifting
    CDC ddc2;
    CBrush brush;
    CBitmap bmp2;
    ddc2.CreateCompatibleDC(NULL);
    bmp2.CreateCompatibleBitmap(&ddc,BitMap.bmWidth,BitMap.bmHeight);
    col=GetSysColor(COLOR_3DFACE);
    brush.CreateSolidBrush(col);
    CBitmap * pddcOldBmp2 = ddc2.SelectObject(&bmp2);
    CRect rect(0,0,BitMap.bmWidth,BitMap.bmHeight);
    ddc2.FillRect(rect,&brush);
    bgcol=ddc2.GetPixel(1,1);
    brush.DeleteObject();
    ddc2.SelectObject(pddcOldBmp2);

    for(int i=0;i<BitMap.bmWidth;++i){
        for(int j=0;j<BitMap.bmHeight;++j){
            col=ddc.GetPixel(i,j);
            if(col!=bgcol)ddc.SetPixel(i,j,shadowcol);
        }
    }
    ddc.SelectObject(pddcOldBmp);
}


BOOL BCMenu::AddBitmapToImageList(CImageList *bmplist,UINT nResourceID)
{
    BOOL bReturn=FALSE;

    // O.S.
    if (m_bDynIcons){
        bmplist->Add((HICON)nResourceID);
        bReturn=TRUE;
    }
    else{
        HBITMAP hbmp=LoadSysColorBitmap(nResourceID);
        if(hbmp){
            CBitmap bmp;
            bmp.Attach(hbmp);
            if(m_bitmapBackgroundFlag){
                if(bmplist->Add(&bmp,m_bitmapBackground)>=0)bReturn=TRUE;
            }
            else{
                if(bmplist->Add(&bmp,GetSysColor(COLOR_3DFACE))>=0)bReturn=TRUE;
            }
            bmp.Detach();
            DeleteObject(hbmp);
        }
        else{
            CBitmap mybmp;
            if(mybmp.LoadBitmap(nResourceID)){
                if(m_bitmapBackgroundFlag){
                    if(bmplist->Add(&mybmp,m_bitmapBackground)>=0)bReturn=TRUE;
                }
                else{
                    if(bmplist->Add(&mybmp,GetSysColor(COLOR_3DFACE))>=0)bReturn=TRUE;
                }
            }
        }
    }
    if(bReturn&&IsLunaMenuStyle()&&xp_draw_3D_bitmaps){
        CWnd *pWnd = AfxGetMainWnd();            // Get main window
        if (pWnd == NULL) pWnd = CWnd::GetDesktopWindow();
        CDC *pDC = pWnd->GetDC();              // Get device context
        CBitmap bmp,bmp2;
        GetBitmapFromImageList(pDC,bmplist,0,bmp);
        GetFadedBitmap(bmp);
        bmplist->Add(&bmp,GetSysColor(COLOR_3DFACE));
        GetBitmapFromImageList(pDC,bmplist,0,bmp2);
        GetShadowBitmap(bmp2);
        bmplist->Add(&bmp2,GetSysColor(COLOR_3DFACE));
        pWnd->ReleaseDC(pDC);  // Release the DC
    }
    return(bReturn);
}

void BCMenu::SetBitmapBackground(COLORREF color)
{
    m_bitmapBackground=color;
    m_bitmapBackgroundFlag=TRUE;
}

void BCMenu::UnSetBitmapBackground(void)
{
    m_bitmapBackgroundFlag=FALSE;
}

// Given a toolbar, append all the options from it to this menu
// Passed a ptr to the toolbar object and the toolbar ID
// Author : Robert Edward Caldecott
void BCMenu::AddFromToolBar(CToolBar* pToolBar, int nResourceID)
{
    for (int i = 0; i < pToolBar->GetCount(); i++) {
        UINT nID = pToolBar->GetItemID(i);
        // See if this toolbar option
        // appears as a command on this
        // menu or is a separator
        if (nID == 0 || GetMenuState(nID, MF_BYCOMMAND) == 0xFFFFFFFF)
            continue; // Item doesn't exist
        UINT nStyle;
        int nImage;
        // Get the toolbar button info
        pToolBar->GetButtonInfo(i, nID, nStyle, nImage);
        // OK, we have the command ID of the toolbar
        // option, and the tollbar bitmap offset
        int nLoc;
        BCMenuData* pData;
        BCMenu *pSubMenu = FindMenuOption(nID, nLoc);
        if (pSubMenu && nLoc >= 0)pData = pSubMenu->m_MenuList[nLoc];
        else {
            // Create a new BCMenuData structure
            pData = new BCMenuData;
            m_MenuList.Add(pData);
        }
        // Set some default structure members
        pData->menuIconNormal = nResourceID;
        pData->nID = nID;
        pData->nFlags =  MF_BYCOMMAND | MF_OWNERDRAW;
        pData->xoffset = nImage;
        if (pData->bitmap)pData->bitmap->DeleteImageList();
        else pData->bitmap = new CImageList;
        pData->bitmap->Create(m_iconX, m_iconY,ILC_COLORDDB|ILC_MASK, 1, 1);

        if(!AddBitmapToImageList(pData->bitmap, nResourceID)){
            pData->bitmap->DeleteImageList();
            delete pData->bitmap;
            pData->bitmap=NULL;
            pData->menuIconNormal = -1;
            pData->xoffset = -1;
        }

        // Modify our menu
        ModifyMenu(nID,pData->nFlags,nID,(LPCTSTR)pData);
    }
}

BOOL BCMenu::Draw3DCheckmark(CDC *dc, const CRect& rc,
                             BOOL bSelected, HBITMAP hbmCheck)
{
    CRect rcDest = rc;
    CBrush brush;
    COLORREF col;
    if(IsWinXPLuna())col=GetSysColor(COLOR_3DFACE);
    else col=GetSysColor(COLOR_MENU);
    if(!bSelected)col = LightenColor(col,0.6);
    brush.CreateSolidBrush(col);
    dc->FillRect(rcDest,&brush);
    brush.DeleteObject();
    if (IsNewShell()) //SK: looks better on the old shell
        dc->DrawEdge(&rcDest, BDR_SUNKENOUTER, BF_RECT);
    if (!hbmCheck)DrawCheckMark(dc,rc.left+4,rc.top+4,GetSysColor(COLOR_MENUTEXT));
    else DrawRadioDot(dc,rc.left+5,rc.top+4,GetSysColor(COLOR_MENUTEXT));
    return TRUE;
}

BOOL BCMenu::DrawXPCheckmark(CDC *dc, const CRect& rc, HBITMAP hbmCheck,COLORREF &colorout)
{
    CBrush brushin;
    brushin.CreateSolidBrush(LightenColor(colorout,0.85));
    dc->FillRect(rc,&brushin);
    brushin.DeleteObject();
    dc->Draw3dRect (rc,colorout,colorout);
    if (!hbmCheck)DrawCheckMark(dc,rc.left+5,rc.top+4,GetSysColor(COLOR_MENUTEXT));
    else DrawRadioDot(dc,rc.left+5,rc.top+4,GetSysColor(COLOR_MENUTEXT));
    return TRUE;
}

void BCMenu::DitherBlt2(CDC *drawdc, int nXDest, int nYDest, int nWidth, 
                        int nHeight, CBitmap &bmp, int nXSrc, int nYSrc,
                        COLORREF bgcolor)
{
    // create a monochrome memory DC
    CDC ddc;
    ddc.CreateCompatibleDC(0);
    CBitmap bwbmp;
    bwbmp.CreateCompatibleBitmap(&ddc, nWidth, nHeight);
    CBitmap * pddcOldBmp = ddc.SelectObject(&bwbmp);

    CDC dc;
    dc.CreateCompatibleDC(0);
    CBitmap * pdcOldBmp = dc.SelectObject(&bmp);

    // build a mask
    ddc.PatBlt(0, 0, nWidth, nHeight, WHITENESS);
    dc.SetBkColor(GetSysColor(COLOR_BTNFACE));
    ddc.BitBlt(0, 0, nWidth, nHeight, &dc, nXSrc,nYSrc, SRCCOPY);
    dc.SetBkColor(GetSysColor(COLOR_BTNHILIGHT));
    ddc.BitBlt(0, 0, nWidth, nHeight, &dc, nXSrc,nYSrc, SRCPAINT);

    // Copy the image from the toolbar into the memory DC
    // and draw it (grayed) back into the toolbar.
    dc.FillSolidRect(0,0, nWidth, nHeight, bgcolor);
    //SK: Looks better on the old shell
    dc.SetBkColor(RGB(0, 0, 0));
    dc.SetTextColor(RGB(255, 255, 255));
    CBrush brShadow, brHilight;
    brHilight.CreateSolidBrush(GetSysColor(COLOR_BTNHILIGHT));
    brShadow.CreateSolidBrush(GetSysColor(COLOR_BTNSHADOW));
    CBrush * pOldBrush = dc.SelectObject(&brHilight);
    dc.BitBlt(0,0, nWidth, nHeight, &ddc, 0, 0, 0x00E20746L);
    drawdc->BitBlt(nXDest+1,nYDest+1,nWidth, nHeight, &dc,0,0,SRCCOPY);
    dc.BitBlt(1,1, nWidth, nHeight, &ddc, 0, 0, 0x00E20746L);
    dc.SelectObject(&brShadow);
    dc.BitBlt(0,0, nWidth, nHeight, &ddc, 0, 0, 0x00E20746L);
    drawdc->BitBlt(nXDest,nYDest,nWidth, nHeight, &dc,0,0,SRCCOPY);
    // reset DCs
    ddc.SelectObject(pddcOldBmp);
    ddc.DeleteDC();
    dc.SelectObject(pOldBrush);
    dc.SelectObject(pdcOldBmp);
    dc.DeleteDC();

    brShadow.DeleteObject();
    brHilight.DeleteObject();
    bwbmp.DeleteObject();
}

void BCMenu::SetDisableOldStyle(void)
{
    disable_old_style=TRUE;
}

void BCMenu::UnSetDisableOldStyle(void)
{
    disable_old_style=FALSE;
}

BOOL BCMenu::GetDisableOldStyle(void)
{
    return(disable_old_style);
}


WORD BCMenu::NumBitmapColors(LPBITMAPINFOHEADER lpBitmap)
{
    if ( lpBitmap->biClrUsed != 0)
        return (WORD)lpBitmap->biClrUsed;

    switch (lpBitmap->biBitCount){
        case 1:
            return 2;
        case 4:
            return 16;
        case 8:
            return 256;
        default:
            return 0;
    }
    return 0;
}

HBITMAP BCMenu::LoadSysColorBitmap(int nResourceId)
{
    HINSTANCE hInst = 
        AfxFindResourceHandle(MAKEINTRESOURCE(nResourceId),RT_BITMAP);
    HRSRC hRsrc = 
        ::FindResource(hInst,MAKEINTRESOURCE(nResourceId),RT_BITMAP);
    if (hRsrc == NULL){
        hInst = NULL;
        hRsrc = ::FindResource(hInst,MAKEINTRESOURCE(nResourceId),RT_BITMAP);
    }
    if (hRsrc == NULL)return NULL;

    // determine how many colors in the bitmap
    HGLOBAL hglb;
    if ((hglb = LoadResource(hInst, hRsrc)) == NULL)
        return NULL;
    LPBITMAPINFOHEADER lpBitmap = (LPBITMAPINFOHEADER)LockResource(hglb);
    if (lpBitmap == NULL)return NULL;
    WORD numcol = NumBitmapColors(lpBitmap);
    ::FreeResource(hglb);

    if(numcol!=16)return(NULL);

    return AfxLoadSysColorBitmap(hInst, hRsrc, FALSE);
}

BOOL BCMenu::RemoveMenu(UINT uiId,UINT nFlags)
{
    if(MF_BYPOSITION&nFlags){
        UINT uint = GetMenuState(uiId,MF_BYPOSITION);
        if(uint&MF_SEPARATOR && !(uint&MF_POPUP)){
            delete m_MenuList.GetAt(uiId);
            m_MenuList.RemoveAt(uiId);
        }
        else{
            BCMenu* pSubMenu = (BCMenu*) GetSubMenu(uiId);
            if(NULL==pSubMenu){
                UINT uiCommandId = GetMenuItemID(uiId);
                for(int i=0;i<m_MenuList.GetSize(); i++){
                    if(m_MenuList[i]->nID==uiCommandId){
                        delete m_MenuList.GetAt(i);
                        m_MenuList.RemoveAt(i);
                        break;
                    }
                }
            }
            else{
                int numSubMenus = m_SubMenus.GetUpperBound();
                for(int m = numSubMenus; m >= 0; m--){
                    if(m_SubMenus[m]==pSubMenu->m_hMenu){
                        int numAllSubMenus = m_AllSubMenus.GetUpperBound();
                        for(int n = numAllSubMenus; n>= 0; n--){
                            if(m_AllSubMenus[n]==m_SubMenus[m])m_AllSubMenus.RemoveAt(n);
                        }
                        m_SubMenus.RemoveAt(m);
                    }
                }
                int num = pSubMenu->GetMenuItemCount();
                for(int i=num-1;i>=0;--i)pSubMenu->RemoveMenu(i,MF_BYPOSITION);
                for(int i=m_MenuList.GetUpperBound();i>=0;i--){
                    if(m_MenuList[i]->nID==(UINT)pSubMenu->m_hMenu){
                        delete m_MenuList.GetAt(i);
                        m_MenuList.RemoveAt(i);
                        break;
                    }
                }
                delete pSubMenu; 
            }
        }
    }
    else{
        int iPosition =0;
        BCMenu* pMenu = FindMenuOption(uiId,iPosition);
        // bug fix RIA 14th September 2000 
        // failed to return correct value on call to remove menu as the item was 
        // removed twice. The second time its not found 
        // so a value of 0 was being returned 
        if(pMenu) return pMenu->RemoveMenu(iPosition,MF_BYPOSITION); // added return 
    }
    return CMenu::RemoveMenu(uiId,nFlags);
}

BOOL BCMenu::DeleteMenu(UINT uiId,UINT nFlags)
{
    if(MF_BYPOSITION&nFlags){
        UINT uint = GetMenuState(uiId,MF_BYPOSITION);
        if(uint&MF_SEPARATOR && !(uint&MF_POPUP)){
            // make sure it's a separator
            int menulistsize=m_MenuList.GetSize();    
            if(uiId<(UINT)menulistsize){
                CString str=m_MenuList[uiId]->GetString();
                if(str==""){
                    delete m_MenuList.GetAt(uiId);
                    m_MenuList.RemoveAt(uiId);
                }
            }
        }
        else{
            BCMenu* pSubMenu = (BCMenu*) GetSubMenu(uiId);
            if(NULL==pSubMenu){
                UINT uiCommandId = GetMenuItemID(uiId);
                for(int i=0;i<m_MenuList.GetSize(); i++){
                    if(m_MenuList[i]->nID==uiCommandId){
                        delete m_MenuList.GetAt(i);
                        m_MenuList.RemoveAt(i);
                        break;
                    }
                }
            }
            else{
                int numSubMenus = m_SubMenus.GetUpperBound();
                for(int m = numSubMenus; m >= 0; m--){
                    if(m_SubMenus[m]==pSubMenu->m_hMenu){
                        int numAllSubMenus = m_AllSubMenus.GetUpperBound();
                        for(int n = numAllSubMenus; n>= 0; n--){
                            if(m_AllSubMenus[n]==m_SubMenus[m])m_AllSubMenus.RemoveAt(n);
                        }
                        m_SubMenus.RemoveAt(m);
                    }
                }
                int num = pSubMenu->GetMenuItemCount();
                for(int i=num-1;i>=0;--i)pSubMenu->DeleteMenu(i,MF_BYPOSITION);
                for(int i=m_MenuList.GetUpperBound();i>=0;i--){
                    if(m_MenuList[i]->nID==(UINT)pSubMenu->m_hMenu){
                        delete m_MenuList.GetAt(i);
                        m_MenuList.RemoveAt(i);
                        break;
                    }
                }
                delete pSubMenu;
            }
        }
    }
    else{
        int iPosition =0;
        BCMenu* pMenu = FindMenuOption(uiId,iPosition);
        if(pMenu)return pMenu->DeleteMenu(iPosition,MF_BYPOSITION);
    }

    return(CMenu::DeleteMenu(uiId,nFlags));
}


BOOL BCMenu::AppendMenuA(UINT nFlags,UINT nIDNewItem,const char *lpszNewItem,int nIconNormal)
{
    USES_CONVERSION;
    return AppendMenuW(nFlags,nIDNewItem,A2W(lpszNewItem),nIconNormal);
}

BOOL BCMenu::AppendMenuW(UINT nFlags,UINT nIDNewItem,wchar_t *lpszNewItem,int nIconNormal)
{
    return AppendODMenuW(lpszNewItem,nFlags,nIDNewItem,nIconNormal);
}

BOOL BCMenu::AppendMenuA(UINT nFlags,UINT nIDNewItem,const char *lpszNewItem,CImageList *il,int xoffset)
{
    USES_CONVERSION;
    return AppendMenuW(nFlags,nIDNewItem,A2W(lpszNewItem),il,xoffset);
}

BOOL BCMenu::AppendMenuW(UINT nFlags,UINT nIDNewItem,wchar_t *lpszNewItem,CImageList *il,int xoffset)
{
    return AppendODMenuW(lpszNewItem,nFlags,nIDNewItem,il,xoffset);
}

BOOL BCMenu::AppendMenuA(UINT nFlags,UINT nIDNewItem,const char *lpszNewItem,CBitmap *bmp)
{
    USES_CONVERSION;
    return AppendMenuW(nFlags,nIDNewItem,A2W(lpszNewItem),bmp);
}

BOOL BCMenu::AppendMenuW(UINT nFlags,UINT nIDNewItem,wchar_t *lpszNewItem,CBitmap *bmp)
{
    if(bmp){
        CImageList temp;
        temp.Create(m_iconX,m_iconY,ILC_COLORDDB|ILC_MASK,1,1);
        if(m_bitmapBackgroundFlag)temp.Add(bmp,m_bitmapBackground);
        else temp.Add(bmp,GetSysColor(COLOR_3DFACE));
        return AppendODMenuW(lpszNewItem,nFlags,nIDNewItem,&temp,0);
    }
    return AppendODMenuW(lpszNewItem,nFlags,nIDNewItem,NULL,0);
}

BOOL BCMenu::InsertMenuA(UINT nPosition,UINT nFlags,UINT nIDNewItem,const char *lpszNewItem,int nIconNormal)
{
    USES_CONVERSION;
    return InsertMenuW(nPosition,nFlags,nIDNewItem,A2W(lpszNewItem),nIconNormal);
}

BOOL BCMenu::InsertMenuW(UINT nPosition,UINT nFlags,UINT nIDNewItem,wchar_t *lpszNewItem,int nIconNormal)
{
    return InsertODMenuW(nPosition,lpszNewItem,nFlags,nIDNewItem,nIconNormal);
}

BOOL BCMenu::InsertMenuA(UINT nPosition,UINT nFlags,UINT nIDNewItem,const char *lpszNewItem,CImageList *il,int xoffset)
{
    USES_CONVERSION;
    return InsertMenuW(nPosition,nFlags,nIDNewItem,A2W(lpszNewItem),il,xoffset);
}

BOOL BCMenu::InsertMenuW(UINT nPosition,UINT nFlags,UINT nIDNewItem,wchar_t *lpszNewItem,CImageList *il,int xoffset)
{
    return InsertODMenuW(nPosition,lpszNewItem,nFlags,nIDNewItem,il,xoffset);
}

BOOL BCMenu::InsertMenuA(UINT nPosition,UINT nFlags,UINT nIDNewItem,const char *lpszNewItem,CBitmap *bmp)
{
    USES_CONVERSION;
    return InsertMenuW(nPosition,nFlags,nIDNewItem,A2W(lpszNewItem),bmp);
}

BOOL BCMenu::InsertMenuW(UINT nPosition,UINT nFlags,UINT nIDNewItem,wchar_t *lpszNewItem,CBitmap *bmp)
{
    if(bmp){
        CImageList temp;
        temp.Create(m_iconX,m_iconY,ILC_COLORDDB|ILC_MASK,1,1);
        if(m_bitmapBackgroundFlag)temp.Add(bmp,m_bitmapBackground);
        else temp.Add(bmp,GetSysColor(COLOR_3DFACE));
        return InsertODMenuW(nPosition,lpszNewItem,nFlags,nIDNewItem,&temp,0);
    }
    return InsertODMenuW(nPosition,lpszNewItem,nFlags,nIDNewItem,NULL,0);
}

//--------------------------------------------------------------------------
//[21.06.99 rj]
BCMenu* BCMenu::AppendODPopupMenuW(wchar_t *lpstrText)
{
    BCMenu* pSubMenu = new BCMenu;
    pSubMenu->m_unselectcheck=m_unselectcheck;
    pSubMenu->m_selectcheck=m_selectcheck;
    pSubMenu->checkmaps=checkmaps;
    pSubMenu->checkmapsshare=TRUE;
    pSubMenu->CreatePopupMenu();
    AppendODMenuW(lpstrText,MF_POPUP,(UINT)pSubMenu->m_hMenu, -1);
    return pSubMenu;
}

//--------------------------------------------------------------------------
//[21.06.99 rj]
BCMenu* BCMenu::AppendODPopupMenuA(LPCSTR lpstrText)
{
    USES_CONVERSION;
    return AppendODPopupMenuW(A2W(lpstrText));
}

BOOL BCMenu::ImageListDuplicate(CImageList *il,int xoffset,CImageList *newlist)
{
    if (il == NULL||newlist==NULL||xoffset<0) return FALSE;
    HICON hIcon = il->ExtractIcon(xoffset);
    int cx, cy;
    ImageList_GetIconSize(il->m_hImageList, &cx, &cy);
    newlist->Create(cx,cy,ILC_COLORDDB|ILC_MASK,1,1);
    newlist->Add(hIcon);
    ::DestroyIcon(hIcon);
    if(IsLunaMenuStyle()&&xp_draw_3D_bitmaps){
        CWnd *pWnd = AfxGetMainWnd();            // Get main window
        if (pWnd == NULL) pWnd = CWnd::GetDesktopWindow();
        CDC *pDC = pWnd->GetDC();              // Get device context
        CBitmap bmp,bmp2;
        GetBitmapFromImageList(pDC,newlist,0,bmp);
        GetFadedBitmap(bmp);
        newlist->Add(&bmp,GetSysColor(COLOR_3DFACE));
        GetBitmapFromImageList(pDC,newlist,0,bmp2);
        GetShadowBitmap(bmp2);
        newlist->Add(&bmp2,GetSysColor(COLOR_3DFACE));
        pWnd->ReleaseDC(pDC);  // Release the DC
    }
    return TRUE;
}

// 2001-07-12, Damir Valiulin:
//          Added GetSubMenu (LPCTSTR lpszSubMenuName) function
//

CMenu* BCMenu::GetSubMenu(int nPos)
{
    return CMenu::GetSubMenu (nPos);
}

CMenu* BCMenu::GetSubMenu(LPCTSTR lpszSubMenuName)
{
    int num = GetMenuItemCount ();
    CString name;

    for (int i=0; i<num; i++)
    {
        GetMenuString (i, name, MF_BYPOSITION);
        if (name.Compare (lpszSubMenuName) == 0)
        {
            return CMenu::GetSubMenu (i);
        }
    }

    return NULL;
}

BCMenu* BCMenu::GetSubBCMenu(char* pText)
{
    USES_CONVERSION;
    return GetSubBCMenu(A2W(pText));
}

BCMenu* BCMenu::GetSubBCMenu(wchar_t* lpszSubMenuName)
{
    BCMenuData *mdata;
    mdata=FindMenuOption(lpszSubMenuName);
    if(mdata){
        HMENU bchmenu=(HMENU)mdata->nID;
        CMenu *ptr=FromHandle(bchmenu);
        BOOL flag=ptr->IsKindOf(RUNTIME_CLASS( BCMenu ));
        if(flag)return((BCMenu *)ptr);
    }
    return NULL;
}


// Tongzhe Cui, Functions to remove a popup menu based on its name. Seperators
// before and after the popup menu can also be removed if they exist.
int BCMenu::GetMenuPosition(char* pText)
{
    USES_CONVERSION;
    return GetMenuPosition(A2W(pText));
}

int BCMenu::GetMenuPosition(wchar_t* pText)
{
    int i,j;
    BCMenu* psubmenu;
    for(i=0;i<(int)(GetMenuItemCount());++i)
    {
        psubmenu=(BCMenu *)GetSubMenu(i);
        if(!psubmenu)
        {
            const wchar_t *szWide;//SK: we use const to prevent misuse of this Ptr
            for(j=0;j<=m_MenuList.GetUpperBound();++j)
            {     
                szWide = m_MenuList[j]->GetWideString ();
                if(szWide && !wcscmp(pText,szWide))//SK: modified for dynamic allocation
                    return j;
            }
        }
    }
    // means no found;
    return -1;
}

int BCMenu::RemoveMenu(char* pText, BC_Seperator sPos)
{
    USES_CONVERSION;
    return RemoveMenu(A2W(pText), sPos);
}

int BCMenu::RemoveMenu(wchar_t* pText, BC_Seperator sPos)
{
    int nPos = GetMenuPosition(pText);
    if(nPos != -1)
    {
        RemoveMenu(nPos, MF_BYPOSITION);
    }
    if(sPos == BCMENU_HEAD)
    {
        ASSERT(nPos - 1 >= 0);
        RemoveMenu(nPos-1, MF_BYPOSITION);
    }
    else if(sPos == BCMENU_TAIL)
    {
        RemoveMenu(nPos-1, MF_BYPOSITION);
    }
    else if(sPos == BCMENU_BOTH)
    {
        // remove the end first;
        RemoveMenu(nPos-1, MF_BYPOSITION);
        // remove the head;
        ASSERT(nPos - 1 >= 0);
        RemoveMenu(nPos-1, MF_BYPOSITION);
    }
    return nPos;
}

int BCMenu::DeleteMenu(char* pText, BC_Seperator sPos)
{
    USES_CONVERSION;
    return DeleteMenu(A2W(pText), sPos);
}

int BCMenu::DeleteMenu(wchar_t* pText, BC_Seperator sPos)
{
    int nPos = GetMenuPosition(pText);
    if(nPos != -1)
    {
        DeleteMenu(nPos, MF_BYPOSITION);
    }
    if(sPos == BCMENU_HEAD)
    {
        ASSERT(nPos - 1 >= 0);
        DeleteMenu(nPos-1, MF_BYPOSITION);
    }
    else if(sPos == BCMENU_TAIL)
    {
        DeleteMenu(nPos-1, MF_BYPOSITION);
    }
    else if(sPos == BCMENU_BOTH)
    {
        // remove the end first;
        DeleteMenu(nPos-1, MF_BYPOSITION);
        // remove the head;
        ASSERT(nPos - 1 >= 0);
        DeleteMenu(nPos-1, MF_BYPOSITION);
    }
    return nPos;
}

// Larry Antram
BOOL BCMenu::SetMenuText(UINT id, CString string, UINT nFlags/*= MF_BYPOSITION*/ )
{
    BOOL returnflag=FALSE;

    if(MF_BYPOSITION&nFlags)
    {
        UINT numMenuItems = m_MenuList.GetUpperBound();
        if(id<=numMenuItems){
#ifdef UNICODE
            m_MenuList[id]->SetWideString((LPCTSTR)string);
#else
            m_MenuList[id]->SetAnsiString(string);
#endif
            returnflag=TRUE;
        }
    }
    else{
        int uiLoc;
        BCMenu* pMenu = FindMenuOption(id,uiLoc);
        if(NULL!=pMenu) returnflag = pMenu->SetMenuText(uiLoc,string);
    }
    return(returnflag);
}

// courtesy of Warren Stevens
void BCMenu::ColorBitmap(CDC* pDC,CBitmap& bmp,CSize bitmap_size,CSize icon_size,COLORREF fill,COLORREF border,int hatchstyle)
{
    CDC bmpdc;
    COLORREF m_newclrBack;
    int x1=0,y1=0,x2=bitmap_size.cx,y2=bitmap_size.cy;

    if(IsWinXPLuna())m_newclrBack=GetSysColor(COLOR_3DFACE);
    else m_newclrBack=GetSysColor(COLOR_MENU);

    bmpdc.CreateCompatibleDC(pDC);

    bmp.CreateCompatibleBitmap(pDC, icon_size.cx, icon_size.cy);    
    CBitmap* pOldBitmap = bmpdc.SelectObject(&bmp);

    if(bitmap_size!=icon_size){
        CBrush background_brush;
        background_brush.CreateSolidBrush(m_newclrBack);
        CRect rect(0,0, icon_size.cx, icon_size.cy);
        bmpdc.FillRect(rect,&background_brush);
        x1 = (icon_size.cx-bitmap_size.cx)/2;
        y1 = (icon_size.cy-bitmap_size.cy)/2;
        x2 = x1+bitmap_size.cx;
        y2 = y1+bitmap_size.cy;
        background_brush.DeleteObject();
    }

    CPen border_pen(PS_SOLID, 1, border);
    CBrush fill_brush;
    if(hatchstyle!=-1) { fill_brush.CreateHatchBrush(hatchstyle, fill); }
    else      { fill_brush.CreateSolidBrush(fill);             }

    CPen*    pOldPen    = bmpdc.SelectObject(&border_pen);
    CBrush*  pOldBrush  = bmpdc.SelectObject(&fill_brush);

    bmpdc.Rectangle(x1,y1,x2,y2);

    if(NULL!=pOldBrush)  { bmpdc.SelectObject(pOldBrush);  }
    if(NULL!=pOldPen)    { bmpdc.SelectObject(pOldPen);    }
    if(NULL!=pOldBitmap) { bmpdc.SelectObject(pOldBitmap); }
}

BOOL BCMenu::IsWindowsClassicTheme(void)
{
    TCHAR Buf[_MAX_PATH+10];
    HKEY hKey;
    DWORD size,type; 
    long lRetCode; 
    static BOOL XPTheme_returnflag=FALSE;
    static BOOL XPTheme_checkflag=FALSE;

    if(XPTheme_checkflag)return(XPTheme_returnflag);

    XPTheme_checkflag=TRUE;
    lRetCode = RegOpenKeyEx ( HKEY_CURRENT_USER, 
        _T("Software\\Microsoft\\Plus!\\Themes\\Current"), 
        0,KEY_READ,&hKey);  
    if (lRetCode == ERROR_SUCCESS){ 
        size = _MAX_PATH;type=REG_SZ;
        lRetCode=::RegQueryValueEx(hKey,NULL,NULL,&type,
            (unsigned char *)Buf,&size);
        if(lRetCode == ERROR_SUCCESS){
            TCHAR szClassicTheme[]=_T("Windows Classic.theme");
            int len=lstrlen(Buf);
            if(len>=lstrlen(szClassicTheme)){
                if(!lstrcmpi(&Buf[len-lstrlen(szClassicTheme)],szClassicTheme)){
                    XPTheme_returnflag=TRUE;
                }
            }
        }
        RegCloseKey(hKey);  
    }
    return(XPTheme_returnflag);
}

int BCMenu::GlobalImageListOffset(int nID)
{
    int numcurrent=m_AllImagesID.GetSize();
    int existsloc = -1;
    for(int i=0;i<numcurrent;++i){
        if(m_AllImagesID[i]==nID){
            existsloc=i;
            break;
        }
    }
    return existsloc;
}

BOOL BCMenu::CanDraw3DImageList(int offset)
{
    BOOL retflag=FALSE;
    int numcurrent=m_AllImagesID.GetSize();
    if(offset+1<numcurrent&&offset+2<numcurrent){
        int nID=m_AllImagesID[offset];
        if(m_AllImagesID[offset+1]==nID&&m_AllImagesID[offset+2]==nID)retflag=TRUE;
    }
    return(retflag);
}

int BCMenu::AddToGlobalImageList(CImageList *il,int xoffset,int nID)
{
    int loc = -1;
    HIMAGELIST hImageList = m_AllImages.m_hImageList;
    if(!hImageList){
        m_AllImages.Create(m_iconX,m_iconY,ILC_COLORDDB|ILC_MASK,1,1);
    }
    HICON hIcon = il->ExtractIcon(xoffset);
    if(hIcon){
        CBitmap bmp,bmp2;
        if(IsLunaMenuStyle()&&xp_draw_3D_bitmaps){
            CWnd *pWnd = AfxGetMainWnd();            // Get main window
            if (pWnd == NULL) pWnd = CWnd::GetDesktopWindow();
            CDC *pDC = pWnd->GetDC();              // Get device context
            GetBitmapFromImageList(pDC,il,xoffset,bmp);
            GetFadedBitmap(bmp);
            GetBitmapFromImageList(pDC,il,xoffset,bmp2);
            GetShadowBitmap(bmp2);
            pWnd->ReleaseDC(pDC);  // Release the DC
        }
        int numcurrent=m_AllImagesID.GetSize();
        int existsloc = -1;
        for(int i=0;i<numcurrent;++i){
            if(m_AllImagesID[i]==nID){
                existsloc=i;
                break;
            }
        }
        if(existsloc>=0){
            m_AllImages.Replace(existsloc,hIcon);
            loc = existsloc;
            if(IsLunaMenuStyle()&&xp_draw_3D_bitmaps){
                if(existsloc+1<numcurrent&&m_AllImagesID[existsloc+1]==nID){
                    if(existsloc+2<numcurrent&&m_AllImagesID[existsloc+2]==nID){
                        CImageList il2;
                        il2.Create(m_iconX,m_iconY,ILC_COLORDDB|ILC_MASK,1,1);
                        il2.Add(&bmp,GetSysColor(COLOR_3DFACE));
                        HICON hIcon2 = il2.ExtractIcon(0);
                        m_AllImages.Replace(existsloc+1,hIcon2);
                        il2.Add(&bmp2,GetSysColor(COLOR_3DFACE));
                        HICON hIcon3 = il2.ExtractIcon(1);
                        m_AllImages.Replace(existsloc+2,hIcon3);
                        ::DestroyIcon(hIcon2);
                        ::DestroyIcon(hIcon3);
                    }
                }
            }
        }
        else{
            m_AllImages.Add(hIcon);
            m_AllImagesID.Add(nID);
            loc=numcurrent;
            if(IsLunaMenuStyle()&&xp_draw_3D_bitmaps){
                m_AllImages.Add(&bmp,GetSysColor(COLOR_3DFACE));
                m_AllImages.Add(&bmp2,GetSysColor(COLOR_3DFACE));
                m_AllImagesID.Add(nID);
                m_AllImagesID.Add(nID);
            }
        }
        ::DestroyIcon(hIcon);
    }
    return(loc);
}

//*************************************************************************

/////////////////////////////////////////////////////////////////////////////
// Toolbar for loading images
/////////////////////////////////////////////////////////////////////////////

struct CToolBarData
{
    WORD wVersion;
    WORD wWidth;
    WORD wHeight;
    WORD wItemCount;
    WORD* items(){
        return (WORD*)(this+1);
    }
};

BOOL BCMenuToolBar::LoadToolBar(LPCTSTR lpszResourceName)
{
    ASSERT_VALID(this);
    ASSERT(lpszResourceName != NULL);

    HINSTANCE hInst = AfxFindResourceHandle(lpszResourceName,RT_TOOLBAR);
    HRSRC hRsrc = ::FindResource(hInst,lpszResourceName,RT_TOOLBAR);
    if (hRsrc == NULL){
        hInst = NULL;
        hRsrc = ::FindResource(hInst,lpszResourceName,RT_TOOLBAR);
    }
    if (hRsrc == NULL)
        return FALSE;

    HGLOBAL hGlobal = ::LoadResource(hInst,hRsrc);
    if (hGlobal == NULL)
        return FALSE;

    CToolBarData* pData = (CToolBarData*)::LockResource(hGlobal);
    if (pData == NULL)
        return FALSE;
    ASSERT(pData->wVersion == 1);

    UINT* pItems = new UINT[pData->wItemCount];
    for (int i = 0; i < pData->wItemCount; i++)
        pItems[i] = pData->items()[i];
    BOOL bResult = SetButtons(pItems,pData->wItemCount);
    delete[] pItems;

    if (bResult){
        CSize sizeImage(pData->wWidth,pData->wHeight);
        CSize sizeButton(pData->wWidth+7,pData->wHeight+7);
        SetSizes(sizeButton,sizeImage);
        m_iconX=pData->wWidth;
        m_iconY=pData->wHeight;
        bResult = LoadBitmap(lpszResourceName);
    }

    ::UnlockResource(hGlobal);
    ::FreeResource(hGlobal);
    return bResult;
}

BOOL BCMenuToolBar::LoadBitmap(LPCTSTR lpszResourceName)
{
    ASSERT_VALID(this);
    ASSERT(lpszResourceName != NULL);

    HINSTANCE hInstImageWell = AfxFindResourceHandle(lpszResourceName,RT_BITMAP);
    HRSRC hRsrcImageWell = ::FindResource(hInstImageWell,lpszResourceName,RT_BITMAP);
    if (hRsrcImageWell == NULL){
        hInstImageWell = NULL;
        hRsrcImageWell = ::FindResource(hInstImageWell,lpszResourceName,RT_BITMAP);
    }
    if (hRsrcImageWell == NULL)
        return FALSE;

    HBITMAP hbmImageWell;
    hbmImageWell = AfxLoadSysColorBitmap(hInstImageWell,hRsrcImageWell);

    if (!AddReplaceBitmap(hbmImageWell))
        return FALSE;

    m_hInstImageWell = hInstImageWell;
    m_hRsrcImageWell = hRsrcImageWell;
    return TRUE;
}

CButtonST使本人当下见过的最强劲,效能最全的CButton派生类。撰写本文的目标不在于本事的商酌,而是希望可感觉各位提供有关CButtonST的利用参谋,以增加编写程序的速度。

 

下图是用CButtonST做的多少个开关

 

亚洲必赢手机入口 1 

 

以下是CButtonST类的一对版本信息,方便我们能够即时得到它的新型版本。

CButtonST类简介

作者:Davide Calabro

1 本章经典

CButtonST是效果极其全的CButton派生类,利用它你能够兑现种种开关的功力,它总结的特点如下:

1、    CButton全数的功用

2、    文字和Logo按键

3、    16×16,32×32,48×48,16或256色Logo的辅助

4、    协理透明按键

5、    援救规范的或新的平面按键风格

6、    运转时刻开关风格的改换

7、    鼠标悬浮在按键上时Logo的变化

8、    支持tooltips

9、    每一种开关能够有投机的鼠标形状

10、 按键颜色能够定制

下图是用CButtonST做的几个按键

 

图1

CButtonST类首要富含BtnST.h、BtnST.cpp、BCMenu.h和BCMenu.cpp多个文本。借使您策动采纳CButtonST的窗口不独有三个,那么本人建议您在VC++的Workspace | FileView中程导弹入以上的八个文件之后,然后在SdtAfx.h文件中增加合适的include语句,如#include
“BtnST.h”。

在接下去的几篇小说中,笔者将依附属小学编提供的亲自过问程序向大家介绍CButtonST的各个常用方法。在最后一篇小说中,将为各位提供CButtonST类的中文文书档案,以供各位在后来的施用中参阅。

 

2  CButtonST使用本领(一)

本节第一归纳了以下的功能:
1. 在开关上加入Icon,使Icon和文字同一时候出示
2. 来得平面开关
3. 使开关上的Logo可变
4. 安装按键在分化景观下的底色和文字颜色
5. 设置Logo和文字的岗位
6. 传说Icon的形态设置开关的形态
7. 添加Tooltips
以下是Basic Features的自己要作为表率遵循规则界面:

图2

效果与利益一:在开关上参预Icon,使Icon和文字同不平时间体现

倘使按键ID为IDC_BUTTON1

1. 增加成员变量

CButtonST         m_btn;

2. 添加Icon资源,设其ID设为IDI_ICON1
3. 在OnInitDialog函数中初阶化开关

m_btn.SubclassDlgItem(IDC_BUTTON1,this);

m_btn.SetIcon(IDI_ICON1);

m_btn.SetFlat(FALSE);

静心:为达到规定的规范最佳效用,请依据Icon的大大小小调治开关的大大小小。
实例:演示程序中的Standard 开关。

 

功效二:突显平面按键
只须求在职能一的底子上把m_btn.SetFlat(FALSE);语句去掉。

功能三:使按键上的Logo可变
即使开关ID为IDC_BUTTON1
1. 增多成员变量

CButtonST  m_btn;

2. 增添五个Icon能源,ID设为IDI_ICON1和IDI_ICON2
IDI_ICON1是日常状态的Logo,IDI_ICON2是按下时的Logo
3. 在OnInitDialog函数中开头化开关

m_btn.SubclassDlgItem(IDC_BUTTON1,this);

m_btn.SetIcon(IDI_ICON2,IDI_ICON1);

实例:演示程序中的哈尔loween 按键。

意义四:设置开关在差异情况下的底色和文字颜色 
若是按键ID为IDC_BUTTON1
1. 增添成员变量

CButtonST  m_btn;

2. 添加Icon资源,设其ID设为IDI_ICON1
3. 在OnInitDialog函数中开端化按键

m_btn.SubclassDlgItem(IDC_BUTTON1,this);

m_btn.SetIcon(IDI_ICON1);

m_btn.SetColor(CButtonST::BTNST_COLOR_BK_OUT, RGB(208,208,208));

m_btn.SetColor(CButtonST::BTNST_COLOR_BK_FOCUS, RGB(208,208,208));

m_btn.OffsetColor(CButtonST::BTNST_COLOR_BK_IN, 30);

升迁:SetColor函数和OffsetColor函数的率先个参数表示开关的逐一状态,前景色正是文字的颜料,它们的取值表示:

BTNST_COLOR_BK_IN                  //鼠标放在按键内时的背景观

BTNST_COLOR_FG_IN,                  //鼠标放在开关内时的前景观

BTNST_COLOR_BK_OUT,             //普通状态时的背景象  

BTNST_COLOR_FG_OUT,             //普通状态时的前景象

BTNST_COLOR_BK_FOCUS,         //开关被按下后的背景象

BTNST_COLOR_FG_FOCUS,         //按键被按下后的前景象

实例:演示程序中的48×48 icon 按键、Zip开关等。

功用五:设置Logo和文字的岗位
借使按键ID为IDC_BUTTON1
1.增添成员变量

CButtonST  m_btn;

2.添加Icon资源,ID设为IDI_ICON1
3.在OnInitDialog函数中开头化开关

m_btn.SubclassDlgItem(IDC_BUTTON1,this);

m_btn.SetIcon(IDI_ICON1);

m_btn.SetAlign(CButtonST::ST_ALIGN_VERT);

提拔:SetAlign函数的首先个参数表示地方新闻,缺省事态下,文字在Logo侧边

ST_ALIGN_HO福睿斯IZ       // 文字在右

ST_ALIGN_VERT         //文字在下

ST_ALIGN_HORIZ_RubiconIGHT// 文字在左

实例:演示程序中的Search 开关。

功效六:依据Icon的形态设置开关的形态
万一按键ID为IDC_BUTTON1
1.加多成员变量

CButtonST               m_btn;

2.添加Icon资源,设其ID设为IDI_ICON1
3.在OnInitDialog函数中开首化按键

m_btn.SubclassDlgItem(IDC_BUTTON1,this);

m_btn.SetIcon(IDI_ICON1);

m_btn.DrawBorder(FALSE);

m_btn.SetColor(CButtonST::BTNST_COLOR_BK_OUT, RGB(208,208,208));

m_btn.SetColor(CButtonST::BTNST_COLOR_BK_IN, RGB(208,208,208));

m_btn.SetColor(CButtonST::BTNST_COLOR_BK_FOCUS, RGB(208,208,208));

在意:为达到规定的标准最棒效果,请依照Icon的轻重调度按键的高低。
并依据实际情状设置背景颜色。请事先将开关的文字去掉。

效果七:添加Tooltips
若是按键ID为IDC_BUTTON1
1.增添分子变量

CButtonST  m_btn;

2.添加Icon资源,设其ID设为IDI_ICON1
3. 在OnInitDialog函数中开端化开关

m_btn.SubclassDlgItem(IDC_BUTTON1,this);

m_btn.SetIcon(IDI_ICON1);

m_btn.SetTooltipText(_T(“This is a tooltip./r/nMultiline!”));

 

3  CButtonST使用技能(二)

本节最主要不外乎了以下的效率:
1. 转移鼠标步向开关时的形状(超链接效果)
2. 美食做法开关
3. 位图按键
4. 开关核心
5. CheckBox按钮
6. 晶莹剔透开关(开关背景和窗口背景一样)
7. 特殊的PictureBox

效果与利益一:退换鼠标走入开关时的形制(超链接效果)
若果按键ID为IDC_BUTTON1
1. 加多成员变量

CButtonST    m_btn;

2. 添加Icon资源,设其ID设为IDI_ICON1
3. 在OnInitDialog函数中初阶化开关

m_btn.SubclassDlgItem(IDC_BUTTON1,this);

m_btn.SetIcon(IDI_ICON1);

m_btn.OffsetColor(CButtonST::BTNST_COLOR_BK_IN, 30);

m_btn.SetURL("www.scut.edu.cn");

m_btn.SetTooltipText("www.scut.edu.cn");

m_btn.SetBtnCursor(IDC_CURSOR1);


效果二:菜单按键

借使开关ID为IDC_BUTTON1
1.增加成员变量

CButtonST    m_btn;

2. 添加Icon资源,设其ID设为IDI_ICON1
3. 添加Menu,ID设为IDR_MENU
4. 在OnInitDialog函数中伊始化按钮

m_btn.SubclassDlgItem(IDC_BUTTON1,this);

m_btn.SetIcon(IDI_ICON1);

m_btn.OffsetColor(CButtonST::BTNST_COLOR_BK_IN, 30);

m_btn.SetMenu(IDR_MENU, m_hWnd);

只顾:菜单的作用类似与右键菜单,全数在装置菜单选项时只设置一列就够了。别的菜单的增加率与菜单的文字长度有关,能够用空格占位的格局以达到最好功能。

在菜单中引进位图的点子
1.增加ToolBar,依次使用Menu菜单项ID作为ToolBar开关的ID。
2.ToolBar上的开关图标将显示在相应的菜单项中。
将方面代码中的m_btn.SetMenu(IDR_亚洲必赢手机入口,MENU, m_hWnd);
改为m_btn.SetMenu(IDR_MENU, m_hWnd, TRUE, IDR_TOOLBAR);
IDR_TOOLBAR为相应ToolBar的ID。

功效三:位图按键
一经开关ID为IDC_BUTTON1
1.增多成员变量

CButtonST    m_btn;

2.增添位图能源,ID设为IDB_BITMAP1
3.在OnInitDialog函数中伊始化按键

m_btn.SubclassDlgItem(IDC_BUTTON1,this);     

m_btn.SetBitmaps(IDB_BITMAP1,RGB(0,0,0));

m_btn.OffsetColor(CButtonST::BTNST_COLOR_BK_IN, 30);

提示: 上边的SetBitmaps函数会将图纸中颜色值为传祺GB(0,0,0)的点设为透明。

效果四:按键大旨
譬喻按钮ID为IDC_BUTTON1
1.加多成员变量

CButtonST    m_btn;

2. 添加Icon资源,设其ID设为IDI_ICON1
3. 在OnInitDialog函数中早先化开关

m_btn.SubclassDlgItem(IDC_BUTTON1,this);

m_btn.SetIcon(IDI_ICON1);

m_btn.SetAlign(CButtonST::ST_ALIGN_VERT);

m_btn.DrawFlatFocus(TRUE);

效果五:CheckBox按钮

只要按键ID为IDC_BUTTON1
1.增添分子变量

CButtonST    m_btn;

2. 添加Icon资源,ID设为IDI_ICON1和IDI_ICON2
3.在OnInitDialog函数中开始化按键

m_btn.SubclassDlgItem(IDC_CHECK1,this);

m_btn.SetIcon(IDI_ICON1,IDI_ICON2);

m_btn.OffsetColor(CButtonST::BTNST_COLOR_BK_IN, 30);

提示:
IDI_ICON1为当选时候显得的Logo
IDI_ICON2为为当选时候的Logo

职能六:透明开关
比如按键ID为IDC_BUTTON1
1.增添成员变量

CButtonST    m_btn;

2. 添加Icon资源,ID设为IDI_ICON1
3.在OnInitDialog函数中初叶化按键

m_btn.SubclassDlgItem(IDC_BUTTON1,this);

m_btn.SetIcon(IDI_ICON1);

m_btn.DrawTransparent(TRUE);


效果七:特殊的PictureBox

选拔CButtonST的离奇显示风格,完全可以把它作为八个PictureBox控件使用。那时一般会把开关的属性设置为disable。
实例:演示程序的About页中行使了CButtonST来替代Picture博克斯。

 

4  CButtonST使用技巧(三)

本节将介绍多少个CButtonST的派生类。

一、CWinXPButtonST类
CWinXPButtonST类 是三个CButtonST的派生类。它的特点是应用了WindowsXP中的圆角、玉米黄边框的风格。它富含WinXPButtonST.h和WinXPButtonST.cpp两个文件,而鉴于它是从CButtonST派生而来的,所以在援用它时,也要一并引进CButtonST的文本。
使用:
1. 引进文件,添Gavin件
2. 导入文本后,在SdtAfx.h文件中增添

#include “WinXPButtonST.h”

3. 加多成员变量

CWinXPButtonST            m_btn2;

4. 万一按键ID为IDC_BUTTON
添加Icon资源,ID设为IDI_ICON1
5. 在OnInitDialog函数中初步化开关

m_btn2.SubclassDlgItem(IDC_BUTTON,this);

m_btn2.SetIcon(IDI_ICON1);

m_btn2.SetRounded(TRUE);

在意:不过它存在一个相差的地点,便是按键的圆角是画出来的,开关的样子仍旧是原本的矩形。所以假诺在有背景观的窗口中动用该按键的话就能够来得特别碍眼。
如图所示,在群青的背景观中体现出难看的尖角:

图3

杀鸡取蛋的不二等秘书技是经过SetColor函数使得开关的底色与窗口的底色一致。 

二、CShadeButtonST类
CShadeButtonST类 是CButtonST的另贰个派生类。它的性格是帮忙越发各个化的背景,通过SetShade函数可认为按键设置9种不通的背景效果。它总结八个公文,它们分别是CeXDib.h、CeXDib.cpp、ShadeButtonST.h和ShadeButtonST.cpp。在引用它时,同样要一并引进CButtonST的文件。
使用:
1.引进文件,添Gavin书
2.导入文本后,在SdtAfx.h文件中增添

#include “ShadeButtonST.h”

3.增添成员变量

CShadeButtonST             m_btn3;

4.若是按键ID为IDC_BUTTON3
添加Icon资源,ID设为IDI_ICON1
5.在OnInitDialog函数中起头化开关

m_btn3.SubclassDlgItem(IDC_BUTTON3,this);

m_btn3.SetIcon(IDI_ICON1);

m_btn3.SetShade(CShadeButtonST::SHS_METAL);

上面给出各样背景效果和呼应的参数值。

 

图4

 

 

 

5  CButtonST类公共接口函数

以下是CButtonST类的兼具国有成员函数(函数名按音序排列顺序):

CButtonST::DrawBorder
DWORD DrawBorder(BOOL bDrawBorder = TRUE, BOOL bRepaint = TRUE)

注释:
因为CButtonST的暗中同意显示风格是平面开关。调用此函数用来展示按键边框。

参数:
bDrawBorder: 值为TRUE则显示按键边框。
bRepaint: 值为TRUE则立即重绘开关。

返回值:
BTNST_OK: 函数试行落成。

CButtonST::DrawFlatFocus
DWORD DrawFlatFocus(BOOL bDrawFlatFocus, BOOL bRepaint = TRUE)

注释:
此函数只对平面开关有效,调用此函数能够在按键中展现大旨。

参数:
bDrawFlatFocus : 值为TRUE则会在平面按钮上呈现主旨。
bRepaint : 值为TRUE则立时重画按键。

返回值:
BTNST_OK: 表示函数推行成功。

CButtonST::DrawTransparent
void DrawTransparent(BOOL bRepaint = FALSE)

注释:
调用此函数来激活透显著示情势。注意,此操作是不可逆的,并且必得在按键实例成立之后调用。函数将会在内部存储器中保存一份窗口背景的正片,由此请真正有亟待时才调用此函数,避防浪费内部存款和储蓄器空间。透明情势相似是在含有背景的窗口中行使。

参数:
bRepaint : 为TRUE则立即重绘开关。

CButtonST::OffsetColor
DWORD OffsetColor(BYTE byColorIndex, short shOffset, BOOL bRepaint =
TRUE)

注释:
调用此函数能够安装按键在各个情状下显得内定的底色。函数会依靠所传递的偏移量参数以及开关原本的默许底色发生一个新的颜色值。通过那样的艺术能够使得开关在区别情状下的颜色变化更为自然。

参数:
byColorIndex : 状态索引值,它的取值必须是以下枚举值之一。
取值注释
BTNST_COLOR_BK_IN 鼠标指针位于开关上面时的底色
BTNST_COLOR_FG_IN 鼠标指针位于按键上边时的前景观
BTNST_COLOR_BK_OUT 鼠标指针不在按键下边时的底色
BTNST_COLOR_FG_OUT 鼠标指针不在开关下边时的前景象
BTNST_COLOR_BK_FOCUS 宗旨放在开关上边时的底色
BTNST_COLOR_FG_FOCUS 宗旨放在开关上边时的前景观
*前景象一般是指文字的颜色
shOffsetColor: 钦命颜色的偏移量,它的取值范围是[-255,255]。
bRepaint: 值为TRUE则即刻重绘开关。

返回值:
BTNST_OK : 函数试行成功。
BTNST_INVALIDINDEX : 由 byColorIndex 钦点状态索引值无效。
BTNST_BADPARAM : 根据偏移量生成的值超过智跑GB的水彩取值范围。

CButtonST::SetAlign
DWORD SetAlign(BYTE byAlign, BOOL bRepaint = TRUE)

注释:
调用此函数能够设定按键上海教室标(或位图)于开关上文字的争持地点。

参数:
byAlign: 地点参数,它的取值必得是以下枚举量之一。
取值注释
ST_ALIGN_HO福特ExplorerIZ Logo/图片在左,文字在右
ST_ALIGN_VERT 图标/图片在上,文字在下
ST_ALIGN_HORIZ_KugaIGHT Logo/图片在右,文字在左
暗中同意值为ST_ALIGN_HORIZ. 
bRepaint: 为TRUE则即时重绘按键。

返回值:
BTNST_OK: 函数实践成功。
BTNST_INVALIDALIGN: 地点参数无效。

CButtonST::SetAlwaysTrack
DWORD SetAlwaysTrack(BOOL bAlwaysTrack = TRUE)

注释:
此函数只对平面按键有效。调用此函数能够设定按键是不是出示高亮颜色。

参数:
bAlwaysTrack: 值为TRUE时,无论前窗口是或不是为激活窗口,只要鼠标指针移动到开关上面都会发开关的显得状态爆发变化。暗中同意值为TRUE。
值为FALSE时,假诺窗口未被激活,开关的显得不会发生变化。

返回值:
BTNST_OK : 函数施行成功。

CButtonST::SetBitmaps
DWORD SetBitmaps(int nBitmapIn, COLORREF crTransColorIn, int nBitmapOut
= NULL, COLORREF crTransColorOut = 0)
DWORD SetBitmaps(HBITMAP hBitmapIn, COLORREF crTransColorIn, HBITMAP
hBitmapOut = NULL, COLORREF crTransColorOut = 0)

注释:
调用此函数能够在按键上出示钦点的图纸(Icon)。假诺对同一个按键重复调用了此函数的话,那么按键只突显最终三次内定的图片。

参数:
nBitmapIn: 图片的ID值。当鼠标指针位于开关之上时显示该图形。
crTransColorIn: 颜色值。ID为nBitmapIn的图样中与该颜色同样的区域将呈现透明。
nBitmapOut: 图片的ID值。当鼠标指针不在开关之上时显得该图形。
crTransColorOut: 颜色值。ID为nBitmapOut的图片中与该颜色同样的区域将展现透明。
hBitmapIn: 图片的句柄。当鼠标指针位于按键之上时显得该图片。
crTransColorIn: 颜色值。由hBitmapIn钦点的图片中与该颜色同样的区域将呈现透明。
hBitmapOut: 图片的ID值。当鼠标指针不在按键之上时显示该图片。
crTransColorOut: 颜色值。由hBitmapOut钦定的图片中与该颜色同样的区域将显得透明。

返回值:
BTNST_OK: 函数推行成功。
BTNST_INVALIDRESOURCE: 钦命能源读取失败。
BTNST_FAILEDMASK: 颜色提取失利。

CButtonST::SetBtnCursor
DWORD SetBtnCursor(int nCursorId = NULL, BOOL bRepaint = TRUE)

注释:
那一个函数可以让鼠标在活动到按键上面包车型大巴时候显得钦点的鼠标指针。

参数:
nCursorId: 鼠标指针的ID值。
bRepaint: 值为TRUE则即时重绘按键。

返回值:
BTNST_OK: 函数试行成功。
BTNST_INVALIDRESOURCE: 读取钦点财富失利。

CButtonST::SetCheck
DWORD SetCheck(int nCheck, BOOL bRepaint = TRUE)

注释:
当按键被当作CheckBox使用的时候,用来安装开关的动静。

参数:
nCheck : 1表示当选; 0代表没选中
bRepaint: 值为TRUE则立时重绘开关。

返回值:
BTNST_OK: 函数试行成功。

CButtonST::SetColor
DWORD SetColor(BYTE byColorIndex, COLORREF crColor, BOOL bRepaint =
TRUE)

注释:
调用此函数能够安装开关在各样气象下显得钦赐的底色。

参数:
byColorIndex
: 状态索引值。具体意思能够参见OffsetColor函数中的参数(byColorIndex)表达。
crColor : 颜色值。设置开关内定状态的底色。
bRepaint: 值为TRUE则随即重绘开关。

返回值:
BTNST_OK: 函数实行成功。
BTNST_INVALIDINDEX: 无效的意况索引值。

CButtonST::SetDefaultColors
DWORD SetDefaultColors(BOOL bRepaint = TRUE)

注释:
调用此函数之后,程序将接纳暗许颜色来设定开关在每一个状态下的水彩。那么些颜色值或许会因为Windows版本的例外而分裂。

参数:
bRepaint: 值为TRUE则立时重绘按键。

返回值:
BTNST_OK: 函数试行成功。

CButtonST::SetFlat
DWORD SetFlat(BOOL bFlat = TRUE, BOOL bRepaint = TRUE)

注释:
调用此函数来安装开关的展现风格。

参数:
bFlat: 值为TRUE则呈现为平面按键; 值为FALSE则体现为正规的Windows开关
bRepaint: 值为TRUE则马上重绘开关。

返回值:
BTNST_OK: 函数推行成功。

CButtonST::SetIcon
DWORD SetIcon(int nIconIn, int nIconOut = NULL)
DWORD SetIcon(HICON hIconIn, HICON hIconOut = NULL)

注释:
调用此函数能够在按键上显示内定的Logo(Icon)。尽管对同二个按键重复调用了此函数的话,那么按键只呈现最终二次钦命的Logo。

参数:
nIconIn
: Logo的ID值,当鼠标指针移动到开关上边的时候显得该Logo。假诺该参数被赋值为 NULL ,则分配给这几个开关的具有Logo财富将被释放。
nIconOut: Logo的ID值,当鼠标指针不在按键上边的时候显得该Logo。调用函数的时候能够忽略该参数。
hIconIn
: Logo的句柄,当鼠标指针移动到按键上边的时候显得该Logo。即便该参数被赋值为 NULL ,则分配给这几个开关的具有Logo财富将被释放。
hIconOut: Logo的句柄,当鼠标指针不在按键上面包车型大巴时候显得该Logo。调用函数的时候能够忽略该参数。

返回值:
BTNST_OK: 表示函数推行成功。
BTNST_INVALIDRESOURCE: 表示函数实行停业,举例不能读取内定的Logo财富。

CButtonST::SetMenu
DWORD SetMenu(UINT nMenu, HWND hParentWnd, BOOL bWinXPStyle = TRUE, UINT
nToolbarID = NULL, CSize sizeToolbarIcon = CSize(16, 16), COLORREF
crToolbarBk = RGB(255, 0, 255), BOOL bRepaint = TRUE)
DWORD SetMenu(UINT nMenu, HWND hParentWnd, BOOL bRepaint = TRUE)

注释:
要调用此函数必须与BCMenu类一齐利用。函数将为开关指派一个菜系,当点击开关的时候会弹出所指派的菜谱。此函数的调用与宏有关,假设在代码中声称了BTNST_USE_BCMENU 宏,则应该调用SetMenu函数的第一种情势,不然应当调用SetMenu的后一种样式。

参数:
nMenu : 菜单的ID值。
hParentWnd: 菜单所属的窗口句柄。菜单选项将触发该窗口内的年月。
bWinXPStyle: 值为TRUE则会以XP风格彰显菜单, 值为FALSE则会以正规化风格显示菜单。
nToolbarID: 工具条的ID值。程序会将工具条中与菜单项ID值一样图片步向到菜单中。
sizeToolbarIcon: 钦定工具条中每二个Logo的大大小小,它是贰个CSize 类型的实例。注意请保管工具条中存有Logo的尺寸同样。
crToolbarBk: 颜色值。工具条图片中与该颜色一样的区域将展示为透明。
bRepaint: 值为TRUE则即时重绘按钮。

返回值:
BTNST_OK: 函数推行成功。
BTNST_INVALIDRESOURCE: 不能够读取钦定财富。

CButtonST::TooltipText
void SetTooltipText(int nText, BOOL bActivate = TRUE)
void SetTooltipText(LPCTSTR lpszText, BOOL bActivate = TRUE)

注释:
调用此函数可认为按键设定提醒消息。

参数:
nText: 字符串的ID值。
lpszText: 所要展现的字符串。
nActivate: 值为TRUE表示激活提醒效果, 值为FALSE表示不激活提醒意义。

CButtonST::SetURL
DWORD SetURL(LPCTSTR lpszURL = NULL)

注释:
调用此函数后,单击按键将开采参数所钦命的连天。

参数:
lpszUTiggoL: 包括链接消息的字符串。

返回值:
BTNST_OK: 函数实施成功。

 

上述内容出处:http://blog.csdn.net/liuyang1943/article/details/4959454

邮箱地址:davide_calabro@yahoo.com

个人主页:http://www.softechsoftware.it

CButtonST类主要回顾BtnST.h、BtnST.cpp、BCMenu.h和BCMenu.cpp多个文本。借使您筹算选用CButtonST的窗口不仅仅三个,那么本人建议你在VC++的Workspace
|
FileView中程导弹入以上的五个文本从此,然后在SdtAfx.h文件中加多合适的include语句,如#include
“BtnST.h”。

在接下去的几篇小说中,小编将基于笔者提供的演示程序向我们介绍CButtonST的各样常用方法。在末了一篇小说中,将为各位提供CButtonST类的国语文书档案,以供各位在后头的行使中参谋。

 

本篇主要回顾了以下的功效:

  1. 在按键上参预Icon,使Icon和文字同临时候出示

  2. 呈现平面按键

  3. 使开关上的Logo可变

  4. 设置按键在不相同情形下的底色和文字颜色

  5. 安装Logo和文字的岗位

  6. 依照Icon的样子设置按键的样子

  7. 添加Tooltips

以下是Basic Features的演示分界面:

亚洲必赢手机入口 2

效果一:在按键上走入Icon,使Icon和文字同期显示

只要按键ID为IDC_BUTTON1

  1. 增加成员变量

view source

print?

1.``CButtonST   m_btn;

  1. 添加Icon资源,设其ID设为IDI_ICON1

  2. 在OnInitDialog函数中初叶化按键

view source

print?

1.``m_btn.SubclassDlgItem(IDC_BUTTON1,``this``);

2.``m_btn.SetIcon(IDI_ICON1);

3.``m_btn.SetFlat(FALSE);

只顾:为直达最棒效果,请依据Icon的分寸调节开关的分寸。

实例:演示程序中的Standar 按键。

成效二:显示平面按键

只要求在效劳一的根底上把m_btn.SetFlat(FALSE);语句去掉。

效果与利益三:使开关上的Logo可变

设若开关ID为IDC_BUTTON1

  1. 加上成员变量

view source

print?

1.``CButtonST   m_btn;

  1. 增添四个Icon财富,ID设为IDI_ICON1和IDI_ICON2

IDI_ICON1是普通状态的Logo,IDI_ICON2是按下时的Logo

  1. 在OnInitDialog函数中开端化开关

view source

print?

1.``m_btn.SubclassDlgItem(IDC_BUTTON1,``this``);

2.``m_btn.SetIcon(IDI_ICON2,IDI_ICON1);

实例:演示程序中的哈尔loween 开关。 

 功用四:设置按键在不相同情状下的底色和文字颜色

借使按键ID为IDC_BUTTON1

  1. 加多成员变量

view source

print?

1.``CButtonST   m_btn;

  1. 添加Icon资源,设其ID设为IDI_ICON1

  2. 在OnInitDialog函数中初叶化按键

view source

print?

1.``m_btn.SubclassDlgItem(IDC_BUTTON1,``this``);

2.``m_btn.SetIcon(IDI_ICON1);

3.``m_btn.SetColor(CButtonST::BTNST_COLOR_BK_OUT, RGB(208,208,208));

4.``m_btn.SetColor(CButtonST::BTNST_COLOR_BK_FOCUS, RGB(208,208,208));

5.``m_btn.OffsetColor(CButtonST::BTNST_COLOR_BK_IN, 30);

升迁:SetColor函数和OffsetColor函数的率先个参数表示按键的逐个状态,前景观正是文字的水彩,它们的取值表示:

view source

print?

1.``BTNST_COLOR_BK_IN   ``//鼠标放在按钮内时的背景色

2.``BTNST_COLOR_FG_IN,  ``//鼠标放在按钮内时的前景色

3.``BTNST_COLOR_BK_OUT, ``//普通状态时的背景色

4.``BTNST_COLOR_FG_OUT, ``//普通状态时的前景色

5.``BTNST_COLOR_BK_FOCUS,   ``//按钮被按下后的背景色

6.``BTNST_COLOR_FG_FOCUS,   ``//按钮被按下后的前景色

实例:演示程序中的48×48 icon 开关、Zip开关等。

成效五:设置Logo和文字的岗位

设若开关ID为IDC_BUTTON1

1.增多分子变量

view source

print?

1.``CButtonST   m_btn;

2.添加Icon资源,ID设为IDI_ICON1

3.在OnInitDialog函数中早先化按键

view source

print?

1.``m_btn.SubclassDlgItem(IDC_BUTTON1,``this``);

2.``    ``m_btn.SetIcon(IDI_ICON1);

3.``    ``m_btn.SetAlign(CButtonST::ST_ALIGN_VERT);

晋升:SetAlign函数的率先个参数表示地方音讯,缺省事态下,文字在Logo左侧

view source

print?

1.``ST_ALIGN_HORIZ  ``// 文字在右

2.``ST_ALIGN_VERT   ``//文字在下

3.``ST_ALIGN_HORIZ_RIGHT``// 文字在左

实例:演示程序中的Search 开关。

效果六:依照Icon的模样设置开关的形状

借使开关ID为IDC_BUTTON1

1.增加成员变量

view source

print?

1.``CButtonST   m_btn;

2.添加Icon资源,设其ID设为IDI_ICON1

3.在OnInitDialog函数中开头化按键

view source

print?

1.``m_btn.SubclassDlgItem(IDC_BUTTON1,``this``);

2.``m_btn.SetIcon(IDI_ICON1);

3.``m_btn.DrawBorder(FALSE);

4.``m_btn.SetColor(CButtonST::BTNST_COLOR_BK_OUT, RGB(208,208,208));

5.``m_btn.SetColor(CButtonST::BTNST_COLOR_BK_IN, RGB(208,208,208));

6.``m_btn.SetColor(CButtonST::BTNST_COLOR_BK_FOCUS, RGB(208,208,208));

留心:为完成最棒功效,请依照Icon的轻重缓急调度按键的轻重缓急。

并依附实际境况设置背景颜色。请事先将开关的文字去掉。

效果七:添加Tooltips

一旦开关ID为IDC_BUTTON1

1.增加分子变量

view source

print?

1.``CButtonST   m_btn;

2.添加Icon资源,设其ID设为IDI_ICON1

  1. 在OnInitDialog函数中初叶化开关

view source

print?

1.``m_btn.SubclassDlgItem(IDC_BUTTON1,``this``);

2.``m_btn.SetIcon(IDI_ICON1);

3.``m_btn.SetTooltipText(_T(``"This is a tooltip.\r\nMultiline!"``));

 

 

 

上一篇小说《 CButtonST使用技艺(一)
》介绍了CButtonST使用的7种技能,本篇首要回顾了以下的效果与利益:

  1. 转移鼠标步入开关时的造型(超链接效果)

  2. 菜单开关

  3. 位图按键

  4. 开关宗旨

  5. CheckBox按钮

  6. 晶莹剔透按钮(按键背景和窗口背景一样)

  7. 特殊的PictureBox

 效果一:更动鼠标步入按键时的样子(超链接效果)

设若按键ID为IDC_BUTTON1

  1. 加上分子变量

view source

print?

1.``CButtonST    m_btn;

  1. 添加Icon资源,设其ID设为IDI_ICON1

  2. 在OnInitDialog函数中起先化开关

view source

print?

1.``m_btn.SubclassDlgItem(IDC_BUTTON1,``this``);

2.``m_btn.SetIcon(IDI_ICON1);

3.``m_btn.OffsetColor(CButtonST::BTNST_COLOR_BK_IN, 30);

4.``m_btn.SetURL(``"www.scut.edu.cn"``);

5.``m_btn.SetTooltipText(``"www.scut.edu.cn"``);

6.``m_btn.SetBtnCursor(IDC_CURSOR1);

成效二:菜单开关

譬如开关ID为IDC_BUTTON1

1.增加成员变量

view source

print?

1.``CButtonST    m_btn;

  1. 添加Icon资源,设其ID设为IDI_ICON1

  2. 添加Menu,ID设为IDR_MENU

  3. 在OnInitDialog函数中早先化按键

view source

print?

1.``m_btn.SubclassDlgItem(IDC_BUTTON1,``this``);

2.``m_btn.SetIcon(IDI_ICON1);

3.``m_btn.OffsetColor(CButtonST::BTNST_COLOR_BK_IN, 30);

4.``m_btn.SetMenu(IDR_MENU, m_hWnd);

在意:菜单的功效类似与右键菜单,全体在设置菜单选项时只设置一列就够了。别的菜单的幅度与菜单的文字长度有关,能够用空格占位的章程以高达最佳效应。

在菜单中引进位图的格局

1.加多ToolBar,依次使用Menu菜单项ID作为ToolBar按键的ID。

2.ToolBar上的按键Logo将展现在对应的菜单项中。

将下边代码中的m_btn.SetMenu(IDR_MENU, m_hWnd);

改为m_btn.SetMenu(IDR_MENU, m_hWnd, TRUE, IDR_TOOLBAR);

IDR_TOOLBAR为相应ToolBar的ID。

 

效用三:位图开关

设若按键ID为IDC_BUTTON1

1.增加分子变量

view source

print?

1.``CButtonST    m_btn;

2.增加位图能源,ID设为IDB_BITMAP1

3.在OnInitDialog函数中最早化按键

view source

print?

1.``m_btn.SubclassDlgItem(IDC_BUTTON1,``this``);

2.``m_btn.SetBitmaps(IDB_BITMAP1,RGB(0,0,0));

3.``m_btn.OffsetColor(CButtonST::BTNST_COLOR_BK_IN, 30);

提示: 下边包车型客车SetBitmaps函数会将图片中颜色值为奥德赛GB(0,0,0)的点设为透明。

作用四:按钮主旨

假设开关ID为IDC_BUTTON1

1.增添成员变量

view source

print?

1.``CButtonST    m_btn;

  1. 添加Icon资源,设其ID设为IDI_ICON1

  2. 在OnInitDialog函数中开头化开关

view source

print?

1.``m_btn.SubclassDlgItem(IDC_BUTTON1,``this``);

2.``m_btn.SetIcon(IDI_ICON1);

3.``m_btn.SetAlign(CButtonST::ST_ALIGN_VERT);

4.``m_btn.DrawFlatFocus(TRUE);

效果五:CheckBox按钮

倘若开关ID为IDC_BUTTON1

1.增添成员变量

view source

print?

1.``CButtonST    m_btn;

  1. 添加Icon资源,ID设为IDI_ICON1和IDI_ICON2

3.在OnInitDialog函数中开始化开关

view source

print?

1.``m_btn.SubclassDlgItem(IDC_CHECK1,``this``);

2.``m_btn.SetIcon(IDI_ICON1,IDI_ICON2);

3.``m_btn.OffsetColor(CButtonST::BTNST_COLOR_BK_IN, 30);

提示:

IDI_ICON1为当选时候显得的Logo

IDI_ICON2为为当选时候的Logo

效果与利益六:透明按键

借使开关ID为IDC_BUTTON1

1.增加分子变量

view source

print?

1.``CButtonST    m_btn;

  1. 添加Icon资源,ID设为IDI_ICON1

3.在OnInitDialog函数中最初化按键

view source

print?

1.``m_btn.SubclassDlgItem(IDC_BUTTON1,``this``);

2.``m_btn.SetIcon(IDI_ICON1);

3.``m_btn.DrawTransparent(TRUE);

效果七:特殊的PictureBox

利用CButtonST的超过常规规呈现风格,完全能够把它当作三个PictureBox控件使用。那时一般会把开关的属性设置为disable。
实例:演示程序的About页中使用了CButtonST来代替PictureBox。

 

 

 

本篇将向大家介绍多个CButtonST的派生类。

一、CWinXPButtonST类

CWinXPButtonST类
是三个CButtonST的派生类。它的风味是运用了WindowsXP中的圆角、石黄边框的风骨。它归纳WinXPButtonST.h和WinXPButtonST.cpp七个文本,而鉴于它是从CButtonST派生而来的,所以在援用它时,也要一并引进CButtonST的公文。

使用:

  1. 引进文件,添Gavin书

  2. 导入文本后,在SdtAfx.h文件中加多

view source

print?

1.``#include "WinXPButtonST.h"

  1. 充裕分子变量

view source

print?

1.``CWinXPButtonST    m_btn2;

  1. 只要开关ID为IDC_BUTTON

添加Icon资源,ID设为IDI_ICON1

  1. 在OnInitDialog函数中初步化开关

view source

print?

1.``m_btn2.SubclassDlgItem(IDC_BUTTON,``this``);

2.``m_btn2.SetIcon(IDI_ICON1);

3.``m_btn2.SetRounded(TRUE);

在意:可是它存在一个相差的地方,正是按键的圆角是画出来的,开关的形象如故是本来的矩形。所以若是在有背景象的窗口中动用该开关的话就能够来得极度碍眼。

如图所示,在烟灰的背景观中显得出难看的尖角:

亚洲必赢手机入口 3

化解的点子是经过SetColor函数使得开关的底色与窗口的底色一致。 

二、CShadeButtonST类

CShadeButtonST类
是CButtonST的另贰个派生类。它的风味是支撑越发两种化的背景,通过SetShade函数可感觉按键设置9种不通的背景效果。它回顾多少个文件,它们各自是CeXDib.h、CeXDib.cpp、ShadeButtonST.h和ShadeButtonST.cpp。在援用它时,一样要一并引入CButtonST的公文。

使用:

1.引进文件,添Gavin书

2.导入文本后,在SdtAfx.h文件中增多

view source

print?

1.``#include "ShadeButtonST.h"

3.增添分子变量

view source

print?

1.``CShadeButtonST  m_btn3;

4.假若按键ID为IDC_BUTTON3

添加Icon资源,ID设为IDI_ICON1

5.在OnInitDialog函数中起首化按键

view source

print?

1.``m_btn3.SubclassDlgItem(IDC_BUTTON3,``this``);

2.``m_btn3.SetIcon(IDI_ICON1);

3.``m_btn3.SetShade(CShadeButtonST::SHS_METAL);

上边给出各样背景效果和相应的参数值。

亚洲必赢手机入口 4

亚洲必赢手机入口 5

 

 

from:http://www.vckbase.com/index.php/wenku/index 

http://www.vckbase.com/index.php/wv/342.html

http://www.vckbase.com/index.php/wenku/index

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图