📄 toolbarex.cpp
字号:
/////////////////////////////////////////////////////////////////////////////
// ToolBarEx.cpp: implementation of the CToolBarEx class.
//
/////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001 by Nikolay Denisov. All rights reserved.
//
// This code is free for personal and commercial use, providing this
// notice remains intact in the source files and all eventual changes are
// clearly marked with comments.
//
// You must obtain the author's consent before you can include this code
// in a software library.
//
// No warrantee of any kind, express or implied, is included with this
// software; use at your own risk, responsibility for damages (if any) to
// anyone resulting from the use of this software rests entirely with the
// user.
//
// Please email bug reports, bug fixes, enhancements, requests and
// comments to: nick@actor.ru
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "CommonRes.h"
#include "../resource.h"
#include "CustomizeDialog.h"
#include "SizableReBar.h"
#include "ToolBarEx.h"
#include "WinAppEx.h"
#include <afxpriv.h> // ON_MESSAGE_VOID()
#include "../generaldata.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
/////////////////////////////////////////////////////////////////////////////
// CToolBarEx
LPCTSTR CToolBarEx::m_lpszStateInfoEntry = _T("ToolbarStateInfo (v1.01)");
CToolBarEx* CToolBarEx::m_pToolBar = 0;
CCustomizeDialog* CToolBarEx::m_pCustomizeDlg = 0;
HHOOK CToolBarEx::m_hCBTHook = 0;
IMPLEMENT_DYNAMIC( CToolBarEx, CToolBar )
CToolBarEx::CToolBarEx()
{
m_eTextOptions = toNone; // no options selected yet
m_eIconOptions = ioNone;
m_customize = TRUE;
}
CToolBarEx::~CToolBarEx()
{
}
BOOL CToolBarEx::Create( CWnd* pParentWnd, DWORD dwStyle, UINT nID /*=AFX_IDW_TOOLBAR*/ )
{
if ( !CreateEx( pParentWnd,
TBSTYLE_FLAT | TBSTYLE_TRANSPARENT | TBSTYLE_TOOLTIPS,
dwStyle & ~CBRS_TOOLTIPS, CRect( 0, 0, 0, 0 ), nID ) )
{
return false;
}
GetToolBarCtrl().SetExtendedStyle(
TBSTYLE_EX_DRAWDDARROWS | TBSTYLE_EX_HIDECLIPPEDBUTTONS );
return true;
}
/////////////////////////////////////////////////////////////////////////////
// Attributes
void CToolBarEx::SetTextOptions( ETextOptions eTextOptions, bool bUpdate /*=true*/ )
{
ASSERT( ::IsWindow( m_hWnd ) );
ASSERT( GetStyle() & TBSTYLE_TOOLTIPS );
ASSERT( !( GetBarStyle() & CBRS_TOOLTIPS ) );
ASSERT( IsTextOptionAvailable( eTextOptions ) );
m_eTextOptions = eTextOptions;
// Modify toolbar style according to new text options
ModifyStyle(
( eTextOptions == toTextOnRight ) ? 0 : TBSTYLE_LIST,
( eTextOptions == toTextOnRight ) ? TBSTYLE_LIST : 0 );
CToolBarCtrl& tbCtrl = GetToolBarCtrl();
DWORD dwStyleEx = tbCtrl.GetExtendedStyle();
tbCtrl.SetExtendedStyle(
( eTextOptions == toTextOnRight ) ?
( dwStyleEx | TBSTYLE_EX_MIXEDBUTTONS ) :
( dwStyleEx & ~TBSTYLE_EX_MIXEDBUTTONS ) );
VERIFY( tbCtrl.SetMaxTextRows(
( eTextOptions == toNoTextLabels ) ? 0 : 1 ) );
// Modify all (even currently hidden ones) buttons in internal cache
int nIndex;
for ( nIndex = 0; nIndex <= m_aButtons.GetUpperBound(); nIndex++ )
{
TBBUTTON& tbinfo = m_aButtons[ nIndex ].tbinfo;
if ( !( tbinfo.fsStyle & TBSTYLE_SEP ) )
{
CString strButtonText;
GetButtonText( tbinfo.idCommand,strButtonText);
//strButtonText = m_aButtons[ nIndex ].btntext;
CString strToAdd( strButtonText, strButtonText.GetLength() + 1 );
tbinfo.iString = tbCtrl.AddStrings( strToAdd );
switch ( eTextOptions )
{
case toTextLabels:
tbinfo.fsStyle &= ~( TBSTYLE_AUTOSIZE | BTNS_SHOWTEXT );
break;
case toTextOnRight:
tbinfo.fsStyle |= ( TBSTYLE_AUTOSIZE |
( HasButtonText( tbinfo.idCommand ) ? BTNS_SHOWTEXT : 0 ) );
break;
case toNoTextLabels:
tbinfo.fsStyle &= ~BTNS_SHOWTEXT;
tbinfo.fsStyle |= TBSTYLE_AUTOSIZE;
break;
}
}
}
// If requested, reflect changes immediately
if ( bUpdate )
{
ReloadButtons();
UpdateParentBandInfo();
}
}
ETextOptions CToolBarEx::GetTextOptions() const
{
return m_eTextOptions;
}
void CToolBarEx::SetIconOptions( EIconOptions eIconOptions, bool bUpdate /*=true*/ )
{
ASSERT( ::IsWindow( m_hWnd ) );
ASSERT( IsIconOptionAvailable( eIconOptions ) );
m_eIconOptions = eIconOptions;
// Set image list(s) and icon size for selected icon options
CToolBarCtrl& tbCtrl = GetToolBarCtrl();
tbCtrl.SetImageList( 0 );
tbCtrl.SetHotImageList( 0 );
CSize szIcon = ( eIconOptions == ioSmallIcons ) ? szImageSmall : szImageLarge;
VERIFY( tbCtrl.SetBitmapSize( szIcon ) );
UINT nIDCold = ( eIconOptions == ioSmallIcons ) ? m_nIDSmallCold : m_nIDLargeCold;
UINT nIDHot = ( eIconOptions == ioSmallIcons ) ? m_nIDSmallHot : m_nIDLargeHot;
ASSERT( nIDCold != ( UINT )-1 ); // at least there must be "cold" imagelist
m_imageListCold.DeleteImageList();
VERIFY( m_imageListCold.Attach( ImageList_LoadImage( AfxGetResourceHandle(),
MAKEINTRESOURCE( nIDCold ), szIcon.cx, 0, RGB(255,0,255),
IMAGE_BITMAP, LR_CREATEDIBSECTION ) ) );
tbCtrl.SetImageList( &m_imageListCold );
/////////////
/////////////
if ( nIDHot != ( UINT )-1 ) // "hot" imagelist is optional
{
m_imageListHot.DeleteImageList();
//m_imageListHot.Create(16, 16, ILC_COLORDDB|ILC_MASK, 40, 1);
VERIFY( m_imageListHot.Attach( ImageList_LoadImage( AfxGetResourceHandle(),
MAKEINTRESOURCE( nIDHot ), szIcon.cx, 0, m_clrMask,
IMAGE_BITMAP, LR_CREATEDIBSECTION ) ) );
tbCtrl.SetHotImageList( &m_imageListHot );
}
else
{
int nCount = m_imageListCold.GetImageCount();
if(nCount>0)
{
m_imageListHot.DeleteImageList();
m_imageListDisabled.DeleteImageList();
m_imageListDisabled.Create(szIcon.cx,szIcon.cy,ILC_COLORDDB|ILC_MASK,0,10);
m_imageListHot.Create(szIcon.cx,szIcon.cy,ILC_COLORDDB|ILC_MASK,0,10);
for(int nIndex=0;nIndex<nCount;nIndex++)
{
HICON hIcon = m_imageListCold.ExtractIcon(nIndex);
// m_imageListHot.Add(hIcon);
AddGloomIcon(&m_imageListHot,hIcon);
AddGrayIcon(&m_imageListDisabled,hIcon);
DestroyIcon(hIcon);
}
tbCtrl.SetHotImageList(&m_imageListHot);
tbCtrl.SetDisabledImageList(&m_imageListDisabled);
}
}
// If requested, reflect changes immediately
if ( bUpdate )
{
ReloadButtons();
UpdateParentBandInfo();
}
}
EIconOptions CToolBarEx::GetIconOptions() const
{
return m_eIconOptions;
}
/////////////////////////////////////////////////////////////////////////////
// Operations
void CToolBarEx::SetBitmaps( UINT nIDSmallCold, UINT nIDSmallHot,
UINT nIDLargeCold, UINT nIDLargeHot,
EIconOptions eIconOptionsDefault,
COLORREF clrMask /*=RGB(255,0,255)*/ )
{
m_nIDSmallCold = nIDSmallCold;
m_nIDSmallHot = nIDSmallHot;
m_nIDLargeCold = nIDLargeCold;
m_nIDLargeHot = nIDLargeHot;
m_clrMask = clrMask;
m_eIconOptionsDefault = eIconOptionsDefault; // to be used on reset
SetIconOptions( m_eIconOptionsDefault ); // apply new options
}
void CToolBarEx::SetButtons( int nNumButtons, TBBUTTONEX* lpButtons,
ETextOptions eTextOptionsDefault )
{
// Delete old buttons
CToolBarCtrl& tbCtrl = GetToolBarCtrl();
while ( tbCtrl.DeleteButton( 0 ) );
// Load buttons from provided array
m_aButtons.RemoveAll();
for ( int nIndex = 0; nIndex < nNumButtons; nIndex++ )
{
if ( lpButtons[ nIndex ].bInitiallyVisible )
{
VERIFY( tbCtrl.AddButtons( 1, &lpButtons[ nIndex ].tbinfo ) );
}
m_aButtons.Add( lpButtons[ nIndex ] );
}
m_eTextOptionsDefault = eTextOptionsDefault; // to be used on reset
SetTextOptions( m_eTextOptionsDefault ); // apply new options
}
void CToolBarEx::LoadState( LPCTSTR lpszProfileName )
{
CString strSubKey;
strSubKey.Format( _T("Software\\%s\\%s\\%s"),
AfxGetApp()->m_pszRegistryKey,
AfxGetApp()->m_pszProfileName,
lpszProfileName );
GetToolBarCtrl().RestoreState( HKEY_CURRENT_USER,
strSubKey, m_lpszStateInfoEntry );
// It was found out that TB_SAVERESTORE causes TBN_BEGINADJUST
// and TBN_ENDADJUST to be sent correspondingly at the beggining
// and the end of save/restore process. So, the following
// call is redundant and therefore was commented out.
// UpdateParentBandInfo();
}
void CToolBarEx::SaveState( LPCTSTR lpszProfileName )
{
CString strSubKey;
strSubKey.Format( _T("Software\\%s\\%s\\%s"),
AfxGetApp()->m_pszRegistryKey,
AfxGetApp()->m_pszProfileName,
lpszProfileName );
GetToolBarCtrl().SaveState( HKEY_CURRENT_USER,
strSubKey, m_lpszStateInfoEntry );
}
/////////////////////////////////////////////////////////////////////////////
// Overrides
BOOL CToolBarEx::OnNotify( WPARAM wParam, LPARAM lParam, LRESULT* pResult )
{
NMHDR* pNMHDR = ( NMHDR* )lParam;
if ( ( pNMHDR->code == TTN_NEEDTEXTA ) ||
( pNMHDR->code == TTN_NEEDTEXTW ) )
{
// If button doesn't have a tip, ignore notification
*pResult = HasButtonTip( pNMHDR->idFrom ) ? Default() : 0;
return TRUE;
}
return CToolBar::OnNotify( wParam, lParam, pResult );
}
LRESULT CToolBarEx::DoCustomDraw( NMHDR* pNMHDR, CWnd* pToolBar )
{
LPNMTBCUSTOMDRAW lpNMCustomDraw = ( LPNMTBCUSTOMDRAW )pNMHDR;
switch ( lpNMCustomDraw->nmcd.dwDrawStage )
{
case CDDS_PREPAINT:
return CDRF_NOTIFYITEMDRAW;
case CDDS_ITEMPREPAINT:
{
UINT nID = lpNMCustomDraw->nmcd.dwItemSpec;
bool bHot = ( lpNMCustomDraw->nmcd.uItemState & CDIS_HOT ) != 0;
if ( pToolBar->SendMessage( TB_ISBUTTONCHECKED, nID ) &&
pToolBar->SendMessage( TB_ISBUTTONENABLED, nID ) && bHot )
{
// I personally don't like when background of checked item
// which is currently hot is drawn using dither brush
lpNMCustomDraw->hbrMonoDither = 0;
}
// fall through...
}
default:
return CDRF_DODEFAULT;
}
}
bool CToolBarEx::HasButtonText( UINT /*nID*/ )
{
return true;
}
bool CToolBarEx::HasButtonTip( UINT nID )
{
switch ( m_eTextOptions )
{
case toTextLabels:
return false;
case toTextOnRight:
return !HasButtonText( nID );
case toNoTextLabels:
return true;
default:
ASSERT( false );
return false;
}
}
void CToolBarEx::GetButtonText( UINT nID, CString& strText )
{
CString strFull,strNew;
if(strFull.LoadString( nID ) )
{
GetText(strFull,strNew,menuhint_item_text);
( AfxExtractSubString( strText, strNew, 1, _T('|') ) );
}
else
{
int index=CommandToIndex(nID);
if(index>=0&&index<m_itemName.GetCount())
strText=m_itemName.GetAt(m_itemName.FindIndex(index));
}
}
void CToolBarEx::GetButtonTip( UINT nID, CString& strTip)
{
GetButtonText( nID, strTip);
}
void CToolBarEx::Init()
{
ASSERT( false ); // must be overridden
}
bool CToolBarEx::IsTextOptionAvailable( ETextOptions /*eTextOptions*/ ) const
{
return true;
}
bool CToolBarEx::IsIconOptionAvailable( EIconOptions /*eIconOptions*/ ) const
{
return true;
}
/////////////////////////////////////////////////////////////////////////////
// Implementation
CReBarCtrl& CToolBarEx::GetParentReBarCtrl() const
{
return STATIC_DOWNCAST( CReBar, GetParent() )->GetReBarCtrl();
}
int CToolBarEx::GetParentBandIndex() const
{
int nBand = GetParentReBarCtrl().IDToIndex( ( UINT )GetDlgCtrlID() );
ASSERT( nBand != -1 );
return nBand;
}
void CToolBarEx::ReloadButtons()
{
// Reload buttons from internal cache
CToolBarCtrl& tbCtrl = GetToolBarCtrl();
for ( int nIndex = 0, nButtons = tbCtrl.GetButtonCount(); nIndex < nButtons; nIndex++ )
{
TBBUTTON tbinfo;
VERIFY( tbCtrl.GetButton( 0, &tbinfo ) );
VERIFY( GetButtonInfo( tbinfo.idCommand, tbinfo ) );
VERIFY( tbCtrl.DeleteButton( 0 ) );
VERIFY( tbCtrl.AddButtons( 1, &tbinfo ) );
}
}
void CToolBarEx::UpdateParentBandInfo()
{
CToolBarCtrl& tbCtrl = GetToolBarCtrl();
tbCtrl.AutoSize();
// Calculate desired height and ideal width of the bar
CRect rcItem;
int cyChild = 0;
int cxIdeal = 0;
for ( int nIndex = 0, nButtons = tbCtrl.GetButtonCount(); nIndex < nButtons; nIndex++ )
{
if ( tbCtrl.GetItemRect( nIndex, rcItem ) )
{
cxIdeal += rcItem.Width();
cyChild = max( cyChild, rcItem.Height() );
}
}
// Modify parent band info accordingly
REBARBANDINFO rbbi;
rbbi.cbSize = sizeof( rbbi );
rbbi.fMask = RBBIM_CHILDSIZE | RBBIM_IDEALSIZE;
rbbi.cxIdeal = cxIdeal;
rbbi.cxMinChild = 0;
rbbi.cyMinChild = cyChild;
VERIFY( GetParentReBarCtrl().SetBandInfo( GetParentBandIndex(), &rbbi ) );
Invalidate(); // visual feedback
}
bool CToolBarEx::GetButtonInfo( UINT nID, TBBUTTON& tbinfo )
{
if ( tbinfo.fsStyle & TBSTYLE_SEP )
{
return true;
}
for ( int nIndex = 0; nIndex <= m_aButtons.GetUpperBound(); nIndex++ )
{
if ( ( UINT )m_aButtons[ nIndex ].tbinfo.idCommand == nID )
{
tbinfo = m_aButtons[ nIndex ].tbinfo;
return true;
}
}
return false;
}
/////////////////////////////////////////////////////////////////////////
// CToolBarEx message handlers
BEGIN_MESSAGE_MAP(CToolBarEx, CToolBar)
//{{AFX_MSG_MAP(CToolBarEx)
ON_COMMAND(ID_CUSTOMIZE, OnCustomize)
//}}AFX_MSG_MAP
ON_MESSAGE( WM_REBAR_CONTEXTMENU, OnReBarContextMenu )
ON_MESSAGE( WM_REBAR_CHEVRONPUSHED, OnReBarChevronPushed )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -