📄 menubar.cpp
字号:
m_bIgnoreAlt = TRUE; // next SysKeyUp will be ignored
break;
}
return FALSE; // pass along...
}
BOOL CMenuBar::TranslateFrameMessage(MSG* pMsg)
{
ASSERT_VALID(this);
ASSERT(pMsg);
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 = HIWORD(pMsg->lParam) & KF_ALTDOWN; // Alt key presed?
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 none:
if (m_bIgnoreAlt == TRUE) {
// LTRACE(" ignore ALT key up\n");
m_bIgnoreAlt = FALSE;
break;
}
UpdateBar(button, GetNextOrPrevButton(0, FALSE));
break;
case button:
UpdateBar();
break;
case buttonmouse:
break; // do nothing
}
}
return TRUE;
}
else if ((nMsg == WM_SYSKEYDOWN || nMsg == WM_KEYDOWN)) {
if (m_nTrackingState == button) {
if (m_dwStyle & CBRS_ORIENT_HORZ) { // if horizontal
switch (vkey) {
case VK_LEFT:
case VK_RIGHT: {
int nNewIndex = GetNextOrPrevButton(m_nCurIndex, vkey == VK_LEFT);
UpdateBar(button, nNewIndex);
return TRUE;
}
case VK_SPACE:
case VK_UP:
case VK_DOWN:
TrackPopup(m_nCurIndex);
return TRUE;
case VK_ESCAPE:
UpdateBar();
return TRUE;
}
}
else { // if vertical
switch (vkey) {
case VK_UP:
case VK_DOWN:{
int nNewIndex = GetNextOrPrevButton(m_nCurIndex, vkey == VK_UP);
UpdateBar(button, nNewIndex);
return TRUE;
}
case VK_SPACE:
case VK_RIGHT:
case VK_LEFT:
TrackPopup(m_nCurIndex);
return TRUE;
case VK_ESCAPE:
UpdateBar();
return TRUE;
}
}
}
// Alt + X pressed
if ((bAlt || m_nTrackingState == button) && isalnum(vkey)) {
int nIndex;
if (MapAccessKey(vkey, nIndex) == TRUE) {
UpdateBar();
TrackPopup(nIndex);
return TRUE; // eat it!
}
else if (m_nTrackingState==button && !bAlt) {
// MessageBeep(0); // if you want
return TRUE;
}
}
if (m_nTrackingState > 0) { // unknown key
if (m_nTrackingState != buttonmouse) { // if tracked with mouse, don't update bar
UpdateBar();
}
}
}
}
return FALSE; // pass along...
}
BOOL CMenuBar::MapAccessKey(TCHAR cAccessKey, int& nIndex)
{
for (int i = 0; i < GetItemCount(); ++i) {
TCHAR cKey;
if (m_arrItem[i]->GetAccessKey(cKey) == TRUE &&
cKey == cAccessKey) {
nIndex = i;
return TRUE;
}
}
return FALSE;
}
/////////////////////////////////////////////////////////////////////////////
// CMenuBar layout
// calculate only layout from m_bWrapped
void CMenuBar::CalcFloatingLayout()
{
ASSERT_VALID(this);
ASSERT(::IsWindow(m_hWnd));
int xStart = CXGAP;
if (!IsFloating()) {
xStart += CXGRIPPER;
}
int xOffset = xStart;
int yOffset = CYGAP;
for (int i = 0; i < GetItemCount(); ++i) {
CMenuItem* pItem = m_arrItem[i];
if (pItem->IsValid()) {
CPoint ptItem(xOffset, yOffset);
pItem->Layout(ptItem, TRUE); // layout by itself!
if (pItem->m_bWrapped == TRUE) {
xOffset = xStart; // reset xOffset
yOffset += pItem->m_sizeHorz.cy;
}
else
xOffset += pItem->m_sizeHorz.cx;
}
}
}
// calulate ordinary layout and size without m_bWrapped
CSize CMenuBar::CalcLayout(DWORD dwMode, int nLength)
{
ASSERT_VALID(this);
ASSERT(::IsWindow(m_hWnd));
if (dwMode & LM_HORZDOCK)
ASSERT(dwMode & LM_HORZ);
CSize sizeResult(0, 0);
if (!(dwMode & LM_HORZ)) { // if vertical
int yOffset = CXGAP;
if (!IsFloating())
yOffset += CXGRIPPER;
for (int i = 0; i < GetItemCount(); ++i) {
CMenuItem* pItem = m_arrItem[i];
if (pItem->IsValid()) {
CPoint ptItem(CYGAPVERT, yOffset);
pItem->Layout(ptItem, FALSE); // layout by itself
yOffset += pItem->m_rcItem.Height();
}
}
int cxBar = max(::GetSystemMetrics(SM_CXSMICON), cyMenuButton + (CYGAPVERT)*2);
sizeResult = CSize(cxBar, yOffset+CXGAP);
}
else { // if horizontal
int xOffset = CXGAP;
if (!IsFloating())
xOffset += CXGRIPPER;
for (int i = 0; i < GetItemCount(); ++i) {
CMenuItem* pItem = m_arrItem[i];
if (pItem->IsValid()) {
CPoint ptItem(xOffset, CYGAP);
pItem->Layout(ptItem, TRUE); // layout by itself
xOffset += pItem->m_rcItem.Width();
}
}
int cyBar = max(::GetSystemMetrics(SM_CYSMICON), cyMenuButton + CYGAP*2);
sizeResult = CSize(xOffset+CXGAP, cyBar);
}
return sizeResult;
}
// in fact, it's never called
CSize CMenuBar::CalcFixedLayout(BOOL bStretch, BOOL bHorz)
{
// LTRACE("CMenuBar::CalcFixedLayout\n");
DWORD dwMode = bStretch ? LM_STRETCH : 0;
dwMode |= bHorz ? LM_HORZ : 0;
return CalcLayout(dwMode);
}
CSize CMenuBar::CalcDynamicLayout(int nLength, DWORD dwMode)
{
LTRACE("CMenuBar::CalcDynamicLayout\n");
// Who can understand what "dwMode" means?
//
// If you want it be pricisely same as DevStudio style,
// I think you have to create a "CDockContext" derived class.
// This is the reason why everyone think "CControlBar class" junk ?
ASSERT_VALID(this);
ASSERT_VALID(m_pDockSite);
ASSERT_VALID(m_pDockBar);
if (m_hMenu == NULL) // if have no menu yet, just return
return CSize(0, 0);
if (IsFloating()) {
CFrameWnd* pFrame = GetParentFrame();
ASSERT_VALID(pFrame);
CMenu* pSysMenu = pFrame->GetSystemMenu(FALSE);
ASSERT_VALID(pSysMenu);
pSysMenu->EnableMenuItem(SC_CLOSE, MF_BYCOMMAND | MF_DISABLED);
}
if (dwMode & LM_HORZ) { // horizontal
// LTRACE(" horizontal\n");
if (dwMode & LM_HORZDOCK) {
if (IsFloating() || (m_dwStyle & CBRS_ORIENT_VERT)) { // if Floating->Docking, return min size
// LTRACE(" return min size\n");
return CalcLayout(dwMode);
}
else {
if (m_pDockContext->m_pDC) { // now dragging
// return DockBar size
//LTRACE(" now dragging, so calc with DockBar\n");
CSize size = CalcSize(GetItemCount());//CalcLayout(dwMode);
CRect rcFrame;
m_pDockBar->GetWindowRect(rcFrame);
CRect rcBar;
GetWindowRect(rcBar);
rcBar.right = rcFrame.right;
return CSize(rcBar.Width() + cxBorder2, size.cy);
}
else {
//LTRACE(" no draggin calc bigger size\n");
CRect rcFrame;
m_pDockSite->GetWindowRect(rcFrame);
SizeMenuBar(GetItemCount(), rcFrame.Width() - cxBorder2*2, FALSE);
CalcFloatingLayout();
CSize size1 = CalcSize(GetItemCount());
return CSize(rcFrame.Width(), size1.cy);
}
}
}
else if (dwMode & LM_MRUWIDTH) { // floating size
//LTRACE(" return floating size\n");
SizeMenuBar(GetItemCount(), m_nMRUWidth, FALSE); // load floating Bar Width!
CalcFloatingLayout();
return CalcSize(GetItemCount());
}
else if (dwMode & LM_COMMIT) {
//LTRACE(" commit, just calc: %d\n", nLength);
m_nMRUWidth = nLength; // save floating Bar Width!!! (used when SaveBarState)
CalcFloatingLayout();
return CSize(0, 0); // MFC does'nt use this Size
}
else if (dwMode & LM_LENGTHY) {
//LTRACE(" nLength is height : %d\n", nLength);
SizeMenuBar(GetItemCount(), nLength, TRUE);
return CalcSize(GetItemCount());
}
else {
//LTRACE(" nLength is width : %d\n", nLength);
SizeMenuBar(GetItemCount(), nLength, FALSE);
return CalcSize(GetItemCount());
}
ASSERT(TRUE);
}
else { // vertical
InvalidateRect(NULL); // force to repaint!!!
//LTRACE(" vertical\n");
if (IsFloating() || (m_dwStyle & CBRS_ORIENT_HORZ)) { // if Floating->Docking, return min size
//LTRACE(" return min size\n");
return CalcLayout(dwMode);
}
else { // return large size
if (m_pDockContext->m_pDC) { // CDockContext::m_bDragging is not helpful :(
//LTRACE(" now dragging, so calc with DockBar\n");
CSize size = CalcLayout(dwMode);
CRect rcFrame;
m_pDockBar->GetWindowRect(rcFrame);
CRect rcBar;
GetWindowRect(rcBar);
rcBar.bottom = rcFrame.bottom;
return CSize(size.cx, rcBar.Height());
}
else {
//LTRACE(" no dragging, return biggest size\n");
CSize size = CalcLayout(dwMode);
CRect rcFrame;
m_pDockSite->GetWindowRect(rcFrame);
CRect rcBar;
GetWindowRect(rcBar);
rcBar.bottom = rcFrame.bottom;
return CSize(size.cx, rcFrame.Height());
}
}
}
ASSERT(TRUE); // never come here
return CalcLayout(dwMode, nLength);
}
void CMenuBar::DrawGripper(CDC* pDC)
{
if( (m_dwStyle & CBRS_FLOATING) || m_dwDockStyle == 0 )
return;
CRect rcGrip;
GetClientRect(&rcGrip);
if(m_dwStyle & CBRS_ORIENT_HORZ) {
// gripper at left
rcGrip.DeflateRect(4, 3);
rcGrip.right = rcGrip.left + 3;
pDC->DrawEdge(rcGrip, BDR_RAISEDINNER, BF_RECT);
rcGrip.OffsetRect(4, 0);
pDC->DrawEdge(rcGrip, BDR_RAISEDINNER, BF_RECT);
}
else {
// gripper at top
rcGrip.DeflateRect(3, 4);
rcGrip.bottom = rcGrip.top + 3;
pDC->DrawEdge(rcGrip, BDR_RAISEDINNER, BF_RECT);
rcGrip.OffsetRect(0, 4);
pDC->DrawEdge(rcGrip, BDR_RAISEDINNER, BF_RECT);
}
}
#define CX_BORDER 1
#define CY_BORDER 1
void CMenuBar::DrawBorder(CDC* pDC)
{
if( (m_dwStyle & CBRS_FLOATING) || m_dwDockStyle == 0 )
return;
CRect rect;
GetClientRect(rect);
DWORD dwStyle = m_dwStyle;
if (!(dwStyle & CBRS_BORDER_ANY))
return;
CRect rect3 = rect;
if (m_dwStyle & CBRS_ORIENT_HORZ) {
rect3.left += cxBorder2;//rect.DeflateRect(2, 0);
pDC->DrawEdge(rect3, BDR_RAISEDINNER, BF_LEFT);
}
else {
rect3.top += cyBorder2;//rect.DeflateRect(0, 2);
pDC->DrawEdge(rect3, BDR_RAISEDINNER, BF_TOP);
}
// prepare for dark lines
ASSERT(rect.top == 0 && rect.left == 0);
CRect rect1, rect2;
rect1 = rect;
rect2 = rect;
COLORREF clr = ::GetSysColor(COLOR_BTNSHADOW);//afxData.bWin4 ? afxData.clrBtnShadow : afxData.clrWindowFrame;
// draw dark line one pixel back/up
if (dwStyle & CBRS_BORDER_3D)
{
rect1.right -= CX_BORDER;
rect1.bottom -= CY_BORDER;
}
if (dwStyle & CBRS_BORDER_TOP)
rect2.top += CY_BORDER;//cyBorder2;
if (dwStyle & CBRS_BORDER_BOTTOM)
rect2.bottom -= CY_BORDER;
if (dwStyle & CBRS_BORDER_LEFT)
rect2.left += CX_BORDER;
if (dwStyle & CBRS_BORDER_RIGHT)
rect2.right -= CX_BORDER;
if (dwStyle & CBRS_BORDER_3D)
{
// draw left and top
if (dwStyle & CBRS_BORDER_LEFT)
pDC->DrawEdge(rect2, BDR_RAISEDINNER, BF_LEFT);//pDC->FillSolidRect(1, rect2.top, CX_BORDER, rect2.Height(), clr);
if (dwStyle & CBRS_BORDER_TOP)
pDC->DrawEdge(rect2, BDR_RAISEDINNER, BF_TOP);//pDC->FillSolidRect(0, 1, rect.right, CY_BORDER, clr);
// draw right and bottom
if (dwStyle & CBRS_BORDER_RIGHT)
pDC->DrawEdge(rect2, BDR_RAISEDINNER, BF_RIGHT);//pDC->FillSolidRect(rect.right, rect2.top, -CX_BORDER, rect2.Height(), clr);
if (dwStyle & CBRS_BORDER_BOTTOM)
pDC->DrawEdge(rect2, BDR_RAISEDINNER, BF_BOTTOM);//pDC->FillSolidRect(0, rect.bottom, rect.right, -CY_BORDER, clr);
}
}
/////////////////////////////////////////////////////////////////////////////
// CMenuBarFrameHook implementation
CMenuBarFrameHook::CMenuBarFrameHook()
{
m_pMenuBar = NULL;
}
BOOL CMenuBarFrameHook::Install(CMenuBar* pMenuBar, HWND hWndToHook)
{
ASSERT_VALID(pMenuBar);
ASSERT(m_pMenuBar == NULL);
m_pMenuBar = pMenuBar;
return HookWindow(hWndToHook);//CWnd::FromHandlePermanent(hWndToHook));
}
CMenuBarFrameHook::~CMenuBarFrameHook()
{
}
LRESULT CMenuBarFrameHook::WindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam)
{
ASSERT_VALID(m_pMenuBar);
switch (nMsg) {
case WM_MENUSELECT:
m_pMenuBar->OnMenuSelect((HMENU)lParam, (UINT)LOWORD(wParam));
break;
// The following messages are trapped for the MDI client window
case WM_INITMENUPOPUP:
LTRACE("CMenuBar::WM_INITMENUPOPUP\n");
if (!HIWORD(lParam) && (HMENU)wParam == m_pMenuBar->m_hWindowMenu)
m_pMenuBar->OnInitMenuPopup();
break;
case WM_MDISETMENU: // only sent to MDI client window
// Setting new frame/window menu: bypass MDI. wParam is new menu.
if (wParam) {
LTRACE("CMenuBar::WM_MDISETMENU 0x%04x\n", wParam);
// HMENU hNewMenu = (HMENU)wParam;
m_pMenuBar->OnSetMenu((HMENU)wParam, (HMENU)lParam);
}
return 0;
case WM_MDIREFRESHMENU: // only sent to MDI client window
// Normally, would call DrawMenuBar, but I have the menu, so eat it.
// LTRACE("CMenuBar::WM_MDIREFRESHMENU\n");
return 0;
case WM_PAINT:
// After changing the MDI maximized state, the client window gets a
// paint message. This is the most convenient place to find out; there
// is no WM_MDIMAXIMIZED message.
if (/*m_pWndHooked->*/m_hWnd == m_pMenuBar->m_hWndMDIClient)
m_pMenuBar->OnPaintMDIClient();//CheckMinMaxState();
break;
}
return CSubclassWnd::WindowProc(nMsg, wParam, lParam);
}
void CMenuBar::OnLButtonUp(UINT nFlags, CPoint point)
{
//LTRACE("CMenuBar::OnLButtonUp\n");
// TODO:
ASSERT(m_pMenuControl);
if (m_pMenuControl->OnMouseMsg(WM_LBUTTONUP, nFlags, point)) {
CControlBar::OnLButtonUp(nFlags, point);
return;
}
int nIndex = HitTestOnTrack(point);
/*
if (IsValidIndex(nIndex) && m_bDown == TRUE) {
HMENU hSubMenu = ::GetSubMenu(m_hMenu, nIndex);
if (hSubMenu == NULL) {
UINT nID = ::GetMenuItemID(m_hMenu, nIndex);
ASSERT(nID != -1);
GetOwner()->SendMessage(WM_COMMAND, (WPARAM)nID, (LPARAM)GetSafeHwnd());
UpdateBar();
}
}
*/
CControlBar::OnLButtonUp(nFlags, point);
}
void CMenuBar::DoPaint(CDC* pDC)
{
//LTRACE("CMenuBar::DoPaint\n");
CRect rect;
GetClientRect(rect);
// draw buttons
for (int i = 0; i < m_arrItem.GetSize(); ++i) {
CMenuItem* pItem = m_arrItem[i];
if (pItem->IsValid())
m_arrItem[i]->Update(pDC);
}
// draw decorations
DrawGripper(pDC);
DrawBorder(pDC);
// draw captions
if (m_pMenuControl) {
CRect rcDockBar;
m_pDockBar->GetClientRect(rcDockBar);
if (m_dwStyle & CBRS_ORIENT_HORZ) {
m_pMenuControl->DelayLayoutAndDraw(pDC, CSize(rcDockBar.Width() + cxBorder2, rect.Height()));
}
else {
m_pMenuControl->DelayLayoutAndDraw(pDC, CSize(rect.Width(), rcDockBar.Height()));
}
}
}
void CMenuBar::_KillTimer()
{
if (m_nIDEvent) {
KillTimer(m_nIDEvent);
m_nIDEvent = NULL;
}
}
int getPrevValidIndex(int nIndex)
{
--nIndex;
return nIndex;
}
// set only m_bWrapped by nWidth
int CMenuBar::WrapMenuBar(int nCount, int nWidth)
{
// LTRACE("CMenuBar::WrapMenuBar\n");
int nResult = 0;
int xStart = CXGAP;
if (!IsFloating() && !m_pDockContext->m_pDC) // if not floating and ****not dragging!!!****
xStart += CXGRIPPER;
int x = xStart;
for (int i = 0; i < nCount; ++i) {
CMenuItem* pItem = m_arrItem[i];
if (pItem->IsValid()) {
if (i+1 == nCount)
return ++nResult;
if (x + pItem->m_sizeHorz.cx + CXGAP> nWidth) {// itself is over
if (pItem->CanWrap()) {
pItem->m_bWrapped = TRUE;
++nResult;
x = xStart;
}
}
else if (x + pItem->m_sizeHorz.cx + m_arrItem[i+1]->m_sizeHorz.cx + CXGAP > nWidth) {
if (pItem->CanWrap()) {
pItem->m_bWrapped = TRUE;
++nResult;
x = xStart;
}
}
else {
pItem->m_bWrapped = FALSE;
x += pItem->m_sizeHorz.cx;
}
}
}
/* //another algorithm
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -