📄 mtlctrlw.h
字号:
#ifndef __MTLCTRLW_H__
#define __MTLCTRLW_H__
#pragma once
#ifndef __MTLMISC_H__
#error mtlctrlw.h requires mtlmisc.h to be included first
#endif
////////////////////////////////////////////////////////////////////////////
// MTL Version 0.10
// Copyright (C) 2001 MB<mb2@geocities.co.jp>
// All rights unreserved.
//
// This file is a part of Mb Template Library.
// The code and information is *NOT* provided "as-is" without
// warranty of any kind, either expressed or implied.
//
// MtlCtrlw.h: Last updated: March 17, 2001
/////////////////////////////////////////////////////////////////////////////
namespace MTL
{
/////////////////////////////////////////////////////////////////////////////
// Command Bars
// Window Styles:
#define CBR2WS_TOP CCS_TOP
#define CBR2WS_BOTTOM CCS_BOTTOM
#define CBR2WS_NORESIZE CCS_NORESIZE
#define CBR2WS_NOPARENTALIGN CCS_NOPARENTALIGN
#define CBR2WS_NODIVIDER CCS_NODIVIDER
// Extended styles
#define CBR2_EX_TRANSPARENT 0x00000001L // not supported yet
#define CBR2_EX_SHAREMENU 0x00000002L
// standard command bar styles
#define MTL_SIMPLE_CMDBAR2_PANE_STYLE \
(WS_CHILD | WS_VISIBLE | CBR2WS_NODIVIDER | CBR2WS_NORESIZE | CBR2WS_NOPARENTALIGN)
/////////////////////////////////////////////////////////////////////////////
// Forward declarations
template <class T, class TBase = CCommandBarCtrl2Base, class TWinTraits = CControlWinTraits> class CCommandBarCtrlImpl;
class CCommandBarCtrl2;
/////////////////////////////////////////////////////////////////////////////
// CCmdBarButton
// CCmdBarButton state flags
#define CBSTATE_ENABLED 0x01
#define CBSTATE_PRESSED 0x02
#define CBSTATE_HOT 0x04
#define CBSTATE_INACTIVE 0x08
#define CBSTATE_HIDDEN 0x10
class CCmdBarButton
{
public:
// Data members
BYTE m_fsState;
CString m_strBtn; // string on button
CMenuHandle m_menuSub; // handle to sub menu
TCHAR m_cAccessKey; // access key (Alt key + X)
CRect m_rcBtn;
// Constructor/destructor
CCmdBarButton(BYTE fsState, const CString& strBtn, HMENU hSubMenu)
: m_fsState(fsState), m_strBtn(strBtn), m_menuSub(hSubMenu)
{
// init access key
int nIndex = m_strBtn.Find(_T('&'));
if (nIndex + 1 == m_strBtn.GetLength()) {
ATLTRACE(_T("warning : & is bad position, access key is invalid.\n"));
m_cAccessKey = 0;
}
m_cAccessKey = m_strBtn[nIndex + 1];// -1 + 1 = 0; it's ok
}
// Attributes
bool ModifyState(BYTE fsRemove, BYTE fsAdd)
{
bool bOldEnable = m_fsState & CBSTATE_ENABLED;
m_fsState = (m_fsState & ~fsRemove) | fsAdd;
bool bNewEnable = m_fsState & CBSTATE_ENABLED;
return bOldEnable != bNewEnable;
}
// Methods
void Update(CDCHandle dc)
{
if (m_fsState & CBSTATE_HIDDEN)
return;
if (m_fsState & CBSTATE_HOT) {
DrawHot(dc);
}
else if (m_fsState & CBSTATE_PRESSED) {
DrawPressed(dc);
}
else {
_DrawText(dc);
}
}
void TrackPopup(HWND hWnd, HWND hWndMenuOwner, bool bW2K)
{
// Menu animation flags
#ifndef TPM_VERPOSANIMATION
const UINT TPM_VERPOSANIMATION = 0x1000L;
#endif
#ifndef TPM_NOANIMATION
const UINT TPM_NOANIMATION = 0x4000L;
#endif
// "! menu"
ATLASSERT(m_menuSub.IsMenu());
CWindow wnd(hWnd);
// get popup menu and it's position
CRect rect = m_rcBtn;
wnd.ClientToScreen(&rect);
TPMPARAMS TPMParams;
TPMParams.cbSize = sizeof(TPMPARAMS);
TPMParams.rcExclude = rect;
m_menuSub.TrackPopupMenuEx(TPM_LEFTBUTTON | TPM_VERTICAL | TPM_LEFTALIGN | TPM_TOPALIGN |
(bW2K ? (true ? TPM_VERPOSANIMATION : TPM_NOANIMATION) : 0),
rect.left, rect.bottom, hWndMenuOwner, &TPMParams);
}
// Implementation
void _DrawText(CDCHandle dc, CPoint ptOffset = CPoint(0, 0))
{
COLORREF clr;
if (m_fsState & CBSTATE_INACTIVE)
clr = ::GetSysColor(COLOR_GRAYTEXT);
else if (m_fsState & CBSTATE_ENABLED)
clr = ::GetSysColor(COLOR_MENUTEXT);
else
clr = ::GetSysColor(COLOR_3DSHADOW);
COLORREF clrOld = dc.SetTextColor(clr);
CRect rcBtn = m_rcBtn + ptOffset;
if (!(m_fsState & CBSTATE_ENABLED)) {
// disabled - draw shadow text shifted down and right 1 pixel (unles selected)
CRect rcDisabled = rcBtn + CPoint(1, 1);
COLORREF clrOld2 = dc.SetTextColor(::GetSysColor(COLOR_3DHILIGHT));
dc.DrawText(m_strBtn, -1, rcDisabled, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
dc.SetTextColor(clrOld2);
}
dc.DrawText(m_strBtn, -1, rcBtn, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
dc.SetTextColor(clrOld);
}
void DrawHot(CDCHandle dc)
{
dc.DrawEdge(m_rcBtn, BDR_RAISEDINNER, BF_RECT);
_DrawText(dc);
}
void DrawPressed(CDCHandle dc)
{
dc.DrawEdge(m_rcBtn, BDR_SUNKENOUTER, BF_RECT);
_DrawText(dc, CPoint(1, 1));
}
};
/////////////////////////////////////////////////////////////////////////////
// CCommandBarCtrl2Base - base class for the Command Bar2 implementation
class CCommandBarCtrl2Base : public CWindow
{
public:
static bool s_bW2K; // For animation flag
static CCommandBarCtrl2Base* s_pCurrentBar;
static bool s_bStaticInit;
static HHOOK s_hMsgHook;
CCommandBarCtrl2Base()
{
// init static variables
if(!s_bStaticInit) {
CLockStaticDataInit lock;
if(!s_bStaticInit) {
// Animation on Win2000 only
s_bW2K = !AtlIsOldWindows();
// done
s_bStaticInit = true;
}
}
}
virtual bool OnMenuInput(MSG* pMsg) = 0;
};
__declspec(selectany) CCommandBarCtrl2Base* CCommandBarCtrl2Base::s_pCurrentBar = NULL;
__declspec(selectany) bool CCommandBarCtrl2Base::s_bW2K = false;
__declspec(selectany) bool CCommandBarCtrl2Base::s_bStaticInit = false;
__declspec(selectany) HHOOK CCommandBarCtrl2Base::s_hMsgHook = NULL;
/////////////////////////////////////////////////////////////////////////////
// CCommandBarCtrl2 - MTL implementation of Command Bars
template <class T, class TBase = CCommandBarCtrl2Base, class TWinTraits = CControlWinTraits>
class ATL_NO_VTABLE CCommandBarCtrl2Impl :
public CWindowImpl< T, TBase, TWinTraits >,
public CTrackMouseLeave<CCommandBarCtrl2Impl>
{
public:
DECLARE_WND_CLASS_EX(NULL, 0, -1)
// Declarations
// Constants
enum _CmdBarDrawConstants
{
s_kcxTextMargin = 7,
s_kcyTextMargin = 2
};
enum
{
_nMaxMenuItemTextLength = 100,
_chChevronShortcut = _T('/')
};
enum _TrackingState
{
none = 0,
hotByAlt,
popup,
hotByMouse
};
// Data members
HMENU m_hMenu;
CSimpleArray<CCmdBarButton> m_arrBtn;
_TrackingState m_nTrackingState;
CPoint m_ptMouse;
int m_nPopBtn;
bool m_bLoop;
bool m_bProcessRightArrow, m_bProcessLeftArrow;
bool m_bIgnoreAlt;
bool m_bIgnoreInputMouseMove;
CContainedWindow m_wndParent;
CFont m_fontMenu;
DWORD m_dwExtendedStyle; // Command Bar2 specific extended styles
// Constructor/destructor
CCommandBarCtrl2Impl() :
m_hMenu(NULL),
m_wndParent(this, 1),
m_nPopBtn(-1),
m_dwExtendedStyle(CBR2_EX_TRANSPARENT | CBR2_EX_SHAREMENU),
m_bLoop(false),
m_bProcessRightArrow(false),
m_bProcessLeftArrow(false),
m_bIgnoreAlt(false), m_bIgnoreInputMouseMove(false),
m_nTrackingState(none),
m_ptMouse(-1, -1)
{
}
~CCommandBarCtrl2Impl()
{
if(m_wndParent.IsWindow())
/*scary!*/ m_wndParent.UnsubclassWindow();
if(m_hMenu != NULL && (m_dwExtendedStyle & CBR2_EX_SHAREMENU) == 0)
::DestroyMenu(m_hMenu);
}
// Attributes
DWORD GetCommandBar2ExtendedStyle() const
{
return m_dwExtendedStyle;
}
DWORD SetCommandBar2ExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)
{
DWORD dwPrevStyle = m_dwExtendedStyle;
if(dwMask == 0)
m_dwExtendedStyle = dwExtendedStyle;
else
m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);
return dwPrevStyle;
}
CMenuHandle GetMenu() const
{
ATLASSERT(::IsWindow(m_hWnd));
return m_hMenu;
}
int GetButtonCount() const
{
return m_arrBtn.GetSize();
}
// Methods
HWND Create(HWND hWndParent, RECT& rcPos, LPCTSTR szWindowName = NULL,
DWORD dwStyle = 0, DWORD dwExStyle = 0,
UINT nID = 0, LPVOID lpCreateParam = NULL)
{
return CWindowImpl< T, TBase, TWinTraits >::Create(hWndParent, rcPos, szWindowName, dwStyle, dwExStyle, nID, lpCreateParam);
}
BOOL LoadMenu(_U_STRINGorID menu)
{
ATLASSERT(::IsWindow(m_hWnd));
if(menu.m_lpstr == NULL)
return false;
HMENU hMenu = ::LoadMenu(_Module.GetResourceInstance(), menu.m_lpstr);
if(hMenu == NULL)
return false;
return AttachMenu(hMenu);
}
BOOL AttachMenu(HMENU hMenu)
{
ATLASSERT(::IsWindow(m_hWnd));
ATLASSERT(::IsMenu(hMenu));
if(hMenu != NULL && !::IsMenu(hMenu))
return false;
// destroy old menu, if needed, and set new one
if(m_hMenu != NULL && (m_dwExtendedStyle & CBR2_EX_SHAREMENU) == 0)
::DestroyMenu(m_hMenu);
m_hMenu = hMenu;
// Clear all
_ClearAll();
// Add buttons for each menu item
_AddButtons(m_hMenu);
Invalidate();
UpdateWindow();
return true;
}
void EnableButton(int nIndex, bool bEnable = true)
{
if (!_IsValidIndex(nIndex))
return;
BYTE fsRemove, fsAdd;
if (bEnable) {
fsRemove = 0;
fsAdd = CBSTATE_ENABLED;
}
else {
fsRemove = CBSTATE_ENABLED;
fsAdd = 0;
}
if (m_arrBtn[nIndex].ModifyState(fsRemove, fsAdd)) {
InvalidateRect(m_arrBtn[nIndex].m_rcBtn);
UpdateWindow();
}
}
void RefreshBandIdealSize(CReBarCtrl rebar)
{
REBARBANDINFO rbBand;
rbBand.cbSize = sizeof(REBARBANDINFO);
rbBand.fMask = RBBIM_IDEALSIZE | RBBIM_CHILDSIZE;
int nIndex = rebar.IdToIndex(GetDlgCtrlID());
rebar.GetBandInfo(nIndex, &rbBand);
int nCount = GetButtonCount();
if (nCount != 0) {
rbBand.cxIdeal = m_arrBtn[nCount - 1].m_rcBtn.right;
rbBand.cxMinChild = m_arrBtn[0].m_rcBtn.Width();
}
rebar.SetBandInfo(nIndex, &rbBand);
}
// Message map and handlers
BEGIN_MSG_MAP(CCommandBarCtrl2Impl)
MESSAGE_HANDLER(WM_CREATE, OnCreate)
MESSAGE_HANDLER(WM_PAINT, OnPaint)
MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
CHAIN_MSG_MAP(CTrackMouseLeave<CCommandBarCtrl2Impl>)
ALT_MSG_MAP(1) // Parent window messages
MESSAGE_HANDLER(WM_ACTIVATE, OnParentActivate)
MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)
#if (_WIN32_IE >= 0x0500)
NOTIFY_CODE_HANDLER(RBN_CHEVRONPUSHED, OnChevronPushed)
#endif
END_MSG_MAP()
LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
// Let the toolbar initialize itself
LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);
// get and use system settings
GetSystemSettings();
// Parent init
CWindow wndParent = GetParent();
CWindow wndTopLevelParent = wndParent.GetTopLevelParent();
m_wndParent.SubclassWindow(wndTopLevelParent);
return lRet;
}
void _DoPaint(CDCHandle dc, LPCRECT lpRect = NULL)
{
CFontHandle fontOld = dc.SelectFont(m_fontMenu.m_hFont);
int modeOld = dc.SetBkMode(TRANSPARENT);
for (int i = 0; i < m_arrBtn.GetSize(); ++i) {
if (lpRect == NULL || MtlIsCrossRect(m_arrBtn[i].m_rcBtn, lpRect)) {
m_arrBtn[i].Update(dc.m_hDC);
}
}
dc.SelectFont(fontOld);
dc.SetBkMode(modeOld);
}
LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
{
if (m_dwExtendedStyle & CBR2_EX_TRANSPARENT) {
bHandled = FALSE;
return 0;
}
RECT rect;
GetClientRect(&rect);
::FillRect((HDC)wParam, &rect, (HBRUSH)LongToPtr(COLOR_MENU + 1));
return 1; // don't do the default erase
}
LRESULT OnMenuSelect(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
bHandled = FALSE;
UINT uItem = (UINT) LOWORD(wParam); // menu item or submenu index
UINT fuFlags = (UINT) HIWORD(wParam); // menu flags
HMENU hmenu = (HMENU) lParam;
if (m_nTrackingState == popup && hmenu != m_hMenu) {// it's not mine
// if no submenu, ->
m_bProcessRightArrow = (::GetSubMenu(hmenu, uItem) == NULL ||
::GetMenuState(hmenu, uItem, MF_BYPOSITION) & (MF_GRAYED | MF_DISABLED));
// if top leveled menu popping up, <-
HMENU hSubMenu = ::GetSubMenu(m_hMenu, m_nPopBtn);
m_bProcessLeftArrow = (hmenu == hSubMenu);
}
return 1;
}
LRESULT OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
if (wParam != NULL) {
_DoPaint((HDC)wParam);
}
else {
CPaintDC dc(m_hWnd);
_DoPaint(dc.m_hDC, &dc.m_ps.rcPaint);
}
return 0;
}
LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
m_bIgnoreInputMouseMove = false;
int nIndex = _HitTest(pt);
if (nIndex != -1)
_DoTrackPopupMenu(nIndex);
return 0;
}
// Overrides
void OnTrackMouseMove(UINT nFlags, CPoint pt)
{
int nIndex = _HitTest(pt);
if (_IsValidIndex(nIndex)) {
if (m_nPopBtn == -1 || m_nPopBtn != nIndex) {// if other button
_UpdateBar(hotByMouse, nIndex);// button made hot with mouse
}
}
else {
_UpdateBar();
}
}
void OnTrackMouseLeave()
{
if (m_nTrackingState != popup) {
_UpdateBar();
}
}
LRESULT OnParentActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
bool bParentActive = (wParam != WA_INACTIVE);
if (!bParentActive)
_UpdateBar();
for (int i = 0; i < m_arrBtn.GetSize(); ++i) {
if (bParentActive)
m_arrBtn[i].ModifyState(CBSTATE_INACTIVE, 0);
else
m_arrBtn[i].ModifyState(0, CBSTATE_INACTIVE);
}
Invalidate();
UpdateWindow();
bHandled = FALSE;
return 1;
}
#if (_WIN32_IE >= 0x0500)
LRESULT OnChevronPushed(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
{
LPNMREBARCHEVRON lpnm = (LPNMREBARCHEVRON)pnmh;
if (lpnm->wID != GetDlgCtrlID()) {
bHandled = FALSE;
return 1;
}
CMenuHandle menu = _PrepareChevronMenu();
_DisplayChevronMenu(menu, lpnm);
_CleanupChevronMenu(menu, lpnm);
return 0;
}
#endif
// Implementation - Hook proc
static LRESULT CALLBACK MessageHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
LPMSG pMsg = (LPMSG)lParam;
return (nCode == MSGF_MENU && s_pCurrentBar && s_pCurrentBar->OnMenuInput(pMsg))
? true : ::CallNextHookEx(s_hMsgHook, nCode, wParam, lParam);
}
void _CloseMenu()
{
// m_wndParent.PostMessage(WM_KEYDOWN, VK_ESCAPE);
m_wndParent.PostMessage(WM_CANCELMODE);
}
virtual bool OnMenuInput(MSG* pMsg)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -