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;
}
CHotToolbar(m_wndToolBar.GetToolBarCtrl());
...
Now, here is the CHotToolbar Class:
class CHotToolbar
{
public:
CHotToolbar(CToolBarCtrl& Bar,
COLORREF crHighlightNormal = RGB(0,0,0) ,
COLORREF crHighlightDisabled = RGB(160,160,160),
DWORD dwStyle = TBSTYLE_FLAT )
static HICON CreateGrayScaleIcon(HICON hIcon,
COLORREF crHighlightColor = RGB(160,160,160));
};
CHotToolbar::CHotToolbar(CToolBarCtrl& Bar,
COLORREF crHighlightNormal ,
COLORREF crHighlightDisabled ,
DWORD dwStyle )
{
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 ))
{
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 );
}
::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);
}
}
}
}
}
HICON CHotToolbar::CreateGrayScaleIcon(HICON hIcon,
COLORREF crHighlightColor )
{
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);
int nWidth = bm.bmWidth + 1;
int nHeight = bm.bmHeight + 1;
HBITMAP hBrushBitmap = CreateBitmap( 8, 8, 1, 1, &Bits );
HBITMAP hBitmap = CreateCompatibleBitmap( hScreenDC, nWidth, nHeight );
HDC hMemDC = CreateCompatibleDC( hScreenDC );
HBRUSH hBrush = CreatePatternBrush( hBrushBitmap );
if( ( !hBrushBitmap ) ||
( !hBitmap ) ||
( !hMemDC ) ||
( !hBrush ) )
{
if( hBrushBitmap )
DeleteObject(hBrushBitmap);
if( hBitmap )
DeleteObject( hBitmap );
if( hMemDC )
DeleteDC( hMemDC );
if( hBrush )
DeleteObject( hBrush );
return NULL;
}
HBITMAP hOldMemBitmap = (HBITMAP)SelectObject( hMemDC, hBitmap );
RECT rcRect = { 0, 0, nWidth, nHeight};
FillRect( hMemDC, &rcRect, hBrush );
BitBlt( hMemDC, 0, 0, nWidth, nHeight, hDC, 0, 0, SRCAND);
COLORREF crOldTextColor = SetTextColor( hDC, crHighlightColor );
COLORREF crOldBkColor = SetBkColor( hDC, RGB(0,0,0) );
int OldBkMode = SetBkMode( hDC, OPAQUE );
HBRUSH hOldBrush = (HBRUSH)SelectObject( hDC, hBrush );
FillRect( hDC, &rcRect, hBrush );
BitBlt( hDC, 0, 0, nWidth, nHeight, hMemDC, 0, 0, SRCPAINT );
SetBkMode( hDC, OldBkMode );
SetBkColor( hDC, crOldBkColor );
SetTextColor( hDC, crOldTextColor );
SelectObject( hMemDC, hOldMemBitmap );
DeleteObject( hBitmap );
DeleteDC( hMemDC );
DeleteObject( hBrushBitmap );
SelectObject( hDC, hOldBrush );
DeleteObject( hBrush );
SelectObject( hDC, hOldColor );
ReleaseDC( NULL, hScreenDC );
return CreateIconIndirect(&iconinfo);
}