Adding rollover Hot Toolbars to an application.





5.00/5 (1 vote)
Feb 3, 2002

66737
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); }