📄 menubar.cpp
字号:
DrawBorders(&dc, rectWindow);
// erase parts not drawn
dc.IntersectClipRect(rectWindow);
SendMessage(WM_ERASEBKGND, (WPARAM)dc.m_hDC);
// draw gripper in non-client area
_DrawGripper(&dc, rectWindow);
}
#define CX_BORDER 1
#define CY_BORDER 1
void CMenuBar::DrawRaisedBorders(CDC* pDC, CRect& rect)
{
ASSERT_VALID(this);
ASSERT_VALID(pDC);
DWORD dwStyle = m_dwStyle;
if (!(dwStyle & CBRS_BORDER_ANY))
return;
// prepare for dark lines
ASSERT(rect.top == 0 && rect.left == 0);
CRect rect1, rect2;
rect1 = rect;
rect2 = rect;
COLORREF clrBtnShadow = ::GetSysColor(COLOR_BTNSHADOW);//afxData.bWin4 ? afxData.clrBtnShadow : afxData.clrWindowFrame;
COLORREF clrBtnFace = ::GetSysColor(COLOR_BTNFACE);
COLORREF clrBtnHilight = ::GetSysColor(COLOR_BTNHILIGHT);
// 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 += cyBorder2;
if (dwStyle & CBRS_BORDER_BOTTOM)
rect2.bottom -= cyBorder2;
// draw left and top
if (dwStyle & CBRS_BORDER_LEFT)
pDC->FillSolidRect(0, rect2.top, CX_BORDER, rect2.Height(), clrBtnFace);
if (dwStyle & CBRS_BORDER_TOP)
pDC->FillSolidRect(0, 0, rect.right, CY_BORDER, clrBtnFace);
// draw right and bottom
if (dwStyle & CBRS_BORDER_RIGHT)
pDC->FillSolidRect(rect1.right, rect2.top, -CX_BORDER, rect2.Height(), clrBtnShadow);
if (dwStyle & CBRS_BORDER_BOTTOM)
pDC->FillSolidRect(0, rect1.bottom, rect.right, -CY_BORDER, clrBtnShadow);
if (dwStyle & CBRS_BORDER_3D)
{
// draw left and top
if (dwStyle & CBRS_BORDER_LEFT)
pDC->FillSolidRect(1, rect2.top, CX_BORDER, rect2.Height(), clrBtnHilight);
if (dwStyle & CBRS_BORDER_TOP)
pDC->FillSolidRect(0, 1, rect.right, CY_BORDER, clrBtnHilight);
// draw right and bottom
if (dwStyle & CBRS_BORDER_RIGHT)
pDC->FillSolidRect(rect.right, rect2.top, -CX_BORDER, rect2.Height(), clrBtnFace);
if (dwStyle & CBRS_BORDER_BOTTOM)
pDC->FillSolidRect(0, rect.bottom, rect.right, -CY_BORDER, clrBtnFace);
}
if (dwStyle & CBRS_BORDER_LEFT)
rect.left += cxBorder2;
if (dwStyle & CBRS_BORDER_TOP)
rect.top += cyBorder2;
if (dwStyle & CBRS_BORDER_RIGHT)
rect.right -= cxBorder2;
if (dwStyle & CBRS_BORDER_BOTTOM)
rect.bottom -= cyBorder2;
}
int CMenuBar::GetNextOrPrevButton(int nIndex, BOOL bPrev)
{
int nCount = GetItemCount();
if (bPrev) { // <-
--nIndex;
if (nIndex < 0)
nIndex = nCount - 1;
}
else { // ->
++nIndex;
if (nIndex >= nCount)
nIndex = 0;
}
if (!(m_arrItem[nIndex]->GetStyle() & MISTYLE_TRACKABLE) ||
(m_arrItem[nIndex]->GetState() & MISTATE_HIDDEN)) {
return GetNextOrPrevButton(nIndex, bPrev);
}
return nIndex;
}
/////////////////////////////////////////////////////////////////////////////
// CMenuBar insists own bar line
void CMenuBar::EnableDockingEx(DWORD dwDockStyle)
{
// pasted from CFrameWnd implementation
static const DWORD dwDockBarMap[4][2] =
{
{ AFX_IDW_DOCKBAR_TOP, CBRS_TOP },
{ AFX_IDW_DOCKBAR_BOTTOM, CBRS_BOTTOM },
{ AFX_IDW_DOCKBAR_LEFT, CBRS_LEFT },
{ AFX_IDW_DOCKBAR_RIGHT, CBRS_RIGHT },
};
EnableDocking(dwDockStyle);
// must be CBRS_ALIGN_XXX or CBRS_FLOAT_MULTI only
ASSERT((dwDockStyle & ~(CBRS_ALIGN_ANY|CBRS_FLOAT_MULTI)) == 0);
CFrameWnd* pFrame = GetParentFrame(); ASSERT_VALID(pFrame);
//pFrame->m_pFloatingFrameClass = RUNTIME_CLASS(CMiniDockFrameWnd);
for (int i = 0; i < 4; i++)
{
if (dwDockBarMap[i][1] & dwDockStyle & CBRS_ALIGN_ANY)
{
CDockBar* pDock = (CDockBar*)pFrame->GetControlBar(dwDockBarMap[i][0]);
if (pDock == NULL)
{
pDock = new CMenuDockBar;// which wait for CMenuBar
if (!pDock->Create(pFrame,
WS_CLIPSIBLINGS|WS_CLIPCHILDREN|WS_CHILD|WS_VISIBLE |
dwDockBarMap[i][1], dwDockBarMap[i][0]))
{
AfxThrowResourceException();
}
}
}
}
}
/////////////////////////////////////////////////////////////////////////////
// CMenuBar OLE menu support
// MFC does'nt do command routing for other process server.
// ::TrackPopupMenuEx won't accept HWND of other process and
// we have to determine a message target(ole server window or not)
// as ::OleCreateMenuDescriptor do.
// This is a hard coding.
// First menu(ordinarily File menu) and WindowMenu regarded as container's own menu.
// Some shapes can't update toolbar button and statusbar pane.
HWND CMenuBar::OleMenuDescriptor(BOOL& bSend, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
CWnd* pOleWnd = GetCmdSentOleWnd();
if (pOleWnd == NULL)
return NULL;
HWND hWndSentCmd = NULL;
HMENU hMenu = NULL;
if (nMsg == WM_INITMENUPOPUP || nMsg == WM_INITMENU)
hMenu = (HMENU)wParam;
else if (nMsg == WM_MENUSELECT)
hMenu = (HMENU)lParam;
switch (nMsg) {
case WM_INITMENUPOPUP:
case WM_INITMENU:
case WM_MENUSELECT:
bSend = TRUE;
if (m_nTrackingState == popup) {
LTRACE2(_T(" now popup\n"));
if (m_bMDIApp) {
LTRACE2(_T(" this is MDI\n"));
if (m_nCurIndex == 0 || m_nCurIndex == 1 || hMenu == m_hWindowMenu) {
LTRACE2(_T(" it's container menu, send to frame\n"));
return NULL;
}
}
else {
LTRACE2(_T(" it's container menu, send to frame\n"));
if (m_nCurIndex == 0) {
return NULL;
}
}
LTRACE2(_T(" it's server menu, send to server\n"));
return pOleWnd->GetSafeHwnd();
}
break;
case WM_COMMAND:
bSend = FALSE;
if (m_bMDIApp) {
LTRACE2(_T(" this is MDI\n"));
if (_nPrevIndexForCmd == 0 || _nPrevIndexForCmd == 1 || _bWindowMenuSendCmd) {
LTRACE2(_T(" it's container menu, send to frame\n"));
return NULL;
}
}
else {
if (_nPrevIndexForCmd == 0) {
LTRACE2(_T(" it's container menu, send to frame\n"));
return NULL;
}
}
LTRACE2(_T(" it's server menu, send to server\n"));
return pOleWnd->GetSafeHwnd();
}
return NULL;// send to frame
}
CWnd* CMenuBar::GetCmdSentOleWnd()
{
// *****fixed by VORGA, thanks!*****
CWnd* pWnd = AfxGetMainWnd();
if (pWnd == NULL || !pWnd->IsFrameWnd())
return NULL;
CFrameWnd* pFrame = NULL;
if (m_bMDIApp) {
CMDIFrameWnd *pMDIFrame = STATIC_DOWNCAST(CMDIFrameWnd, pWnd);
if (pMDIFrame == NULL)
return NULL;
pFrame = pMDIFrame->GetActiveFrame();
}
else {
pFrame = STATIC_DOWNCAST(CFrameWnd, pWnd);
}
if (pFrame == NULL)
return NULL;
CDocument* pDoc = pFrame->GetActiveDocument();
if (pDoc != NULL && pDoc->IsKindOf(RUNTIME_CLASS(COleDocument))) {
COleDocument* pOleDoc = STATIC_DOWNCAST(COleDocument, pDoc);
ASSERT_VALID(pOleDoc);
COleClientItem* pClientItem = pOleDoc->GetInPlaceActiveItem(pFrame);
CWnd* pWnd = (pClientItem == NULL) ? NULL : pClientItem->GetInPlaceWindow();
if (pWnd != NULL) {
// TCHAR str[256];
// ::GetClassName(pWnd->GetSafeHwnd(), str, 256);
// LTRACE2(_T(" server wnd : %s\n"), str);
return pWnd;
}
}
return NULL;
}
/////////////////////////////////////////////////////////////////////////////
// CMDIClientHook
CMDIClientHook::CMDIClientHook()
{
m_pMenuBar = NULL;
}
BOOL CMDIClientHook::Install(CMenuBar* pMenuBar, HWND hWndToHook)
{
ASSERT_VALID(pMenuBar);
ASSERT(m_pMenuBar == NULL);
m_pMenuBar = pMenuBar;
return HookWindow(hWndToHook);
}
CMDIClientHook::~CMDIClientHook()
{
}
LRESULT CMDIClientHook::WindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam)
{
ASSERT_VALID(m_pMenuBar);
switch (nMsg) {
case WM_MDISETMENU: // only sent to MDI client window
// Setting new frame/window menu: bypass MDI. wParam is new menu.
if (wParam) {
//LTRACE(_T("CMenuBar::WM_MDISETMENU 0x%04x\n"), 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(_T("CMenuBar::WM_MDIREFRESHMENU\n"));
return 0;
// case WM_PAINT:
//LTRACE(_T("CMenuBar:WM_PAINT\n"));
// If you use no Doc-View project, when child window maximized,
// WM_PAINT never sent! so this trick never do.
// So this code moved to OnUpdateCmdUI.
// 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->CheckActiveChildWndMaximized();
// break;
}
return CSubclassWnd::WindowProc(nMsg, wParam, lParam);
}
/////////////////////////////////////////////////////////////////////////////
// CMainFrameHook
CMainFrameHook::CMainFrameHook()
{
m_pMenuBar = NULL;
}
BOOL CMainFrameHook::Install(CMenuBar* pMenuBar, HWND hWndToHook)
{
ASSERT_VALID(pMenuBar);
ASSERT(m_pMenuBar == NULL);
m_pMenuBar = pMenuBar;
return HookWindow(hWndToHook);
}
CMainFrameHook::~CMainFrameHook()
{
}
LRESULT CMainFrameHook::WindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam)
{
ASSERT_VALID(m_pMenuBar);
// be care for other windows(MainFrame) hooking
// possible called when already this wnd destroyed (WM_NCACTIVATE is)
if (!::IsWindow(m_pMenuBar->m_hWnd)) {
return CSubclassWnd::WindowProc(nMsg, wParam, lParam);
}
BOOL bSend = FALSE;
if (HWND hWndServer = m_pMenuBar->OleMenuDescriptor(bSend, nMsg, wParam, lParam)) {
// OLE wnd will handle message
if (bSend)
return ::SendMessage(hWndServer, nMsg, wParam, lParam);
else
return ::PostMessage(hWndServer, nMsg, wParam, lParam);
}
switch (nMsg) {
case WM_MENUSELECT:
m_pMenuBar->OnMenuSelect((HMENU)lParam, (UINT)LOWORD(wParam));
break;
case WM_INITMENUPOPUP:
if (!HIWORD(lParam) && (HMENU)wParam == m_pMenuBar->m_hWindowMenu)
m_pMenuBar->OnInitMenuPopup(CMenu::FromHandle((HMENU)wParam),
LOWORD(lParam), (BOOL)HIWORD(lParam));
break;
case WM_NCACTIVATE:
m_pMenuBar->OnFrameNcActivate((BOOL)wParam);
break;
case WM_SYSCOLORCHANGE:
case WM_SETTINGCHANGE:
LTRACE(_T("CMenuBar::WM_SETTINGCHANGE\n"));
// It's enough to reinitialize common resources once.
m_pMenuBar->OnSettingChange(wParam, lParam);
break;
}
if (nMsg == CMenuBar::WM_GETMENU)
return (LRESULT)m_pMenuBar->m_hMenu;
return CSubclassWnd::WindowProc(nMsg, wParam, lParam);
}
//////////////////////////////////////////////////////////////////////
// CMenuItem interface
CMenuItem::CMenuItem()
{
m_fsStyle = 0;
m_fsState = 0;
m_rcItem.SetRectEmpty();
m_sizeHorz = CSize(0, 0);
m_cAccessKey = 0;
}
void CMenuItem::ModifyState(BYTE fsRemove, BYTE fsAdd)
{
m_fsState = (m_fsState & ~fsRemove) | fsAdd;
}
CSize CMenuItem::GetHorizontalSize() const
{
if (m_fsState & MISTATE_HIDDEN)
return CSize(0, 0);
else
return m_sizeHorz;
}
//////////////////////////////////////////////////////////////////////
// CMenuButton class
CMenuButton::CMenuButton(HMENU hMenu, int nIndex)
{
ASSERT(::IsMenu(hMenu));
ASSERT(nIndex >= 0);
m_fsStyle |= (MISTYLE_TRACKABLE | MISTYLE_WRAPPABLE);
InitButtonStringAndSubMenuHandle(hMenu, nIndex);
InitHorizontalButtonSize();
InitAccessKeyAndVerticalLinePoint();
}
void CMenuButton::InitButtonStringAndSubMenuHandle(HMENU hMenu, int nIndex)
{
// get menu button Text
TCHAR szText[256];
MENUITEMINFO info; ::memset(&info, 0, sizeof(MENUITEMINFO));
info.cbSize = sizeof(MENUITEMINFO);
info.fMask = MIIM_ID | MIIM_TYPE;
info.dwTypeData = szText;
info.cch = sizeof(szText);
::GetMenuItemInfo(hMenu, nIndex, TRUE, &info);
m_strBtn = CString(szText);
m_hSubMenu = ::GetSubMenu(hMenu, nIndex);
if (!m_hSubMenu) {
m_nID = ::GetMenuItemID(hMenu, nIndex);
ASSERT(m_nID != -1);
}
else {
m_nID = -1;
}
}
void CMenuButton::InitHorizontalButtonSize()
{
// get menu button Text size
ASSERT(m_strBtn.IsEmpty() == FALSE);
m_sizeHorz.cx = _CalcTextWidth(m_strBtn) + CXTEXTMARGIN*2;
m_sizeHorz.cy = _cyHorzFont + _cyTextMargin*2;
}
void CMenuButton::InitAccessKeyAndVerticalLinePoint()
{
int nIndex = m_strBtn.Find('&');
if (nIndex + 1 == m_strBtn.GetLength()) {
TRACE(_T("warning : & is bad position, access key is invalid.\n"));
m_cAccessKey = 0;
m_ptLineFrom = m_ptLineTo = CPoint(0, 0);
return;
}
m_cAccessKey = m_strBtn[nIndex + 1];// -1 + 1 = 0; it's ok
if (nIndex == -1) {
m_ptLineFrom = m_ptLineTo = CPoint(0, 0);
}
else if (nIndex == 0) {
m_ptLineFrom = CPoint(_cyTextMargin, CXTEXTMARGIN);
m_ptLineTo = CPoint(_cyTextMargin, CXTEXTMARGIN + _CalcTextWidth(m_strBtn.Left(nIndex+2)));
}
else {
m_ptLineFrom = CPoint(_cyTextMargin, CXTEXTMARGIN + _CalcTextWidth(m_strBtn.Left(nIndex)));
m_ptLineTo = CPoint(_cyTextMargin, CXTEXTMARGIN + _CalcTextWidth(m_strBtn.Left(nIndex+2)));
}
}
void CMenuButton::Layout(CPoint point, BOOL bHorz)
{
if (bHorz)
m_fsState |= MISTATE_HORZ;
else
m_fsState &= ~MISTATE_HORZ;
if (m_fsState & MISTATE_HIDDEN) {
m_rcItem.SetRectEmpty();
return;
}
if (bHorz) {
m_rcItem = CRect(point, m_sizeHorz);
}
else {
m_rcItem = CRect(point, CSize(m_sizeHorz.cy, m_sizeHorz.cx));
}
}
void CMenuButton::Update(CDC* pDC)
{
if (m_fsState & MISTATE_HIDDEN)
return;
// clean background
COLORREF clr = ::GetSysColor(COLOR_BTNFACE);
pDC->FillSolidRect(m_rcItem, clr);
if (m_fsState & MISTATE_HOT){
DrawHot(pDC);
}
else if (m_fsState & MISTATE_PRESSED){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -