📄 menubar.cpp
字号:
// get last item position to measure bar size
CRect rcItem;
GetItemRect(m_nItemCount-1, &rcItem);
CRect rcRect(0, 0, rcItem.right, rcItem.bottom);
if (GetParent() == GetParentFrame())
{
// not in a rebar yet, just resize the toolbar
MoveWindow(&rcRect, FALSE);
}
else
{
// update band information
REBARBANDINFO rbbi;
ZeroMemory(&rbbi, sizeof(rbbi));
rbbi.cbSize = sizeof(rbbi);
rbbi.fMask = RBBIM_CHILD;
CReBarCtrl* pReBar = (CReBarCtrl*)GetParent();
for (UINT i=0; i<pReBar->GetBandCount(); i++)
{
pReBar->GetBandInfo(i, &rbbi);
if (rbbi.hwndChild == m_hWnd)
{
rbbi.fMask = RBBIM_CHILDSIZE;
rbbi.cyMinChild = rbbi.cyMaxChild = rbbi.cyChild = rcRect.Height();
rbbi.cxMinChild = rcRect.Width();
pReBar->SetBandInfo(i, &rbbi);
// force updating bands layout
CRect rcClient;
pReBar->GetClientRect(&rcClient);
pReBar->MoveWindow(0, 0, 1, 1, FALSE);
pReBar->MoveWindow(&rcClient);
// recalc frame window layout
GetParentFrame()->RecalcLayout();
break;
}
}
}
}
/////////////////////////////////////////////////////////////////////////////
// CMenuBar menu popup
LRESULT CMenuBar::OnPopupMenu(WPARAM wParam, LPARAM lParam)
{
// correct index if necessary
if (m_nPressed<0)
m_nPressed = m_nItemCount - 1;
if (m_nPressed>=m_nItemCount)
m_nPressed = 0;
OpenPopup();
return 0;
}
BOOL CMenuBar::OpenMenu(UINT nChar)
{
for (int i=0; i<m_nItemCount; i++)
{
CString strText;
m_pMenu->GetMenuString(i, strText, MF_BYPOSITION);
// check menu mnemonic
int iAmpersand = strText.Find('&');
if (iAmpersand >=0 && toupper(nChar)==toupper(strText[iAmpersand+1]))
{
// open matching menu
m_nPressed = i;
m_bKeyboard = TRUE;
PostMessage(MBM_POPUPMENU);
SetPrefix(TRUE);
return TRUE;
}
}
return FALSE;
}
void CMenuBar::OpenPopup()
{
// if the menu bar has focus, give it back
CWnd *pWnd = GetFocus();
if (pWnd && pWnd->m_hWnd==m_hWnd && m_pPrevFocus && IsWindow(m_pPrevFocus->m_hWnd))
{
BOOL bRest = m_bPrefix; // prevent from removing prefixes
m_pPrevFocus->SetFocus();
SetPrefix(bRest);
m_pPrevFocus = NULL;
}
m_bSelPopup = FALSE;
m_hSelMenu = (HMENU)-1;
m_bKeepPrefix = FALSE;
m_bNextMenu = FALSE;
m_bPopMenu = FALSE;
CMenu *pSubMenu = m_pMenu->GetSubMenu(m_nPressed);
// change the state of the menu button
SetHotItem(-1);
PressButton(m_nPressed, TRUE);
// notify frame window that menu is selected
GetParentFrame()->SendMessage(WM_MENUSELECT, MAKELONG(m_nPressed, MF_POPUP | MF_HILITE | MF_MOUSESELECT), (LPARAM)m_pMenu->m_hMenu);
CRect rc;
GetItemRect(m_nPressed, &rc);
ClientToScreen(&rc);
CRect rcScreen;
CWnd *pDesktop = GetDesktopWindow();
if(pDesktop)
pDesktop->GetWindowRect(rcScreen);
else
AfxMessageBox("Err0");
rc.IntersectRect(rc, rcScreen);
CString str;
TPMPARAMS tpm;
tpm.cbSize = sizeof(tpm);
tpm.rcExclude = rc;
// install message filter
g_pMenuBar = this;
g_hMsgHook = SetWindowsHookEx(WH_MSGFILTER, MenuInputFilter, NULL, GetCurrentThreadId());
// do menu loop
// TrackPopupMenuEx(pSubMenu->GetSafeHmenu(),
// TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_VERTICAL | TPM_VERPOSANIMATION,
// rc.left, rc.bottom, m_hWnd, &tpm);
if(pSubMenu && pDesktop)
{
// str.Format("%d", pSubMenu->GetSafeHmenu());
// AfxMessageBox(str);
TrackPopupMenuEx(pSubMenu->GetSafeHmenu(),
TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_VERTICAL | TPM_VERPOSANIMATION,
rc.left, rc.bottom, m_hWnd, &tpm);
}
else
AfxMessageBox("Err");
// remove message filter
UnhookWindowsHookEx(g_hMsgHook);
g_hMsgHook = NULL;
g_pMenuBar = NULL;
// unpress the button
PressButton(m_nPressed, FALSE);
// remove prefixes if not asked to keep
if (!m_bKeepPrefix)
SetPrefix(FALSE);
// notify frame window that menu is closing
// if another menu is not about to open
if (!m_bNextMenu)
GetParentFrame()->SendMessage(WM_MENUSELECT, MAKELONG(m_nPressed, 0xFFFF), (LPARAM)m_pMenu->GetSafeHmenu());
}
/////////////////////////////////////////////////////////////////////////////
// CMenuBar message handlers
void CMenuBar::OnLButtonDown(UINT nFlags, CPoint point)
{
int nTest = HitTest(&point);
if (nTest<0 || nTest>=m_nItemCount)
{
AfxMessageBox("Err");
return;
}
m_nPressed = nTest;
m_bKeyboard = FALSE;
// open menu when button is clicked
OpenPopup();
}
void CMenuBar::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu)
{
CToolBarCtrl::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu);
// pass message to frame window to let the update handlers do their job
GetParentFrame()->SendMessage(WM_INITMENUPOPUP, (WPARAM)pPopupMenu->GetSafeHmenu(), MAKELONG(nIndex, bSysMenu));
MENUITEMINFO miinfo;
ZeroMemory(&miinfo, sizeof(miinfo));
miinfo.cbSize = sizeof(miinfo);
miinfo.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STATE;
// set ownerdraw flag for menu items
for (int i=0; i<(int)pPopupMenu->GetMenuItemCount(); i++)
{
GetMenuItemInfo(pPopupMenu->m_hMenu, i, TRUE, &miinfo);
//if (miinfo.fType & MFT_SEPARATOR)
//{
// //continue; // use standard separators
//}
miinfo.fType |= MFT_OWNERDRAW;
SetMenuItemInfo(pPopupMenu->m_hMenu, i, TRUE, &miinfo);
}
if (m_bKeyboard)
{
// a simple trick to highlight the first menu item
PostMessage(WM_KEYDOWN, VK_DOWN, 0);
m_bKeyboard = FALSE;
}
}
BOOL CMenuBar::PreMenuMessage(MSG* pMsg)
{
if (pMsg->message == WM_SYSKEYDOWN && pMsg->wParam == VK_MENU)
SetPrefix(TRUE);
else if (pMsg->message == WM_KEYUP && pMsg->wParam == VK_MENU)
SetPrefix(FALSE);
else if (pMsg->message == WM_ACTIVATE)
Activate(LOWORD(pMsg->wParam) != WA_INACTIVE);
else if (pMsg->message == WM_MENUCHAR)
OpenMenu(LOWORD(pMsg->wParam));
else if (pMsg->message == WM_SETTINGCHANGE)
UpdateSettings();
else if (pMsg->message == WM_SYSCOMMAND)
{
if (pMsg->wParam == SC_KEYMENU && OnKeyMenu(pMsg->lParam))
return FALSE;
}
return TRUE;
}
BOOL CMenuBar::PreTranslateMessage(MSG* pMsg)
{
// handle key messages when the menu bar has focus
if (pMsg->message == WM_KEYDOWN ||
pMsg->message == WM_SYSKEYDOWN)
{
int nItem = GetHotItem();
switch (pMsg->wParam)
{
case VK_RETURN: // open selected menu
case VK_UP:
case VK_DOWN:
m_nPressed = nItem;
m_bKeyboard = TRUE;
OpenPopup();
return TRUE;
case VK_ESCAPE: // restore focus
if(m_pPrevFocus)
m_pPrevFocus->SetFocus();
m_pPrevFocus = NULL;
return TRUE;
default: // check mnemonic
if (OpenMenu((UINT)pMsg->wParam))
return TRUE;
break;
}
}
return CToolBarCtrl::PreTranslateMessage(pMsg);
}
void CMenuBar::OnKillFocus(CWnd* pNewWnd)
{
SetHotItem(-1);
SetPrefix(FALSE);
CToolBarCtrl::OnKillFocus(pNewWnd);
}
// pass these messages to parent frame to enable status bar updating
void CMenuBar::OnEnterIdle(UINT nWhy, CWnd* pWho)
{
GetParentFrame()->SendMessage(WM_ENTERIDLE, nWhy, (LPARAM)pWho->m_hWnd);
}
void CMenuBar::OnMenuSelect(UINT nItemID, UINT nFlags, HMENU hSysMenu)
{
GetParentFrame()->SendMessage(WM_MENUSELECT, MAKELONG(nItemID, nFlags), (LPARAM)hSysMenu);
}
BOOL CMenuBar::OnKeyMenu(UINT nKey)
{
if (nKey == VK_SPACE)
{
// window menu will be opened
if (GetFocus()->m_hWnd == m_hWnd)
Highlight(-1);
else
SetPrefix(FALSE);
}
else if (nKey == 0)
{
// activate or deactivate menu bar
if (GetFocus()->m_hWnd == m_hWnd)
Highlight(-1);
else
{
SetPrefix();
Highlight();
}
return TRUE;
}
return FALSE;
}
/////////////////////////////////////////////////////////////////////////////
// CMenuBar menu bar drawing
void CMenuBar::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMTBCUSTOMDRAW lpNMCustomDraw = (LPNMTBCUSTOMDRAW)pNMHDR;
switch (lpNMCustomDraw->nmcd.dwDrawStage)
{
case CDDS_PREPAINT:
if (m_bFlatMenu || !m_bWndActive)
*pResult = CDRF_NOTIFYITEMDRAW;
break;
case CDDS_ITEMPREPAINT:
if (m_bFlatMenu) // draw flat-style menu bar
{
CDC dc;
dc.Attach(lpNMCustomDraw->nmcd.hdc);
CRect rcRect = lpNMCustomDraw->nmcd.rc;
int nState = lpNMCustomDraw->nmcd.uItemState;
BOOL bHilight = nState & (CDIS_HOT | CDIS_SELECTED);
if (bHilight) // draw highlight rectangle
{
DrawTop(&dc,rcRect,nState);
/* CBrush brHighlight;
brHighlight.CreateSysColorBrush(COLOR_HIGHLIGHT);
CBrush brMenuHilight;
brMenuHilight.CreateSysColorBrush(COLOR_MENUHILIGHT);
dc.FillRect(&rcRect, &brMenuHilight);
dc.FrameRect(&rcRect, &brHighlight);
*/
}
char buf[80];
SendMessage(TB_GETBUTTONTEXT, lpNMCustomDraw->nmcd.dwItemSpec, (LPARAM)buf);
CString strText = buf;
// draw text
dc.SelectObject(GetFont());
// dc.SetTextColor(GetSysColor(m_bWndActive
// ? (bHilight ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT)
// : COLOR_GRAYTEXT));
dc.SetTextColor(GetSysColor(m_bWndActive?COLOR_MENUTEXT : COLOR_GRAYTEXT));
dc.SetBkMode(TRANSPARENT);
dc.DrawText(strText, &rcRect, DT_VCENTER | DT_CENTER | DT_SINGLELINE
| (m_bPrefix ? 0 : DT_HIDEPREFIX));
dc.Detach();
*pResult = CDRF_SKIPDEFAULT;
}
else if (!m_bWndActive) // draw gray text if window is inactive
{
lpNMCustomDraw->clrText = GetSysColor(COLOR_GRAYTEXT);
*pResult = CDRF_DODEFAULT;
}
break;
}
}
void CMenuBar::SetPrefix(BOOL bPrefix)
{
if (m_bPrefix == bPrefix)
return;
// ignore if cues are always displayed
if (!bPrefix && m_bCues)
return;
m_bPrefix = bPrefix;
RedrawWindow();
}
void CMenuBar::Activate(BOOL bActive)
{
if (m_bWndActive == bActive)
return;
SetPrefix(FALSE);
// change the color of menu text
m_bWndActive = bActive;
RedrawWindow();
}
/////////////////////////////////////////////////////////////////////////////
// CMenuBar menu item drawing
void CMenuBar::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
CDC dc;
dc.CreateCompatibleDC(NULL);
dc.SelectObject(&m_Font);
UINT nID = lpMeasureItemStruct->itemID;
CMenu* pMenu = m_bPopMenu ? m_pPopupMenu : m_pMenu;
CString strString;
pMenu->GetMenuString(nID, strString, MF_BYCOMMAND);
// split string to command name and keyboard shortcut
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -