Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Adding rollover Hot Toolbars to an application.

0.00/5 (No votes)
2 Feb 2002 1  
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