📄 atlctrlxp.h
字号:
#ifndef __ATLCTRLXP_H__
#define __ATLCTRLXP_H__
/////////////////////////////////////////////////////////////////////////////
// CCommandBarXPCtrl - Command Bar (XP look) and others
//
// Written by Bjarke Viksoe (bjarke@viksoe.dk)
// Copyright (c) 2001-2002 Bjarke Viksoe.
// Alex Kamenev provided chevron support.
// Thanks to Ramon Casellas for plenty for suggestions.
// Nicola Tufarelli supplied fixes for button texts.
// Tim France fixed the flat window animations.
//
// Overrides the original WTL CCommandBarCtrl.
//
// This code may be used in compiled form in any way you desire. This
// file may be redistributed by any means PROVIDING it is
// not sold for profit without the authors written consent, and
// providing that this notice and the authors name is included.
//
// This file is provided "as is" with no expressed or implied warranty.
// The author accepts no liability if it causes any damage to you or your
// computer whatsoever. It's free, so don't hassle me about it.
//
// Beware of bugs.
//
#pragma once
#ifndef __cplusplus
#error WTL requires C++ compilation (use a .cpp suffix)
#endif
#ifndef __ATLCTRLW_H__
#error atlctrlxp.h requires atlctrlw.h to be included first
#endif
#if (_WTL_VER < 0x0700)
#error This file requires WTL version 7.0 or higher
#endif
// This hack allows us to have a SDI and MDI commandbar (but only one).
// Add this define if you're building a MDI app.
#ifndef _WTL_USE_MDI
#define COMMANDBAR_CLASS CCommandBarCtrlImpl
#else
#define COMMANDBAR_CLASS CMDICommandBarCtrlImpl
#endif
/////////////////////////////////////////////////////////////////////////////
// CCommandBarXPCtrl - The Command Bar
// Standard XP Command Bar styles
#define ATL_SIMPLE_XP_CMDBAR_PANE_STYLE \
(WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CBRWS_NODIVIDER | CBRWS_NORESIZE | CBRWS_NOPARENTALIGN)
// Additional Extended CommandBar styles
#define CBR_EX_NOWIGGLE 0x10000000
class CFlatMenuWindow :
public CWindowImpl<CFlatMenuWindow>
#ifdef __DIALOGSHADOWS_H__
, public CDialogShadows<CFlatMenuWindow>
#endif // __DIALOGSHADOWS_H__
{
public:
DECLARE_WND_SUPERCLASS(_T("WTL_XpMenu"), GetWndClassName())
BEGIN_MSG_MAP(CFlatMenuWindow)
MESSAGE_HANDLER(WM_NCPAINT, OnNcPaint)
MESSAGE_HANDLER(WM_PRINT, OnPrint)
#ifdef __DIALOGSHADOWS_H__
CHAIN_MSG_MAP( CDialogShadows<CFlatMenuWindow> )
#endif // __DIALOGSHADOWS_H__
END_MSG_MAP()
COLORREF m_clrHighlightBorder;
COLORREF m_clrBackground;
COLORREF m_clrMenu;
SIZE m_sizeBorder;
int m_cxMenuButton;
CFlatMenuWindow(int cxMenuButton, COLORREF clrBorder, COLORREF clrBack, COLORREF clrColor)
: m_cxMenuButton(cxMenuButton),
m_clrHighlightBorder(clrBorder),
m_clrBackground(clrBack),
m_clrMenu(clrColor)
{
m_sizeBorder.cx = ::GetSystemMetrics(SM_CXDLGFRAME);
m_sizeBorder.cy = ::GetSystemMetrics(SM_CYDLGFRAME);
}
virtual void OnFinalMessage(HWND /*hWnd*/)
{
delete this;
}
LRESULT OnNcPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
CDC dc = ::GetDCEx(m_hWnd, (HRGN) wParam, DCX_WINDOW | DCX_INTERSECTRGN | 0x10000);
if( dc.IsNull() ) dc = ::GetWindowDC(m_hWnd);
RECT rcWin;
GetWindowRect(&rcWin);
::OffsetRect(&rcWin, -rcWin.left, -rcWin.top);
// Paint frame
CBrush brushBack;
brushBack.CreateSolidBrush(m_clrBackground);
CPen pen;
pen.CreatePen(PS_SOLID, 1, m_clrHighlightBorder);
HPEN hOldPen = dc.SelectPen(pen);
HBRUSH hOldBrush = dc.SelectBrush(brushBack);
dc.Rectangle(rcWin.left, rcWin.top, rcWin.right, rcWin.bottom);
// Fill area to the left with grey color
CBrush brushColor;
brushColor.CreateSolidBrush(m_clrMenu);
RECT rcLeft = { rcWin.left + 1, rcWin.top + m_sizeBorder.cy, rcWin.left + m_sizeBorder.cx, rcWin.bottom - m_sizeBorder.cy };
dc.FillRect(&rcLeft, brushColor);
// If this is a top-level dropdown menu, smooth the top/left area
if( m_cxMenuButton > 0 ) {
CPen penColor;
penColor.CreatePen(PS_SOLID, 1, m_clrMenu);
dc.SelectPen(penColor);
dc.MoveTo(rcWin.left + 1, rcWin.top);
dc.LineTo(rcWin.left + m_cxMenuButton, rcWin.top);
}
dc.SelectPen(hOldPen);
dc.SelectBrush(hOldBrush);
return 1;
}
LRESULT OnPrint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
CDCHandle dc = (HDC) wParam;
RECT rcWin;
GetWindowRect(&rcWin);
::OffsetRect(&rcWin, -rcWin.left, -rcWin.top);
// Do the same as in OnNcPaint, but draw to provided DC.
// Should there be a common method?
if( (lParam & PRF_NONCLIENT) != 0 )
{
// Paint frame
CBrush brushBack;
brushBack.CreateSolidBrush(m_clrBackground);
CPen pen;
pen.CreatePen(PS_SOLID, 1, m_clrHighlightBorder);
HPEN hOldPen = dc.SelectPen(pen);
HBRUSH hOldBrush = dc.SelectBrush(brushBack);
dc.Rectangle(rcWin.left, rcWin.top, rcWin.right, rcWin.bottom);
// Fill area to the left with grey color
CBrush brushColor;
brushColor.CreateSolidBrush(m_clrMenu);
RECT rcLeft = { rcWin.left + 1, rcWin.top + m_sizeBorder.cy, rcWin.left + m_sizeBorder.cx, rcWin.bottom - m_sizeBorder.cy };
dc.FillRect(&rcLeft, brushColor);
// If this is a top-level dropdown menu, smooth the top/left area
if( m_cxMenuButton > 0 ) {
CPen penColor;
penColor.CreatePen(PS_SOLID, 1, m_clrMenu);
dc.SelectPen(penColor);
dc.MoveTo(rcWin.left + 1, rcWin.top);
dc.LineTo(rcWin.left + m_cxMenuButton, rcWin.top);
}
dc.SelectPen(hOldPen);
dc.SelectBrush(hOldBrush);
}
// Get the system to draw all the items to a memory DC and then whack it
// on top of the background we just drew above
if( (lParam & PRF_CLIENT) != 0 )
{
RECT rcClient;
GetClientRect(&rcClient);
int cxClient = rcClient.right - rcClient.left;
int cyClient = rcClient.bottom - rcClient.top;
int offsetX = (rcWin.right - rcWin.left - cxClient) / 2;
int offsetY = (rcWin.bottom - rcWin.top - cyClient) / 2;
CDC memDC;
CBitmap memBM;
memDC.CreateCompatibleDC(dc);
memBM.CreateCompatibleBitmap(dc, cxClient, cyClient);
HBITMAP hOldBmp = memDC.SelectBitmap(memBM);
DefWindowProc(WM_PRINTCLIENT, (WPARAM) memDC.m_hDC, PRF_CLIENT);
dc.BitBlt(offsetX, offsetY, cxClient, cyClient, memDC, 0, 0, SRCCOPY);
memDC.SelectBitmap(hOldBmp);
}
bHandled = TRUE;
return 0;
}
};
typedef struct tagXPSTYLE
{
COLORREF clrFrame;
COLORREF clrBackground;
COLORREF clrMenu;
COLORREF clrHighlightBorder;
COLORREF clrHighlight;
COLORREF clrHighlightDark;
COLORREF clrPressed;
COLORREF clrGreyText;
COLORREF clrMenuText;
COLORREF clrSelMenuText;
COLORREF clrButtonText;
COLORREF clrSelButtonText;
COLORREF clrShadow;
} XPSTYLE;
class CCommandBarXPCtrlBase : public CCommandBarCtrlBase
{
public:
static RECT m_rcButton;
static bool m_bIsMenuDropped;
static XPSTYLE m_xpstyle;
};
template< class T, class TBase = CCommandBarXPCtrlBase, class TWinTraits = CControlWinTraits >
class ATL_NO_VTABLE CCommandBarXPCtrlImpl : public COMMANDBAR_CLASS< T, TBase, TWinTraits >
{
public:
DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName())
typedef COMMANDBAR_CLASS< T, TBase, TWinTraits > baseCtrlClass;
enum
{
s_kcxTextMargin = 6,
s_kcxDropDownArrowWidth = 14,
s_kcxDropWholeArrowWidth = 10,
s_kcxChevronItemWidth = 12,
_nMaxMenuItemTextLength = 100,
};
// Declarations
CSimpleValArray<HWND> m_Toolbars;
// Message map and handlers
BEGIN_MSG_MAP(CRecentCommandBarCtrlImpl)
MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)
CHAIN_MSG_MAP( baseCtrlClass )
ALT_MSG_MAP(1) // Parent window messages
NOTIFY_CODE_HANDLER(NM_CUSTOMDRAW, OnParentCustomDraw)
NOTIFY_CODE_HANDLER(TBN_DROPDOWN, OnParentToolbarDropDown)
CHAIN_MSG_MAP_ALT( baseCtrlClass, 1 )
ALT_MSG_MAP(2) // MDI client window messages
CHAIN_MSG_MAP_ALT( baseCtrlClass, 2 )
ALT_MSG_MAP(3) // Message hook messages
CHAIN_MSG_MAP_ALT( baseCtrlClass, 3 )
END_MSG_MAP()
CCommandBarXPCtrlImpl()
{
}
// Operations
BOOL AddToolbar(HWND hwndTB)
{
ATLASSERT(::IsWindow(hwndTB));
m_Toolbars.Add(hwndTB);
#if (_WIN32_IE >= 0x0501)
// WTL 7.1 attempts to set the clipped button style
DWORD dwExStyle = (DWORD)::SendMessage(hwndTB, TB_GETEXTENDEDSTYLE, 0, 0L);
::SendMessage(hwndTB, TB_SETEXTENDEDSTYLE, 0, dwExStyle & ~TBSTYLE_EX_HIDECLIPPEDBUTTONS);
#endif //(_WIN32_IE >= 0x0501)
return TRUE;
}
#ifndef _WTL_USE_MDI
BOOL SetMDIClient(HWND /*hWndMDIClient*/)
{
// Use CMDICommandBarCtrl for MDI support
// and define _WTL_USE_MDI in stdafx.h
ATLASSERT(false);
return FALSE;
}
#endif // _WTL_USE_MDI
void Prepare()
{
#ifndef RBBS_NOGRIPPER
const UINT RBBS_NOGRIPPER = 0x00000100;
#endif // RBBS_NOGRIPPER
// Update colors
_GetSystemSettings();
// Assume we are in a rebar
HWND hWndReBar = GetParent();
ATLASSERT(::IsWindow(hWndReBar));
// Turn off gripper for menu and remove band edge
int nCount = (int) ::SendMessage(hWndReBar, RB_GETBANDCOUNT, 0, 0L);
for( int i = 0; i < nCount; i++ ) {
REBARBANDINFO rbbi = { sizeof(REBARBANDINFO), RBBIM_CHILD | RBBIM_STYLE | RBBIM_COLORS };
BOOL bRet = (BOOL)::SendMessage(hWndReBar, RB_GETBANDINFO, i, (LPARAM) &rbbi);
if( bRet && rbbi.hwndChild == m_hWnd ) {
// Menubar has no gripper.
rbbi.fStyle |= RBBS_NOGRIPPER;
}
else {
// Other toolbars have a special background colour
rbbi.clrBack = m_xpstyle.clrMenu;
}
rbbi.fMask &= ~RBBIM_CHILD;
::SendMessage(hWndReBar, RB_SETBANDINFO, i, (LPARAM) &rbbi);
}
// A nasty hack to get rid of the small indent of the menu toolbar.
// We hide & show the band, and presto - no paint/indent problems!?
::SendMessage(hWndReBar, RB_SHOWBAND, 0, 0L);
::SendMessage(hWndReBar, RB_SHOWBAND, 0, 1L);
}
// Implementation
void _GetSystemSettings()
{
#ifndef BlendRGB
#define BlendRGB(c1, c2, factor) \
RGB( GetRValue(c1) + ((GetRValue(c2) - GetRValue(c1)) * factor / 100), \
GetGValue(c1) + ((GetGValue(c2) - GetGValue(c1)) * factor / 100), \
GetBValue(c1) + ((GetBValue(c2) - GetBValue(c1)) * factor / 100) )
#endif
::EnterCriticalSection(&_Module.m_csStaticDataInit);
COLORREF clrWindow = ::GetSysColor(COLOR_WINDOW);
COLORREF clrText = ::GetSysColor(COLOR_WINDOWTEXT);
COLORREF clrButton = ::GetSysColor(COLOR_BTNFACE);
CWindowDC dc(NULL);
int nBitsPerPixel = dc.GetDeviceCaps(BITSPIXEL);
if( nBitsPerPixel > 8 ) {
m_xpstyle.clrBackground = BlendRGB(clrWindow, clrText, 3);
m_xpstyle.clrMenu = BlendRGB(clrButton, clrWindow, 20);
m_xpstyle.clrHighlightBorder = ::GetSysColor(COLOR_HIGHLIGHT);
m_xpstyle.clrHighlight = BlendRGB(m_xpstyle.clrHighlightBorder, clrWindow, 70);
m_xpstyle.clrHighlightDark = BlendRGB(m_xpstyle.clrHighlightBorder, clrWindow, 60);
m_xpstyle.clrPressed = BlendRGB(m_xpstyle.clrHighlight, clrText, 20);
m_xpstyle.clrShadow = BlendRGB(::GetSysColor(COLOR_3DFACE), ::GetSysColor(COLOR_WINDOWTEXT), 35);
}
else {
m_xpstyle.clrBackground = clrWindow;
m_xpstyle.clrMenu = clrButton;
m_xpstyle.clrHighlightBorder = ::GetSysColor(COLOR_HIGHLIGHT);
m_xpstyle.clrHighlight = clrWindow;
m_xpstyle.clrHighlightDark = clrWindow;
m_xpstyle.clrPressed = ::GetSysColor(COLOR_HIGHLIGHT);
m_xpstyle.clrShadow = ::GetSysColor(COLOR_GRAYTEXT);
}
m_xpstyle.clrFrame = ::GetSysColor(COLOR_WINDOWFRAME);
m_xpstyle.clrGreyText = ::GetSysColor(COLOR_GRAYTEXT);
m_xpstyle.clrMenuText = ::GetSysColor(COLOR_WINDOWTEXT);
m_xpstyle.clrSelMenuText = ::GetSysColor(COLOR_MENUTEXT);
m_xpstyle.clrButtonText = ::GetSysColor(COLOR_BTNTEXT);
m_xpstyle.clrSelButtonText = ::GetSysColor(COLOR_MENUTEXT);
::LeaveCriticalSection(&_Module.m_csStaticDataInit);
}
#if (_WIN32_IE >= 0x0500)
// Chevron support by Alex Kamenev, thanks.
void _DrawChevron(HWND hwndRebar, UINT nItemId, CDCHandle& dc, RECT rc)
{
// Assume we are in a rebar
CReBarCtrl wndRB = hwndRebar;
// Get current band
int nItem = wndRB.IdToIndex(nItemId);
RECT rcTb; // child toolbar rect
REBARBANDINFO rbbi = { sizeof(REBARBANDINFO), RBBIM_STYLE | RBBIM_IDEALSIZE | RBBIM_HEADERSIZE | RBBIM_CHILD | RBBIM_COLORS };
if( ::SendMessage(wndRB, RB_GETBANDINFO, nItem, (LPARAM) &rbbi) )
{
::GetWindowRect(rbbi.hwndChild, &rcTb);
if( (rbbi.fStyle & RBBS_USECHEVRON) != 0 && ( (UINT)(rcTb.right - rcTb.left) < rbbi.cxIdeal) )
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -