📄 toolbarex.cpp
字号:
ON_NOTIFY_REFLECT( NM_CUSTOMDRAW, OnCustomDraw )
ON_NOTIFY_REFLECT( TBN_GETINFOTIP, OnGetInfoTip )
// Toolbar customization
ON_NOTIFY_REFLECT( TBN_BEGINADJUST, OnBeginAdjust )
ON_NOTIFY_REFLECT( TBN_ENDADJUST, OnEndAdjust )
ON_NOTIFY_REFLECT( TBN_QUERYINSERT, OnQueryInsert )
ON_NOTIFY_REFLECT( TBN_QUERYDELETE, OnQueryDelete )
ON_NOTIFY_REFLECT( TBN_INITCUSTOMIZE, OnInitCustomize )
ON_NOTIFY_REFLECT( TBN_GETBUTTONINFO, OnGetButtonInfo )
ON_NOTIFY_REFLECT( TBN_RESET, OnReset )
ON_NOTIFY_REFLECT( TBN_TOOLBARCHANGE, OnToolBarChange )
// Saving and restoring toolbar
ON_NOTIFY_REFLECT( TBN_SAVE, OnSave )
ON_NOTIFY_REFLECT( TBN_RESTORE, OnRestore )
END_MESSAGE_MAP()
void CToolBarEx::OnCustomize()
{
GetToolBarCtrl().Customize();
}
LRESULT CToolBarEx::OnReBarContextMenu( WPARAM wParam, LPARAM /*lParam*/ )
{
// Add "Customize..." item to context menu. This menu item
// allows user to invoke standard "Customize toolbar" dialog.
if(!m_customize)
return 0L;
CMenu* pMenu = ( CMenu* )wParam;
ASSERT_VALID( pMenu );
CString strText,strTextNew;
VERIFY( strText.LoadString( IDS_CUSTOMIZE ) );
GetText(strText,strTextNew,conmeu_item_text);
VERIFY( pMenu->AppendMenu( MF_STRING | ( ( GetStyle() & CCS_ADJUSTABLE ) ? 0 : MF_GRAYED ),
ID_CUSTOMIZE, strTextNew ) );
return 0L;
}
LRESULT CToolBarEx::OnReBarChevronPushed( WPARAM wParam, LPARAM /*lParam*/ )
{
CRect rcChevron( ( LPCRECT )wParam );
CToolBarPopup menu( this );
menu.ShowPopup( TPM_LEFTALIGN | TPM_VERTICAL |
( CWinAppEx::GetInstance()->IsWin98_2K() ? TPM_VERPOSANIMATION : 0 ),
CPoint( rcChevron.left, rcChevron.bottom ), rcChevron );
return 0L;
}
void CToolBarEx::OnCustomDraw( NMHDR* pNMHDR, LRESULT* pResult )
{
*pResult = DoCustomDraw( pNMHDR, this );
}
void CToolBarEx::OnGetInfoTip( NMHDR* pNMHDR, LRESULT* pResult )
{
NMTBGETINFOTIP* lptbgit = ( NMTBGETINFOTIP* )pNMHDR;
CString strTip;
GetButtonTip( lptbgit->iItem, strTip );
_tcsncpy( lptbgit->pszText, strTip, lptbgit->cchTextMax );
*pResult = 0;
}
LRESULT CALLBACK CToolBarEx::CBTProc( int nCode, WPARAM wParam, LPARAM lParam )
{
ASSERT( m_pToolBar != 0 );
HWND hWnd = ( HWND )wParam;
switch ( nCode )
{
case HCBT_CREATEWND:
if ( m_pCustomizeDlg == 0 )
{
// This is where we have a good chance to subclass standard
// "Customize toolbar" dialog in order to add to it some of
// our new features (ie. text and icon options selectors)
TCHAR szClassName[ 7 ];
::GetClassName( hWnd, szClassName, sizeof( szClassName ) / sizeof( szClassName[ 0 ] ) );
if ( !lstrcmp( _T("#32770"), szClassName ) )
{
m_pCustomizeDlg = new CCustomizeDialog( m_pToolBar );
VERIFY( m_pCustomizeDlg->SubclassWindow( hWnd ) );
return 0;
}
}
break;
case HCBT_DESTROYWND:
if ( ( m_pCustomizeDlg != 0 ) && ( m_pCustomizeDlg->m_hWnd == hWnd ) )
{
m_pCustomizeDlg = 0;
return 0;
}
break;
}
return ::CallNextHookEx( m_hCBTHook, nCode, wParam, lParam );
}
void CToolBarEx::OnBeginAdjust( NMHDR* /*pNMHDR*/, LRESULT* pResult )
{
m_pToolBar = this;
m_hCBTHook = ::SetWindowsHookEx( WH_CBT, CBTProc, 0, ::GetCurrentThreadId() );
ASSERT( m_hCBTHook != 0 );
*pResult = 0;
}
void CToolBarEx::OnEndAdjust( NMHDR* /*pNMHDR*/, LRESULT* pResult )
{
VERIFY( ::UnhookWindowsHookEx( m_hCBTHook ) );
m_hCBTHook = 0;
m_pToolBar = 0;
UpdateParentBandInfo();
*pResult = 0;
}
void CToolBarEx::OnQueryInsert( NMHDR* /*pNMHDR*/, LRESULT* pResult )
{
*pResult = TRUE; // otherwise Customize dialog will not be shown
}
void CToolBarEx::OnQueryDelete( NMHDR* /*pNMHDR*/, LRESULT* pResult )
{
*pResult = TRUE; // why not? :)
}
void CToolBarEx::OnInitCustomize( NMHDR* /*pNMHDR*/, LRESULT* pResult )
{
*pResult = TBNRF_HIDEHELP; // no help available yet
}
void CToolBarEx::OnGetButtonInfo( NMHDR* pNMHDR, LRESULT* pResult )
{
NMTOOLBAR* lpnmtb = ( NMTOOLBAR* )pNMHDR;
int nItem = lpnmtb->iItem;
if ( ( 0 <= nItem ) && ( nItem <= m_aButtons.GetUpperBound() ) )
{
// Copy button info from internal cache
lpnmtb->tbButton = m_aButtons[ nItem ].tbinfo;
if ( !( lpnmtb->tbButton.fsStyle & TBSTYLE_SEP ) )
{
CString strText;
GetButtonText( lpnmtb->tbButton.idCommand, strText );
_tcsncpy( lpnmtb->pszText, strText, lpnmtb->cchText );
}
*pResult = TRUE;
}
else
{
*pResult = FALSE;
}
}
void CToolBarEx::OnReset( NMHDR* /*pNMHDR*/, LRESULT* pResult )
{
// Delete all buttons
CToolBarCtrl& tbCtrl = GetToolBarCtrl();
while ( tbCtrl.DeleteButton( 0 ) );
// Load buttons from internal cache
for ( int nIndex = 0; nIndex <= m_aButtons.GetUpperBound(); nIndex++ )
{
if ( m_aButtons[ nIndex ].bInitiallyVisible )
{
VERIFY( tbCtrl.AddButtons( 1, &m_aButtons[ nIndex ].tbinfo ) );
}
}
// Set default text & icon options
SetIconOptions( m_eIconOptionsDefault, false );
SetTextOptions( m_eTextOptionsDefault, false );
ReloadButtons();
UpdateParentBandInfo();
// Synchronize with Customize dialog
ASSERT( m_pCustomizeDlg != 0 );
m_pCustomizeDlg->SetTextOptions( m_eTextOptions, true );
m_pCustomizeDlg->SetIconOptions( m_eIconOptions, true );
*pResult = 0;
}
void CToolBarEx::OnToolBarChange( NMHDR* /*pNMHDR*/, LRESULT* pResult )
{
UpdateParentBandInfo();
*pResult = 0;
}
void CToolBarEx::OnSave( NMHDR* pNMHDR, LRESULT* pResult )
{
NMTBSAVE* lpnmtb = ( NMTBSAVE* )pNMHDR;
if ( lpnmtb->iItem == -1 )
{
lpnmtb->cbData += sizeof( DWORD ) * 2;
lpnmtb->pData = ( LPDWORD )::GlobalAlloc( GMEM_FIXED, lpnmtb->cbData );
lpnmtb->pCurrent = lpnmtb->pData;
*lpnmtb->pCurrent++ = ( DWORD )m_eTextOptions;
*lpnmtb->pCurrent++ = ( DWORD )m_eIconOptions;
}
*pResult = 0;
}
void CToolBarEx::OnRestore( NMHDR* pNMHDR, LRESULT* pResult )
{
NMTBRESTORE* lpnmtb = ( NMTBRESTORE* )pNMHDR;
if ( lpnmtb->iItem == -1 )
{
lpnmtb->cButtons = ( lpnmtb->cbData - sizeof( DWORD ) * 2 ) / lpnmtb->cbBytesPerRecord;
lpnmtb->pCurrent = lpnmtb->pData;
SetTextOptions( ( ETextOptions )*lpnmtb->pCurrent++, false );
SetIconOptions( ( EIconOptions )*lpnmtb->pCurrent++, false );
}
else
{
VERIFY( GetButtonInfo( lpnmtb->tbButton.idCommand, lpnmtb->tbButton ) );
}
*pResult = 0;
}
/////////////////////////////////////////////////////////////////////////////
// CToolBarPopup
HHOOK CToolBarPopup::m_hKeyboardHook = 0;
CToolBarPopup* CToolBarPopup::m_pPopup = 0;
IMPLEMENT_DYNAMIC( CToolBarPopup, CWnd )
CToolBarPopup::CToolBarPopup( CToolBarEx* pToolBar )
{
ASSERT_VALID( pToolBar );
m_pToolBar = pToolBar;
m_bOverTbCtrl = false;
m_bTextLabels = false;
}
CToolBarPopup::~CToolBarPopup()
{
}
/////////////////////////////////////////////////////////////////////////////
// Operations
bool CToolBarPopup::ShowPopup( UINT nFlags, CPoint pt, CRect& rcExclude )
{
CString strWndClass = AfxRegisterWndClass( CS_SAVEBITS,
::LoadCursor( 0, IDC_ARROW ), ::GetSysColorBrush( COLOR_MENU ), 0 );
if ( !CreateEx( WS_EX_PALETTEWINDOW, strWndClass, 0,
WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_DLGFRAME,
CRect( 0, 0, 0, 0 ), 0, 0 ) )
{
return false;
}
SetPosition( nFlags, pt, rcExclude );
SetCapture();
SendMessage( WM_SETCURSOR, ( WPARAM )m_hWnd, MAKELPARAM( HTCLIENT, 0 ) );
m_pPopup = this;
m_hKeyboardHook = ::SetWindowsHookEx( WH_KEYBOARD, KeyboardProc, 0, ::GetCurrentThreadId() );
ASSERT( m_hKeyboardHook != 0 );
// Emulate menu loop
RunModalLoop( MLF_NOKICKIDLE );
VERIFY( ::UnhookWindowsHookEx( m_hKeyboardHook ) );
m_hKeyboardHook = 0;
m_pPopup = 0;
DestroyWindow();
return true;
}
/////////////////////////////////////////////////////////////////////////////
// Implementation
void CToolBarPopup::SetPosition( UINT nFlags, CPoint pt, CRect& rcExclude )
{
// The main purpose of this functions is to find proper position of
// the popup window, so that we neither exceed screen dimensions nor
// intersect rcExclude rectangle. The function also takes into account
// control flags specified by the user.
// Calc initial position
CRect rc;
m_tbCtrl.GetWindowRect( rc );
CalcWindowRect( rc, CWnd::adjustBorder );
rc.OffsetRect( -rc.TopLeft() );
rc.OffsetRect(
( nFlags & TPM_CENTERALIGN ) ? ( pt.x - rc.Width() / 2 ) :
( nFlags & TPM_RIGHTALIGN ) ? ( pt.x - rc.Width() ) : pt.x, 0 );
rc.OffsetRect( 0,
( nFlags & TPM_VCENTERALIGN ) ? ( pt.y - rc.Height() / 2 ) :
( nFlags & TPM_BOTTOMALIGN ) ? ( pt.y - rc.Height() ) : pt.y );
// Make sure we don't exceed screen dimensions
CRect rcDesktop;
GetDesktopWindow()->GetWindowRect( rcDesktop );
rc.OffsetRect(
min( rcDesktop.right - rc.right, 0 ),
min( rcDesktop.bottom - rc.bottom, 0 ) );
rc.OffsetRect(
max( rcDesktop.left - rc.left, 0 ),
max( rcDesktop.top - rc.top, 0 ) );
// Make sure we don't intersect rcExclude rectangle
CRect rcTemp;
if ( !rcExclude.IsRectEmpty() && rcTemp.IntersectRect( rc, rcExclude ) )
{
if ( nFlags & TPM_VERTICAL )
{
CRect rcUp( rc );
int nUp = rc.bottom - rcExclude.top;
rcUp.OffsetRect( 0, -nUp );
CRect rcDown( rc );
int nDown = rcExclude.bottom - rc.top;
rcDown.OffsetRect( 0, nDown );
bool bUp = false;
if ( ( rcUp.top >= rcDesktop.top ) && ( rcDown.bottom <= rcDesktop.bottom ) )
{
bUp = ( nUp < nDown );
}
else if ( rcUp.top >= rcDesktop.top )
{
bUp = true;
}
else if ( rcDown.bottom <= rcDesktop.bottom )
{
bUp = false;
}
else
{
ASSERT( false ); // this case is not supported yet
}
rc = bUp ? rcUp : rcDown;
nFlags &= ~( TPM_HORPOSANIMATION | TPM_HORNEGANIMATION | TPM_VERPOSANIMATION | TPM_VERNEGANIMATION );
nFlags |= ( bUp ? TPM_VERNEGANIMATION : TPM_VERPOSANIMATION );
}
else
{
CRect rcLeft( rc );
int nLeft = rc.right - rcExclude.left;
rcLeft.OffsetRect( -nLeft, 0 );
CRect rcRight( rc );
int nRight = rcExclude.right - rc.left;
rcRight.OffsetRect( nRight, 0 );
bool bLeft = false;
if ( ( rcLeft.left >= rcDesktop.top ) && ( rcRight.right <= rcDesktop.right ) )
{
bLeft = ( nLeft < nRight );
}
else if ( rcLeft.left >= rcDesktop.left )
{
bLeft = true;
}
else if ( rcRight.right <= rcDesktop.right )
{
bLeft = false;
}
else
{
ASSERT( false ); // this case is not supported yet
}
rc = bLeft ? rcLeft : rcRight;
nFlags &= ~( TPM_HORPOSANIMATION | TPM_HORNEGANIMATION | TPM_VERPOSANIMATION | TPM_VERNEGANIMATION );
nFlags |= ( bLeft ? TPM_HORNEGANIMATION : TPM_HORPOSANIMATION );
}
}
Show( nFlags, rc );
}
void CToolBarPopup::Show( UINT nFlags, const CRect& rc )
{
// On W98/W2K systems the menu animation feature is supported.
// This function tries to mimic this feature conformably to
// toolbar popup window.
// Position window on the screen
SetWindowPos( &wndTopMost, rc.left, rc.top, rc.Width(), rc.Height(),
SWP_NOACTIVATE );
CWinAppEx* pApp = CWinAppEx::GetInstance();
if ( pApp->IsWin98_2K() && !( nFlags & TPM_NOANIMATION ) ) // W98/W2K specific (menu animation)
{
if ( pApp->GetMenuAnimation() )
{
DWORD dwAnimationFlags = AW_SLIDE |
( ( nFlags & TPM_HORPOSANIMATION ) ? AW_HOR_POSITIVE : 0 ) |
( ( nFlags & TPM_HORNEGANIMATION ) ? AW_HOR_NEGATIVE : 0 ) |
( ( nFlags & TPM_VERPOSANIMATION ) ? AW_VER_POSITIVE : 0 ) |
( ( nFlags & TPM_VERNEGANIMATION ) ? AW_VER_NEGATIVE : 0 );
if ( dwAnimationFlags == AW_SLIDE )
{
// If none of TPM_*ANIMATION flags is set, set default animation
dwAnimationFlags |= AW_HOR_POSITIVE | AW_VER_POSITIVE;
}
if ( pApp->IsWin2K() && pApp->GetMenuFade() ) // W2K specific (fade effect)
{
dwAnimationFlags = AW_BLEND;
}
VERIFY( ::AnimateWindowWin50( m_hWnd, 200, dwAnimationFlags ) );
return;
}
}
// The animation feature is whether turned off or unsupported
// on this system. Therefore, just show window without activation.
ShowWindow( SW_SHOWNOACTIVATE );
}
void CToolBarPopup::OnKeyDown( UINT nChar )
{
switch ( nChar )
{
case VK_ESCAPE: // dismiss menu
case VK_MENU:
SendMessage( WM_TB_ENDMODALLOOP );
break;
case VK_UP: // select next/prev button
case VK_DOWN:
{
int nLastItem = m_tbCtrl.GetButtonCount() - 1;
int nHotItem = m_tbCtrl.GetHotItem();
for ( int nIndex = 0; nIndex <= nLastItem; nIndex++ )
{
if ( nHotItem >= 0 )
{
nHotItem = ( nChar == VK_UP ) ?
( nHotItem ? nHotItem - 1 : nLastItem ) :
( nHotItem == nLastItem ? 0 : nHotItem + 1 );
}
else
{
nHotItem = ( nChar == VK_UP ) ?
nLastItem : 0;
}
m_tbCtrl.SetHotItem( nHotItem );
if ( m_tbCtrl.GetHotItem() == nHotItem )
{
break;
}
}
break;
}
case VK_RETURN: // issue command associated with selected button
{
int nHotItem = m_tbCtrl.GetHotItem();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -