// toolbar.hpp: interface for the CToolBarCtrlEx class.
//
/////////////////////////////////////////////////////////////////////////////
// Tool Bar Control Extention
//
// Version: 1.0
// Created: April 25, 2000
// Author: BenBurnett
// Email: BenBurnett@telusplanet.net
//
// Copyright (C) 2000 Ben Burnett
// All rights reserved.
//
// Thanks to Paul DiLascia for the code to add drop-down
// menus to toolbar buttons. (1997 MSJ)
//
// Owner-draw code for menu from, CCommandBarCtrl in the
// WTL. See AtlCtrlw.h...
//
// The code and information is provided "as-is" without
// warranty of any kind, either expressed or implied.
//
// Bug fixes and suggestions are welcomed, contact me
// at the email above.
/////////////////////////////////////////////////////////////////////////////
#if !defined(_TOOLBARCTRLEX_H_INCLUDED_)
#define _TOOLBARCTRLEX_H_INCLUDED_
#pragma once
#ifndef __cplusplus
#error toolbar.h requires C++ compilation (use a .cpp suffix)
#endif
#ifndef __ATLAPP_H__
#error toolbar.h requires atlapp.h to be included first
#endif
#ifndef __ATLCTRLS_H__
#pragma message("toolbar.h requires atlctrls.h to be included first.")
#pragma message(" Once you include it you will not get this message.")
#include <atlctrls.h>
#endif
/*
#if (_WIN32_IE < 0x0500)
#error toolbar.h requires _WIN32_IE >= 0x0500
#endif
*/
/////////////////////////////////////////////////////////////////////////////
// CToolBarCtrlExImpl class
template < class T, class TBase = CToolBarCtrl, class TWinTraits = CControlWinTraits >
class CToolBarCtrlExImpl : public CWindowImpl < T, TBase, TWinTraits >
{
public:
DECLARE_WND_SUPERCLASS ( NULL, TBase::GetWndClassName () )
/////////////////////////////////////////////////////////////////////////////
// Declarations
//
struct _ToolBarData // toolbar resource data
{
WORD wVersion;
WORD wWidth;
WORD wHeight;
WORD wItemCount;
//WORD aItems[wItemCount]
WORD* items()
{ return (WORD*)(this + 1); }
};
struct _DropDownButton // One of these for each drop-down button
{
_DropDownButton* next;
UINT uIdButton;
UINT uIdMenu;
};
/////////////////////////////////////////////////////////////////////////////
// Data members
CContainedWindow m_wndParent;
_DropDownButton* m_pDropDownButtons;
bool m_bAnimate;
COLORREF m_clrMask;
/////////////////////////////////////////////////////////////////////////////
// Constructor/Destructor
CToolBarCtrlExImpl() :
m_wndParent ( this, 1 ),
m_pDropDownButtons ( NULL ),
m_bAnimate ( true ) ,
m_clrMask ( RGB ( 192, 192, 192 ) )
{
#if (WINVER >= 0x0500) // Win2K only
// Check if menu animation is turned on
::SystemParametersInfo ( SPI_GETMENUANIMATION, 0, &m_bAnimate, 0 );
#endif
}
~CToolBarCtrlExImpl()
{
if ( m_wndParent.IsWindow () )
m_wndParent.UnsubclassWindow(); // scary!
while (m_pDropDownButtons) {
_DropDownButton* pNext = m_pDropDownButtons->next;
delete m_pDropDownButtons;
m_pDropDownButtons = pNext;
}
}
/////////////////////////////////////////////////////////////////////////////
// Attributes
COLORREF GetImageMaskColor() const
{
ATLASSERT(::IsWindow(m_hWnd));
return m_clrMask;
}
COLORREF SetImageMaskColor(COLORREF clrMask)
{
ATLASSERT(::IsWindow(m_hWnd));
COLORREF clrOld = m_clrMask;
m_clrMask = clrMask;
return clrOld;
}
bool GetAnimate() const
{
ATLASSERT(::IsWindow(m_hWnd));
return m_bAnimate;
}
bool SetAnimate(bool bAnimate = true)
{
ATLASSERT(::IsWindow(m_hWnd));
bool bOld = m_bAnimate;
m_bAnimate = bAnimate;
return bOld;
}
/////////////////////////////////////////////////////////////////////////////
// Methods
// Load the toolbar resource
BOOL LoadToolBar ( UINT uResourceID, BOOL bInitialSeparator = FALSE )
{
ATLASSERT ( IS_INTRESOURCE ( uResourceID ) );
HINSTANCE hInst = _Module.GetResourceInstance ();
HRSRC hRsrc = ::FindResource ( hInst, MAKEINTRESOURCE ( uResourceID ), RT_TOOLBAR );
if ( NULL == hRsrc ) {
return FALSE;
}
HGLOBAL hGlobal = ::LoadResource ( hInst, hRsrc );
if ( NULL == hGlobal ) {
return FALSE;
}
_ToolBarData* pData = reinterpret_cast < _ToolBarData* > ( ::LockResource ( hGlobal ) );
if ( NULL == pData ) {
return FALSE;
}
ATLASSERT ( 1 == pData->wVersion );
WORD * pItems = pData->items ();
int nItems = pData->wItemCount + ( bInitialSeparator ? 1 : 0 );
TBBUTTON * pTBBtn = new TBBUTTON [ nItems ];
// set initial separator (half width)
if ( bInitialSeparator ) {
pTBBtn[0].iBitmap = 4;
pTBBtn[0].idCommand = 0;
pTBBtn[0].fsState = 0;
pTBBtn[0].fsStyle = TBSTYLE_SEP;
pTBBtn[0].dwData = 0;
pTBBtn[0].iString = 0;
}
int nBmp = 0;
for ( int i = 0, j = ( bInitialSeparator ? 1 : 0 ); i < pData->wItemCount; i++, j++ ) {
if ( 0 != pItems[i] ) {
// Toolbar item
pTBBtn[j].iBitmap = nBmp++;
pTBBtn[j].idCommand = pItems[i];
pTBBtn[j].fsState = TBSTATE_ENABLED;
pTBBtn[j].fsStyle = TBSTYLE_BUTTON;
pTBBtn[j].dwData = 0;
pTBBtn[j].iString = 128;
}
else {
// Separator
pTBBtn[j].iBitmap = 0;
pTBBtn[j].idCommand = 0;
pTBBtn[j].fsState = 0;
pTBBtn[j].fsStyle = TBSTYLE_SEP;
pTBBtn[j].dwData = 0;
pTBBtn[j].iString = 0;
}
}
// Set default button structure size
SetButtonStructSize ();
// Add the bitmaps from the resource ID and then add the buttons
if ( -1 == AddBitmap ( nBmp, uResourceID ) || !AddButtons ( nItems, pTBBtn ) ) {
delete [] pTBBtn; // Only free this if not used
return FALSE;
}
// Set bitmap and button sizes
SIZE sizeBitmap, sizeButton;
sizeBitmap.cx = pData->wWidth;
sizeBitmap.cy = pData->wHeight;
sizeButton.cx = sizeBitmap.cx + 7;
sizeButton.cy = sizeBitmap.cy + 7;
if ( !SetBitmapSize ( sizeBitmap ) || !SetButtonSize ( sizeButton ) ) {
return FALSE;
}
return TRUE;
}
// 1997 Microsoft Systems Journal - Written by Paul DiLascia.
// call to add drop-down menus to toolbar buttons.
//
// Modified so that it will work in WTL
//
BOOL AddDropDownButton ( UINT nIDButton, UINT nIDMenu, BOOL bArrow = TRUE )
{
ATLASSERT(::IsWindow(m_hWnd));
_DropDownButton* pb = FindDropDownButton(nIDButton);
if (!pb) {
pb = new _DropDownButton;
ATLASSERT ( NULL != pb );
pb->next = m_pDropDownButtons;
m_pDropDownButtons = pb;
}
pb->uIdButton = nIDButton;
pb->uIdMenu = nIDMenu;
int nIndex = CommandToIndex ( nIDButton );
ATLASSERT ( -1 != nIndex );
// Add drop-down style to the button
TBBUTTON tbb;
GetButton(nIndex, &tbb);
tbb.fsStyle |= BTNS_DROPDOWN;
_SetButton(nIndex, &tbb);
return TRUE;
}
// 1997 Microsoft Systems Journal - Written by Paul DiLascia.
// Find buttons structure for given ID
_DropDownButton* FindDropDownButton ( UINT nID )
{
for ( _DropDownButton* pb = m_pDropDownButtons; pb; pb = pb->next ) {
if ( pb->uIdButton == nID ) {
return pb;
}
}
return NULL;
}
// Set new button information
void _SetButton ( int nIndex, LPTBBUTTON lpButton )
{
ATLASSERT ( ::IsWindow ( m_hWnd ) );
// Get original button state
TBBUTTON button;
GetButton ( nIndex, &button );
// Nothing to do if they are the same
if ( memcmp ( lpButton, &button, sizeof ( TBBUTTON ) ) != 0 )
{
// Don't redraw everything while setting the button
ModifyStyle ( WS_VISIBLE, 0 );
DeleteButton ( nIndex );
InsertButton ( nIndex, lpButton );
ModifyStyle ( 0, WS_VISIBLE );
// Invalidate appropriate parts
if ( ( ( lpButton->fsStyle ^ button.fsStyle ) & TBSTYLE_SEP ) ||
( ( lpButton->fsStyle & TBSTYLE_SEP ) && lpButton->iBitmap != button.iBitmap ) )
{
// Changing a separator
Invalidate ();
}
else
{
// Invalidate just the button
RECT rc;
GetItemRect ( nIndex, &rc );
InvalidateRect ( &rc );
}
}
}
/////////////////////////////////////////////////////////////////////////////
// Virtual Methods
virtual bool DoDropDownMenu ( UINT uIdMenu, RECT* rc )
{
CMenu menu;
CMenuHandle popupMenu;
menu.LoadMenu ( uIdMenu );
popupMenu = menu.GetSubMenu ( 0 );
UINT uFlags = TPM_LEFTBUTTON | TPM_VERTICAL | TPM_LEFTALIGN | TPM_TOPALIGN;
#if (_WIN32_WINNT >= 0x0500)
// Win2K can flag 'no animation'
uFlags |= ( m_bAnimate ? TPM_VERPOSANIMATION : TPM_NOANIMATION );
#else
if ( m_bAnimate ) {
uFlags |= TPM_VERPOSANIMATION;
}
#endif
if ( !popupMenu.TrackPopupMenu ( uFlags, rc->left, rc->bottom, m_hWnd, rc ) ) {
return false;
}
return true;
}
/////////////////////////////////////////////////////////////////////////////
// Message map and handlers
BEGIN_MSG_MAP ( CToolBarCtrlExImpl )
MESSAGE_HANDLER ( WM_CREATE, OnCreate )
ALT_MSG_MAP ( 1 ) // Parent window messages
NOTIFY_CODE_HANDLER ( TBN_DROPDOWN, OnParentDropDown )
END_MSG_MAP ()
LRESULT OnCreate ( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & /*bHandled*/ )
{
// These styles are required
ModifyStyle ( 0, TBSTYLE_FLAT );
// Add drop-down arrows to the toolbar
DWORD dwExStyle = TBSTYLE_EX_DRAWDDARROWS;
#if ( _WIN32_IE >= 0x0501 )
// Add some cool Win2K styles
dwExStyle |= TBSTYLE_EX_HIDECLIPPEDBUTTONS | TBSTYLE_EX_MIXEDBUTTONS;
#endif // ( _WIN32_IE >= 0x0501 )
SetExtendedStyle ( dwExStyle );
// Let the toolbar initialize itself
LRESULT lRet = DefWindowProc ( uMsg, wParam, lParam );
// Subclass parent window
CWindow wndParent = GetParent ();
CWindow wndTopLevelParent = wndParent.GetTopLevelParent ();
m_wndParent.SubclassWindow ( wndTopLevelParent );
return lRet;
}
//
// Parent window message handlers
//
LRESULT OnParentDropDown ( int /*idCtrl*/, LPNMHDR pnmh, BOOL & bHandled )
{
LPNMTOOLBAR lpnmtb = reinterpret_cast < LPNMTOOLBAR > ( pnmh );
// Check if this is from us
if ( pnmh->hwndFrom != m_hWnd ) {
bHandled = FALSE;
return TBDDRET_NODEFAULT;
}
_DropDownButton * pDropDownButton = FindDropDownButton ( lpnmtb->iItem );
RECT rc;
GetRect ( pDropDownButton->uIdButton, &rc );
ClientToScreen ( &rc );
if ( pDropDownButton ) {
if ( DoDropDownMenu ( pDropDownButton->uIdMenu, &rc ) ) {
return TBDDRET_DEFAULT;
}
}
return TBDDRET_NODEFAULT;
}
};
/////////////////////////////////////////////////////////////////////////////
// CToolBarCtrlEx class
class CToolBarCtrlEx : public CToolBarCtrlExImpl < CToolBarCtrlEx >
{
public:
DECLARE_WND_SUPERCLASS ( _T ( "BCB_ToolBarEx" ), GetWndClassName () )
};
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
#endif // !defined(_TOOLBARCTRLEX_H_INCLUDED_)