📄 mtlctrlw.h
字号:
{
int nMsg = pMsg->message;
CPoint pt = pMsg->lParam;
ScreenToClient(&pt);
switch (nMsg) {
case WM_MOUSEMOVE:
if (pt != m_ptMouse && !m_bIgnoreInputMouseMove) {
m_bIgnoreInputMouseMove = false;
int nIndex = _HitTest(pt);
if (_IsValidIndex(nIndex) && nIndex != m_nPopBtn) {
// defferent button clicked
// ATLTRACE(_T("defferent button clicked\n"));
_CloseMenu();
_UpdateBar(); // clean up
m_nPopBtn = nIndex;
m_bLoop = true; // continue loop
}
m_ptMouse = pt;
}
break;
case WM_LBUTTONDOWN: {
int nIndex = _HitTest(pt);
if (nIndex != -1 && nIndex == m_nPopBtn) {
// same button clicked
_CloseMenu();
_UpdateBar(hotByMouse, m_nPopBtn);
m_bLoop = false; // out of loop
return true; // eat it!
}
}
break;
case WM_KEYDOWN: {
TCHAR vKey = pMsg->wParam;
if ((vKey == VK_LEFT && m_bProcessLeftArrow) ||
(vKey == VK_RIGHT && m_bProcessRightArrow)) {
// no submenu
int nNewIndex = _GetNextOrPrevButton(m_nPopBtn, vKey==VK_LEFT);
_CloseMenu();
_UpdateBar();
m_nPopBtn = nNewIndex;
m_bLoop = true; // continue loop
return true; // eat it!
}
}
break;
case WM_SYSKEYDOWN:
// LTRACE(_T(" m_bIgnore = true\n"));
m_bIgnoreAlt = true; // next SysKeyUp will be ignored
break;
}
return false; // pass along...
}
bool _IsAltKeyDown(MSG* pMsg)
{
bool bAlt = HIWORD(pMsg->lParam) & KF_ALTDOWN;
bool bExt = HIWORD(pMsg->lParam) & 0x0100;
return bAlt && !bExt;
}
BOOL PreTranslateMessagePrevVer(MSG* pMsg)
{
if (!m_hWnd)
return FALSE;
UINT nMsg = pMsg->message;
if (WM_LBUTTONDOWN <= nMsg && nMsg <= WM_MOUSELAST) {
if (pMsg->hwnd != m_hWnd && m_nTrackingState > 0) {
// clicked outside
_UpdateBar();
}
}
else if (nMsg == WM_SYSKEYDOWN || nMsg == WM_SYSKEYUP || nMsg == WM_KEYDOWN) {
bool bAlt = _IsAltKeyDown(pMsg); // Alt key pressed?
TCHAR vkey = pMsg->wParam; // + X key
if (vkey == VK_MENU ||
(vkey == VK_F10 && !((GetKeyState(VK_SHIFT) & 0x80000000) ||
(GetKeyState(VK_CONTROL) & 0x80000000) || bAlt))) {
// only alt key pressed
if (nMsg == WM_SYSKEYUP) {
switch (m_nTrackingState) {
case hotByMouse: // NOTE. the mouse hook send WM_MOUSEMOVE even if mouse not moving...
m_bIgnoreInputMouseMove = true;
// break; // do nothing
case none:
if (m_bIgnoreAlt) {
m_bIgnoreAlt = false;
break;
}
_UpdateBar(hotByAlt, 0);
break;
case hotByAlt:
_UpdateBar();
break;
}
}
return true;
}
else if ((nMsg == WM_SYSKEYDOWN || nMsg == WM_KEYDOWN)) {
if (m_nTrackingState == hotByAlt) {
switch (vkey) {
case VK_LEFT:
case VK_RIGHT: {
int nNewIndex = _GetNextOrPrevButton(m_nPopBtn, vkey == VK_LEFT);
_UpdateBar(hotByAlt, nNewIndex);
return true;
}
case VK_SPACE:
case VK_UP:
case VK_DOWN:
_DoTrackPopupMenu(m_nPopBtn);
return true;
case VK_ESCAPE:
_UpdateBar();
return true;
}
}
// Alt + X pressed
if ((bAlt || m_nTrackingState == hotByAlt) && Mtl_istalnum(vkey)) {
int nIndex;
if (_MapAccessKey(vkey, nIndex)) {
_UpdateBar();
_DoTrackPopupMenu(nIndex);
return true; // eat it!
}
else if (m_nTrackingState == hotByAlt && !bAlt) {
// MessageBeep(0); // if you want
return true;
}
}
if (m_nTrackingState > 0) { // unknown key
if (m_nTrackingState != hotByMouse) { // if tracked with mouse, don't update bar
_UpdateBar();
}
}
}
}
return FALSE; // pass along...
}
BOOL PreTranslateMessage(MSG* pMsg)
{
if (m_hWnd == NULL)
return FALSE;
int nVirtKey = pMsg->wParam;
UINT message = pMsg->message;
if (message == WM_SYSKEYUP && nVirtKey == VK_MENU) { // just alt key up
switch (m_nTrackingState) {
case hotByMouse: // NOTE. the mouse hook send WM_MOUSEMOVE even if mouse not moving...
m_bIgnoreInputMouseMove = true;
// break; // do nothing
case none:
if (m_bIgnoreAlt) {
m_bIgnoreAlt = false;
break;
}
_UpdateBar(hotByAlt, 0);
break;
case hotByAlt:
_UpdateBar();
break;
}
return TRUE; // eat it
}
else if (message == WM_KEYDOWN && m_nTrackingState == hotByAlt) {// alt key tracking
switch (nVirtKey) {
case VK_LEFT:
case VK_RIGHT: {
int nNewIndex = _GetNextOrPrevButton(m_nPopBtn, nVirtKey == VK_LEFT);
_UpdateBar(hotByAlt, nNewIndex);
return TRUE;
}
case VK_RETURN:
case VK_UP:
case VK_DOWN:
_DoTrackPopupMenu(m_nPopBtn);
return TRUE;
case VK_ESCAPE:
_UpdateBar();
return TRUE;
}
}
else if (pMsg->message == WM_SYSKEYDOWN) { // access key
if (nVirtKey == VK_MENU || nVirtKey == VK_SHIFT)
return FALSE;
// Alt + X pressed
if (Mtl_istalnum(nVirtKey)) {
int nIndex;
if (_MapAccessKey(nVirtKey, nIndex)) {
_UpdateBar();
_DoTrackPopupMenu(nIndex);
return TRUE; // eat it!
}
}
// unknown access key
if (m_nTrackingState != hotByMouse) {
_UpdateBar();
}
}
return FALSE; // pass along...
}
// Implementation
void _DoTrackPopupMenu(int nIndex)
{
ATLASSERT(_IsValidIndex(nIndex));
m_nPopBtn = nIndex;
m_bLoop = true;
while (m_bLoop) {
// UpdateWindow();// force to repaint when button hidden by other window
_UpdateBar(popup, m_nPopBtn);
// install hook
ATLASSERT(s_pCurrentBar == NULL);
s_pCurrentBar = this;
ATLASSERT(s_hMsgHook == NULL);
m_bLoop = false;
s_hMsgHook = ::SetWindowsHookEx(WH_MSGFILTER, MessageHookProc, NULL, ::GetCurrentThreadId());// m_bLoop may become true
// popup!!
m_nTrackingState = popup;
m_wndParent.SendMessage(WM_MENUSELECT, MAKEWPARAM(m_nPopBtn, MF_POPUP), (LPARAM)m_hMenu);// for help message line
ATLASSERT(_IsValidIndex(m_nPopBtn));
m_arrBtn[m_nPopBtn].TrackPopup(m_hWnd, m_wndParent, s_bW2K);
// uninstall hook
::UnhookWindowsHookEx(s_hMsgHook);
s_hMsgHook = NULL;
s_pCurrentBar = NULL;
}
_UpdateBar();
}
void _UpdateBar(_TrackingState nState = none, int nNewPopBtn = -1)
{
if (m_nTrackingState == hotByMouse)
m_bIgnoreAlt = false;// if prev state is hotByMouse, always should be false!
m_nTrackingState = nState;
// clean up
if (_IsValidIndex(m_nPopBtn)) {
m_arrBtn[m_nPopBtn].ModifyState(CBSTATE_HOT | CBSTATE_PRESSED, 0);
InvalidateRect(m_arrBtn[m_nPopBtn].m_rcBtn);
UpdateWindow();
}
m_nPopBtn = -1;
if (nState != none) {
ATLASSERT(_IsValidIndex(nNewPopBtn));
m_nPopBtn = nNewPopBtn;
CCmdBarButton& cbbtn = m_arrBtn[nNewPopBtn];
if (nState == hotByAlt || nState == hotByMouse) {
cbbtn.ModifyState(CBSTATE_PRESSED, CBSTATE_HOT);
InvalidateRect(cbbtn.m_rcBtn);
UpdateWindow();
}
else if (nState == popup) {
cbbtn.ModifyState(CBSTATE_HOT, CBSTATE_PRESSED);
InvalidateRect(cbbtn.m_rcBtn);
UpdateWindow();
}
}
else {
// must be default parameter
ATLASSERT(nNewPopBtn == -1);
}
m_bProcessRightArrow = m_bProcessLeftArrow = true;
}
bool _MapAccessKey(TCHAR cAccessKey, int& nIndex)
{
for (int i = 0; i < m_arrBtn.GetSize(); ++i) {
// fixing point
TCHAR cKey = m_arrBtn[i].m_cAccessKey;
if (Mtl_tolower(cKey)/*_totupper(cKey)*/ == Mtl_tolower(cAccessKey) &&
m_arrBtn[i].m_fsState & CBSTATE_ENABLED) {
nIndex = i;
return true;
}
}
return false;
}
int _HitTest(CPoint point)
{
CRect rc;
GetClientRect(&rc);
if (!rc.PtInRect(point))
return -1;
if (m_nTrackingState == popup) {
CPoint ptScreen = point;
ClientToScreen(&ptScreen);
if (::WindowFromPoint(ptScreen) != m_hWnd) // the puzzle figured out!
return -1;
}
for (int i = 0; i < m_arrBtn.GetSize(); ++i) {
if (m_arrBtn[i].m_rcBtn.PtInRect(point) &&
m_arrBtn[i].m_fsState & CBSTATE_ENABLED) {
return i;
}
}
return -1;
}
int _GetNextOrPrevButton(int nIndex, BOOL bPrev)
{
int nCount = m_arrBtn.GetSize();
if (bPrev) { // <-
--nIndex;
if (nIndex < 0)
nIndex = nCount - 1;
}
else { // ->
++nIndex;
if (nIndex >= nCount)
nIndex = 0;
}
if ( (m_arrBtn[nIndex].m_fsState & CBSTATE_HIDDEN) ||
!(m_arrBtn[nIndex].m_fsState & CBSTATE_ENABLED)) {
return _GetNextOrPrevButton(nIndex, bPrev);
}
return nIndex;
}
bool _IsValidIndex(int nIndex)
{
if (0 <= nIndex && nIndex < m_arrBtn.GetSize())
return true;
else
return false;
}
void _ClearAll()
{
m_arrBtn.RemoveAll();
}
void _AddButtons(HMENU hMenu)
{
ATLASSERT(::IsMenu(hMenu));
int nItems = ::GetMenuItemCount(hMenu);
T* pT = static_cast<T*>(this);
TCHAR szString[pT->_nMaxMenuItemTextLength];
int cxOffset = 0;
for(int i = 0; i < nItems; ++i) {
CMenuItemInfo mii;
mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_SUBMENU;
mii.fType = MFT_STRING;
mii.dwTypeData = szString;
mii.cch = pT->_nMaxMenuItemTextLength;
BOOL bRet = ::GetMenuItemInfo(m_hMenu, i, true, &mii);
ATLASSERT(bRet);
// If we have more than the buffer, we assume we have bitmaps bits
if (::lstrlen(szString) > pT->_nMaxMenuItemTextLength - 1) {
mii.fType = MFT_BITMAP;
::SetMenuItemInfo(m_hMenu, i, true, &mii);
szString[0] = 0;
}
// NOTE: Command Bar2 currently supports only drop-down menu items
ATLASSERT(mii.hSubMenu != NULL);
BYTE fsState = (BYTE)(((mii.fState & MFS_DISABLED) == 0) ? CBSTATE_ENABLED : 0);
CCmdBarButton cbbtn(fsState, szString, mii.hSubMenu);
cbbtn.m_rcBtn = _MeasureButton(szString) + CPoint(cxOffset, 0);
cxOffset = cxOffset + cbbtn.m_rcBtn.Width();
m_arrBtn.Add(cbbtn);
// ATLTRACE(_T("cxOffset : %d\n"), cxOffset);
}
MoveWindow(0, 0, cxOffset, m_arrBtn[0].m_rcBtn.Height());
}
CRect _MeasureButton(const CString& strText)
{
// compute size of text - use DrawText with DT_CALCRECT
int cx = MtlComputeWidthOfText(strText, m_fontMenu);
LOGFONT lf;
m_fontMenu.GetLogFont(lf);
int cy = lf.lfHeight;
if(cy < 0)
cy = -cy;
cy += 2 * s_kcyTextMargin;
// height of item is the bigger of these two
cy = MtlMax(cy, ::GetSystemMetrics(SM_CYMENU) - 1);
// width is width of text plus a bunch of stuff
cx += 2 * s_kcxTextMargin; // L/R margin for readability
// ATLTRACE(_T("(cx, cy) = (%d, %d)\n"), cx, cy);
return CRect(0, 0, cx, cy);
}
CMenuHandle _PrepareChevronMenu()
{
CMenuHandle menuCmdBar(m_hMenu);
// build a menu from hidden items
CMenuHandle menu;
BOOL bRet = menu.CreatePopupMenu();
ATLASSERT(bRet);
RECT rcClient;
bRet = GetClientRect(&rcClient);
ATLASSERT(bRet);
for (int i = 0; i < m_arrBtn.GetSize(); ++i) {
CCmdBarButton cbb = m_arrBtn[i];
bool bEnabled = ((cbb.m_fsState & CBSTATE_ENABLED) != 0);
if (cbb.m_rcBtn.right > rcClient.right) {
TCHAR szBuff[100];
CMenuItemInfo mii;
mii.fMask = MIIM_TYPE | MIIM_SUBMENU;
mii.dwTypeData = szBuff;
mii.cch = sizeof(szBuff) / sizeof(TCHAR);
bRet = menuCmdBar.GetMenuItemInfo(i, TRUE, &mii);
ATLASSERT(bRet);
// Note: CmdBar currently supports only drop-down items
ATLASSERT(::IsMenu(mii.hSubMenu));
bRet = menu.AppendMenu(MF_STRING | MF_POPUP | (bEnabled ? MF_ENABLED : MF_GRAYED), (UINT_PTR)mii.hSubMenu, mii.dwTypeData);
ATLASSERT(bRet);
}
}
if (menu.GetMenuItemCount() == 0) { // no hidden buttons after all
menu.DestroyMenu();
return NULL;
}
return menu;
}
#if (_WIN32_IE >= 0x0500)
void _DisplayChevronMenu(CMenuHandle menu, LPNMREBARCHEVRON lpnm)
{
// convert chevron rect to screen coordinates
CWindow wndFrom = lpnm->hdr.hwndFrom;
RECT rc = lpnm->rc;
wndFrom.ClientToScreen(&rc);
// set up flags and rect
UINT uMenuFlags = TPM_LEFTBUTTON | TPM_VERTICAL | TPM_LEFTALIGN | TPM_TOPALIGN | (!AtlIsOldWindows() ? TPM_VERPOSANIMATION : 0);
TPMPARAMS TPMParams;
TPMParams.cbSize = sizeof(TPMPARAMS);
TPMParams.rcExclude = rc;
::TrackPopupMenuEx(menu.m_hMenu, uMenuFlags, rc.left, rc.bottom, m_wndParent, &TPMParams);
}
void _CleanupChevronMenu(CMenuHandle menu, LPNMREBARCHEVRON lpnm)
{
// if menu is from a command bar, detach submenus so they are not destroyed
for(int i = menu.GetMenuItemCount() - 1; i >=0; i--)
menu.RemoveMenu(i, MF_BYPOSITION);
// destroy menu
menu.DestroyMenu();
// convert chevron rect to screen coordinates
CWindow wndFrom = lpnm->hdr.hwndFrom;
RECT rc = lpnm->rc;
wndFrom.ClientToScreen(&rc);
// eat next message if click is on the same button
MtlEatNextLButtonDownOnChevron(m_wndParent, rc);
}
#endif
void GetSystemSettings()
{
// refresh our font
NONCLIENTMETRICS info;
info.cbSize = sizeof(info);
::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0);
LOGFONT logfont;
memset(&logfont, 0, sizeof(LOGFONT));
if(m_fontMenu.m_hFont != NULL)
m_fontMenu.GetLogFont(logfont);
if(logfont.lfHeight != info.lfMenuFont.lfHeight ||
logfont.lfWidth != info.lfMenuFont.lfWidth ||
logfont.lfEscapement != info.lfMenuFont.lfEscapement ||
logfont.lfOrientation != info.lfMenuFont.lfOrientation ||
logfont.lfWeight != info.lfMenuFont.lfWeight ||
logfont.lfItalic != info.lfMenuFont.lfItalic ||
logfont.lfUnderline != info.lfMenuFont.lfUnderline ||
logfont.lfStrikeOut != info.lfMenuFont.lfStrikeOut ||
logfont.lfCharSet != info.lfMenuFont.lfCharSet ||
logfont.lfOutPrecision != info.lfMenuFont.lfOutPrecision ||
logfont.lfClipPrecision != info.lfMenuFont.lfClipPrecision ||
logfont.lfQuality != info.lfMenuFont.lfQuality ||
logfont.lfPitchAndFamily != info.lfMenuFont.lfPitchAndFamily ||
lstrcmp(logfont.lfFaceName, info.lfMenuFont.lfFaceName) != 0)
{
HFONT hFontMenu = ::CreateFontIndirect(&info.lfMenuFont);
ATLASSERT(hFontMenu != NULL);
if(hFontMenu != NULL)
{
if(m_fontMenu.m_hFont != NULL)
m_fontMenu.DeleteObject();
m_fontMenu.Attach(hFontMenu);
SetFont(m_fontMenu);
}
}
}
};
class CCommandBarCtrl2 : public CCommandBarCtrl2Impl<CCommandBarCtrl2>
{
public:
DECLARE_WND_CLASS_EX(_T("MTL_CommandBar2"), NULL, COLOR_BTNFACE)
};
#ifdef __ATLCTRLW_H__
class CCoolMenuManager
{
public:
WTL::CCommandBarCtrl m_CmdBar;
BOOL Install(HWND hWnd)
{
return m_CmdBar.AttachToWindow(hWnd);
}
BOOL LoadImages(int* __firstID, int* __lastID,
UINT nImageBmpID, int cx, int cy, COLORREF clrMask, UINT nFlags = ILC_COLOR8)
{
return MtlCmdBarLoadImages(m_CmdBar, __firstID, __lastID, nImageBmpID, cx, cy, clrMask, nFlags);
}
void Validate(bool bOn)
{
m_CmdBar.SetImagesVisible(bOn);
}
};
#endif
////////////////////////////////////////////////////////////////////////////
} //namespace MTL
#endif // __MTLCTRLW_H__
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -