Click here to Skip to main content
Click here to Skip to main content

Adding rollover Hot Toolbars to an application.

, 2 Feb 2002
Rate this:
Please Sign up or sign in to vote.
Adding rollover Hot Toolbars to an application when you don't have access to the toolbar source code

Introduction

The problem with current implementations of rollover toolbars is that they assume that you are in charge of source code, which is not always true.

For example, if you are designing a container that is supposed to host some controls then the source code of the toolbar implementation of those controls is not accessible by the container. Another scenario would also include the case of Toolbars that are dynamically created by reading images from external sources that usually don't present all 3 possible icon states (normal, hot and disabled).

The approach presented here doesn't show you how to implement hooking or subclassing to achieve rollover results on 3d party toolbars loaded into your application, but with a little effort you can modify and reuse the following approach.

I'm presenting this sample using VC5 grammar, because not all readers have switched to VC6 or VS .NET and/or have the latest common control libraries.

Let's get started

OK, idea is simple: after standard creation of a ToolBar the following code will query for current toolbar ImageList, create a Hot and Disabled List and set them to that toolbar.

In your CMainFrame::OnCreate implementation add the following:

 ...
 if (!m_wndToolBar.Create(this) ||
     !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
 {
     TRACE0("Failed to create toolbar\n");
     return -1;      // fail to create
 }
 CHotToolbar(m_wndToolBar.GetToolBarCtrl());
 ...

Now, here is the CHotToolbar Class:

class CHotToolbar
{
public:
     CHotToolbar(CToolBarCtrl& Bar,
                 // see comments about crHighlightColor below
                 COLORREF crHighlightNormal = RGB(0,0,0) ,
                 // see comments about crHighlightColor below
                 COLORREF crHighlightDisabled = RGB(160,160,160),
                 DWORD dwStyle = TBSTYLE_FLAT )
     // CreateGrayScaleIcon -- will mix original Icon with "every-other-pixel"
     // pattern brush
     // crHighlightColor could be set to any color to give "special" effect
     // BLACK(RGB(0,0,0)) will correcspond to extremely contrast, 
     // while WHITE(RGB(255,255,255)) will be less visible => default 
     // RGB(160,160,160) is good for Disabled Buttons
     static HICON CreateGrayScaleIcon(HICON hIcon, 
                         COLORREF crHighlightColor = RGB(160,160,160));
};


/////////////////////////////////////////////////////////////////////////////
// CHotToolbar

CHotToolbar::CHotToolbar(CToolBarCtrl& Bar,
                         COLORREF crHighlightNormal /* = RGB(0,0,0) */,
                         COLORREF crHighlightDisabled /* = RGB(160,160,160)*/,
                         DWORD dwStyle /* = TBSTYLE_FLAT */)
{
    CImageList* pImageList = CImageList::FromHandle(
         (HIMAGELIST)::SendMessage(Bar.m_hWnd, TB_GETIMAGELIST, 0, 0L));
    if(pImageList)
    {
        int numButtons = pImageList->GetImageCount( );
        if(numButtons > 0)
        {
            IMAGEINFO ImageInfo;
            if(pImageList->GetImageInfo(0, &ImageInfo ))
            {
                // OK, let's create copy of Original ImageList
                CImageList img, imgHot, imgDisabled;
                CSize size(CRect(ImageInfo.rcImage).Width(), 
                           CRect(ImageInfo.rcImage).Height());
                if( img.Create(size.cx, size.cy, TRUE, 0, 1)&&
                    imgHot.Create(size.cx, size.cy, TRUE, 0, 1)&&
                    imgDisabled.Create(size.cx, size.cy, TRUE, 0, 1))
                {
                    for(int i=0; i<numButtons; i++)
                    {
                        HICON hIcon = pImageList->ExtractIcon(i);
                        HICON hIconNormal = CreateGrayScaleIcon(hIcon, crHighlightNormal);
                        img.Add( hIconNormal );
                        DeleteObject( hIconNormal );
                        HICON hIconDisabled = CreateGrayScaleIcon(hIcon, crHighlightDisabled);
                        imgDisabled.Add( hIconDisabled );
                        DeleteObject( hIconDisabled );
                        imgHot.Add(hIcon);
                        DeleteObject( hIcon );
                    }
                    // Now Standard Images Grabed => Now we can SetImageList
                    // ATTN: after that operation pImageList will not be valid anymore
                    ::SendMessage(Bar.m_hWnd, TB_SETHOTIMAGELIST, 0, 
                                  (LPARAM)imgHot.GetSafeHandle());
                    imgHot.Detach();
                    ::SendMessage(Bar.m_hWnd, TB_SETIMAGELIST, 0, 
                                  (LPARAM)img.GetSafeHandle());
                    img.Detach();
                    ::SendMessage(Bar.m_hWnd, TB_SETDISABLEDIMAGELIST, 0, 
                                  (LPARAM)imgDisabled.GetSafeHandle());
                    imgDisabled.Detach();
                    if(dwStyle)
                        Bar.ModifyStyle(0, TBSTYLE_FLAT);
                }
            }    
        }
    }
}

//
// CreateGrayScaleIcon -- will mix original Icon with "every-other-pixel"
// pattern brush
// crHighlightColor could be set to any color to give "special" effect
// BLACK(RGB(0,0,0)) will correcspond to extremely contrast, while WHITE(RGB(255,255,255))
// will be less visible => default RGB(160,160,160) is good for Disabled Buttons
//
/* static */ 
HICON CHotToolbar::CreateGrayScaleIcon(HICON hIcon, 
                                       COLORREF crHighlightColor /*=RGB(160,160,160)*/)
{
     
     // The bitmap bits are for a monochrome "every-other-pixel"
     // bitmap (for a pattern brush)
     static const WORD  Bits[8] = { 0x0055, 0x00aa,
                                    0x0055, 0x00aa,
                                    0x0055, 0x00aa,
                                    0x0055, 0x00aa };

     ICONINFO iconinfo;
     GetIconInfo(hIcon, &iconinfo);
     BITMAP  bm;
     GetObject(iconinfo.hbmColor, sizeof(bm), &bm);

     HDC hScreenDC = ::GetDC(NULL);
     HDC hDC = ::CreateCompatibleDC(hScreenDC);
     HBITMAP hOldColor = (HBITMAP)::SelectObject(hDC, iconinfo.hbmColor);
     // The Width and Height of the Icon Image
     int nWidth = bm.bmWidth + 1;
     int nHeight = bm.bmHeight + 1;

     // Create pattern bitmap
     HBITMAP hBrushBitmap = CreateBitmap( 8, 8, 1, 1, &Bits );
     // Original bitmap
     HBITMAP hBitmap = CreateCompatibleBitmap( hScreenDC, nWidth, nHeight );
     // Create memory DC to work on
     HDC hMemDC = CreateCompatibleDC( hScreenDC );
     // Create pattern brush
     HBRUSH hBrush = CreatePatternBrush( hBrushBitmap );

     // If somewthing is wrong => return with NULL
     if( ( !hBrushBitmap ) ||
         ( !hBitmap ) ||
         ( !hMemDC ) ||
         ( !hBrush ) )
     {
         if( hBrushBitmap )
             DeleteObject(hBrushBitmap);
         if( hBitmap )
             DeleteObject( hBitmap );
         if( hMemDC )
             DeleteDC( hMemDC );
         if( hBrush )
             DeleteObject( hBrush );
         return NULL;
     }

     // Select bitmap into the memory DC
     HBITMAP hOldMemBitmap = (HBITMAP)SelectObject( hMemDC, hBitmap );
      
     // Original Rectangle:
     RECT  rcRect = { 0, 0, nWidth, nHeight};

     // Lay down the pattern in the memory DC
     FillRect( hMemDC, &rcRect, hBrush );

     // Fill in the non-color pixels with the original image
     BitBlt( hMemDC, 0, 0, nWidth, nHeight, hDC, 0, 0, SRCAND);

     // Set the color scheme
     COLORREF crOldTextColor = SetTextColor( hDC, crHighlightColor );
     COLORREF crOldBkColor = SetBkColor( hDC, RGB(0,0,0) );
     int OldBkMode = SetBkMode( hDC, OPAQUE );

     // Select the pattern brush
     HBRUSH hOldBrush = (HBRUSH)SelectObject( hDC, hBrush );

     // Fill in the color pixels, and set the others to black
     FillRect( hDC, &rcRect, hBrush );

     // Fill in the black ones with the original image
     BitBlt( hDC, 0, 0, nWidth, nHeight, hMemDC, 0, 0, SRCPAINT );

     // Restore target DC settings
     SetBkMode( hDC, OldBkMode );
     SetBkColor( hDC, crOldBkColor );
     SetTextColor( hDC, crOldTextColor );

     // Clean up
     SelectObject( hMemDC, hOldMemBitmap );
     DeleteObject( hBitmap );
     DeleteDC( hMemDC );
     DeleteObject( hBrushBitmap );
     SelectObject( hDC, hOldBrush );
     DeleteObject( hBrush );

     SelectObject( hDC, hOldColor );
     ReleaseDC( NULL, hScreenDC );

     return CreateIconIndirect(&iconinfo);
}

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Igor Tebelev

United States United States
No Biography provided

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.1411019.1 | Last Updated 3 Feb 2002
Article Copyright 2002 by Igor Tebelev
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid