📄 menubar.cpp
字号:
m_pMenuIcon->Validate(FALSE);
}
RefreshBar();
}
}
}
void CMenuBar::OnInitMenuPopup()
{
CMenu menu;
menu.Attach((HMENU)m_hWindowMenu);
// scan for first window command
int n = menu.GetMenuItemCount();
BOOL bAddSeperator = TRUE;
for (int iPos=0; iPos<n; iPos++) {
if (menu.GetMenuItemID(iPos) >= AFX_IDM_FIRST_MDICHILD) {
bAddSeperator = FALSE;
break;
}
}
// iPos is either first window item, or end if none found.
// delete everything after.
while (iPos < (int)menu.GetMenuItemCount())
menu.RemoveMenu(iPos, MF_BYPOSITION);
// get active window so I can check its menu item
ASSERT(m_hWndMDIClient);
HWND hwndActive = (HWND)::SendMessage(m_hWndMDIClient,
WM_MDIGETACTIVE, 0, NULL);
// append window names in the form "# title"
int iWin=1;
for (HWND hwnd=::GetWindow(m_hWndMDIClient, GW_CHILD);
hwnd;
hwnd = ::GetWindow(hwnd, GW_HWNDNEXT)) {
if (bAddSeperator) {
menu.InsertMenu(iPos++, MF_BYPOSITION|MF_SEPARATOR);
bAddSeperator = FALSE;
}
// build item name and add it to the menu
CString sWinName, sMenuItem;
CWnd::FromHandle(hwnd)->GetWindowText(sWinName);
sMenuItem.Format(_T("&%d %s"), iWin++, (LPCTSTR)sWinName);
menu.InsertMenu(iPos, MF_BYPOSITION,
::GetDlgCtrlID(hwnd), sMenuItem);
if (hwnd==hwndActive)
menu.CheckMenuItem(iPos, MF_BYPOSITION|MF_CHECKED);
iPos++;
}
menu.Detach();
}
void CMenuBar::OnSetMenu(HMENU hNewMenu, HMENU hWindowMenu)
{
// We can get active MDI child window on this message!
BOOL bMax;
HWND hWndChild = GetActiveChildWnd(bMax);
if (!m_hWndActiveChild || m_hWndActiveChild != hWndChild) {
// active child window changed
LTRACE(" active child window changed\n");
m_hWndActiveChild = hWndChild;
// tell MenuIcon child window has been changed
m_pMenuIcon->OnActivateChildWnd(hWndChild);
}
LTRACE("CMenuBar::OnSetMenu\n");
if (!m_hMenu || m_hMenu != hNewMenu) { // menu changed
LTRACE(" menu changed\n");
LoadMenu(hNewMenu, hWindowMenu); // set toolbar menu
GetOwner()->SetMenu(NULL); // clear frame menu
}
}
HWND CMenuBar::GetActiveChildWnd(BOOL& bMaximized)
{
if (!m_hWndMDIClient)
return NULL;
BOOL bMax = FALSE;
HWND hWnd = (HWND)::SendMessage(m_hWndMDIClient,
WM_MDIGETACTIVE, 0, (LPARAM)&bMax);
bMaximized = bMax;
return hWnd;
}
CMenuItem::CMenuItem()
{
m_itemState = none;
m_rcItem = CRect(0, 0, 0, 0);
m_sizeHorz = CSize(0, 0);
m_bHorz = TRUE;
m_bWrapped = FALSE;
}
CMenuItem::~CMenuItem()
{
}
CPoint CMenuItem::ComputeMenuTrackPoint(CWnd* pWnd, HMENU hSubMenu, TPMPARAMS& tpm, CFont* pFont)
{
ASSERT_VALID(pWnd);
ASSERT_VALID(pFont);
ASSERT(::IsMenu(hSubMenu));
tpm.cbSize = sizeof(tpm);
CRect& rcExclude = (CRect&)tpm.rcExclude;
CWnd::GetDesktopWindow()->GetWindowRect(&rcExclude);
CPoint pt;
CRect rcItem = m_rcItem;
pWnd->ClientToScreen(&rcItem);
// if (hSubMenu == NULL) // it's possible no sub menu
// return CPoint();
if (m_bHorz) { // horizontal
int nCount = ::GetMenuItemCount(hSubMenu);
ASSERT(nCount != -1);
int cyPopup = nCount * rcItem.Height(); // I want it be not owner drawn but ordinary menu..
if (rcItem.bottom + cyPopup > rcExclude.bottom) {
pt = CPoint(rcItem.left, rcItem.top); // over Screen
rcExclude.top = rcItem.top;
}
else {
pt = CPoint(rcItem.left, rcItem.bottom);
}
pt += CPoint(-1, 1); // precisely same as DevStudio
}
else { // vertical
// we never get the width of popup up menu, but I will try
int nCount = ::GetMenuItemCount(hSubMenu);
ASSERT(nCount != -1);
int cxPopup = 0;
CWindowDC dc(NULL);
CFont* pOldFont = dc.SelectObject(pFont);
for (int i = 0; i < nCount; ++i) {
char szName[256];
MENUITEMINFO info;
::ZeroMemory(&info, sizeof(MENUITEMINFO));
info.cbSize = sizeof(MENUITEMINFO);
info.fMask = MIIM_ID | MIIM_TYPE;
info.dwTypeData = szName;
info.cch = sizeof(szName);
::GetMenuItemInfo(hSubMenu, i, TRUE, &info);
CString strItem(szName);
CRect rcText(0, 0, 0, 0);
dc.DrawText(strItem, &rcText,
DT_SINGLELINE | DT_VCENTER | DT_CALCRECT | DT_NOPREFIX);
int cxOffset = ::GetSystemMetrics(SM_CXMENUCHECK) * 2;
cxPopup = max(rcText.Width() + 4*2 + CXGAP*2 + cxOffset, cxPopup);
}
dc.SelectObject(pOldFont);
if (rcItem.right + cxPopup > rcExclude.right) { // over right-side
pt = CPoint(rcItem.left, rcItem.top);
rcExclude.left = rcItem.left;
}
else {
pt = CPoint(rcItem.right, rcItem.top);
rcExclude.right = rcItem.right;
}
pt += CPoint(1, -1); // precisely same as DevStudio
}
return pt;
}
CMenuIcon::CMenuIcon(CWnd* pWnd)
{
m_hDocIcon = NULL;//hIcon;
m_sizeHorz = CSize(::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON));
m_bValid = FALSE;
m_hSysMenu = NULL;//::GetSystemMenu(pWnd->GetSafeHwnd(), FALSE);
}
CMenuIcon::~CMenuIcon()
{
}
void CMenuIcon::Update(CDC* pDC)
{
ASSERT(m_hDocIcon);
ASSERT(m_bValid);
::DrawIconEx(pDC->m_hDC, m_rcItem.left, m_rcItem.top, m_hDocIcon,
m_sizeHorz.cx, m_sizeHorz.cy, 0, NULL, DI_NORMAL);
}
void CMenuIcon::TrackPopup(CWnd* pWnd)
{
ASSERT(m_hDocIcon);
ASSERT(m_bValid);
ASSERT(::IsMenu(m_hSysMenu));
NONCLIENTMETRICS info;
info.cbSize = sizeof(info);
::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0);
CFont fontSys;
if (!fontSys.CreateFontIndirect(&info.lfMenuFont))
return;
TPMPARAMS tpm;
CPoint pt = ComputeMenuTrackPoint(pWnd, m_hSysMenu, tpm, &fontSys);
::TrackPopupMenuEx(m_hSysMenu,
TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_VERTICAL,
pt.x, pt.y, pWnd->GetOwner()->GetSafeHwnd(), &tpm);
}
void CMenuIcon::Layout(CPoint point, BOOL bHorz)
{
ASSERT(m_bValid);
m_bHorz = bHorz;
m_rcItem = CRect(point, m_sizeHorz);
}
void CMenuIcon::OnActivateChildWnd(HWND hWndChild)
{
TRACE0("CMenuIcon::OnActivateChildWnd\n");
ASSERT(::IsWindow(hWndChild));
m_hSysMenu = ::GetSystemMenu(hWndChild, FALSE);
ASSERT(::IsMenu(m_hSysMenu));
m_hDocIcon = (HICON)GetClassLong(hWndChild, GCL_HICONSM);
}
BOOL CMenuControl::OnMouseMsg(UINT msg, UINT nFlags, CPoint pt)
{
if (!IsValid())
return FALSE;
if (msg == WM_LBUTTONDOWN) {
m_nTracking = HitTest(pt);
if (m_nTracking >= 0) {
CClientDC dc(m_pBar);
DrawControl(&dc, m_nTracking, TRUE);
m_bDown = TRUE;
m_pBar->SetCapture(); // grab mouse input
return TRUE;
}
}
else if ((msg == WM_MOUSEMOVE) && m_nTracking >= 0) {
// mouse moved, and I am tracking: possibly draw button up/down
BOOL bOldDown = m_bDown;
m_bDown = m_arrCaption[m_nTracking].PtInRect(pt);
if (bOldDown != m_bDown) {
// up/down state changed: need to redraw button
CClientDC dc(m_pBar);
DrawControl(&dc, m_nTracking, m_bDown);
}
return TRUE; // handled
}
else if (msg == WM_LBUTTONUP && m_nTracking >= 0) {
// user released the mouse and I am tracking: do button command
ReleaseCapture(); // let go the mouse
if (m_bDown)
{
// if button was down when released: draw button up, and do system cmd
CClientDC dc(m_pBar);
DrawControl(&dc, m_nTracking, FALSE);
CFrameWnd* pFrame = m_pBar->GetTopLevelFrame()->GetActiveFrame();
ASSERT_VALID(pFrame);
static syscmd[3] =
{ /*SC_MOUSEMENU,*/ SC_CLOSE, SC_RESTORE, SC_MINIMIZE };
//pFrame->SendMessage(WM_SYSCOMMAND, syscmd[m_nTracking]);
pFrame->PostMessage(WM_SYSCOMMAND, syscmd[m_nTracking]);//libin .because
//after executing sendMessage,The CMenuControl object is destroyed.However,
//the following line still accesses the member of destroyed object:m_nTracking = -1;array overflow !
}
m_nTracking = -1; // stop tracking
return TRUE; // handled (eat)
}
return FALSE;
}
int CMenuControl::HitTest(CPoint point)
{
for (int i = 0; i < 3; ++i) {
if (m_arrCaption[i].PtInRect(point))
return i;
}
return -1;
}
void CMenuControl::DrawControl(CDC* pDC, int nIndex, BOOL bPressed)
{
// draw frame controls
CRect& rc = m_arrCaption[nIndex];
static UINT dfcs[3] = { DFCS_CAPTIONCLOSE, DFCS_CAPTIONRESTORE, DFCS_CAPTIONMIN };
UINT uState = dfcs[nIndex];
if (bPressed)
uState |= DFCS_PUSHED;
pDC->DrawFrameControl(rc, DFC_CAPTION, uState);
}
void CMenuControl::ForceDrawControl(CDC * pDC)
{
if (!IsValid())
return;
for (int i = 0; i < 3; ++i) {
DrawControl(pDC, i, FALSE);
}
}
namespace {
const int CXTEXTMARGIN = 5;
int CYTEXTMARGIN = 0;
const int CYTEXTMARGINMIN = 2;
CFont fontHorz, fontVert;
// const int CXGAP = 3;
}// anonymouse namespace
CMenuButton::CMenuButton(HMENU hMenu, int nIndex)
{
ASSERT(hMenu);
InitButtonStringAndSubMenuHandle(hMenu, nIndex);
InitHorizontalButtonSize();
InitAccessKeyAndVerticalLinePoint();
}
CMenuButton::~CMenuButton()
{
}
BOOL CMenuButton::InitCommonResource()
{
// clean up
fontHorz.DeleteObject();
fontVert.DeleteObject();
// create fonts
NONCLIENTMETRICS info;
info.cbSize = sizeof(info);
::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0);
if (!fontHorz.CreateFontIndirect(&info.lfMenuFont))
return FALSE;
info.lfMenuFont.lfEscapement = -900;
info.lfMenuFont.lfOrientation = -900;
strcpy (info.lfMenuFont.lfFaceName, _T("Arial")); //Libin
if (!fontVert.CreateFontIndirect(&info.lfMenuFont))
return FALSE;
// get font height
LOGFONT logfont;
fontHorz.GetLogFont(&logfont);
int cyFont = abs(logfont.lfHeight);
// calc Y text margin
int cyText = cyFont + CYTEXTMARGINMIN*2;
int cyMenu = ::GetSystemMetrics(SM_CYMENU);
if (cyMenu > cyText) {
CYTEXTMARGIN = (cyMenu - cyFont)/2;
}
else {
CYTEXTMARGIN = CYTEXTMARGINMIN;
}
return TRUE;
}
void CMenuButton::InitButtonStringAndSubMenuHandle(HMENU hMenu, int nIndex)
{
// get menu button Text
char szText[256];
MENUITEMINFO info; ::ZeroMemory(&info, 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);
}
void CMenuButton::InitHorizontalButtonSize()
{
// get menu button Text size
ASSERT(m_strBtn.IsEmpty() == FALSE);
CWindowDC dc(NULL);
CRect rcText(0, 0, 0, 0);
CFont* pOldFont = dc.SelectObject(&fontHorz);
dc.DrawText(m_strBtn, &rcText, DT_SINGLELINE | DT_CALCRECT);
dc.SelectObject(pOldFont);
m_sizeHorz.cx = rcText.Width() + CXTEXTMARGIN*2;
LOGFONT logfont;
fontHorz.GetLogFont(&logfont);
int cyFont = abs(logfont.lfHeight);
m_sizeHorz.cy = cyFont + CYTEXTMARGIN*2;
}
void CMenuButton::InitAccessKeyAndVerticalLinePoint()
{
int nIndex = m_strBtn.Find('&');
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) {
CRect rcTo;
CWindowDC dc(NULL);
CFont* pOldFont = dc.SelectObject(&fontHorz);
dc.DrawText(m_strBtn.Left(nIndex+2), &rcTo, DT_SINGLELINE | DT_CALCRECT);
dc.SelectObject(pOldFont);
m_ptLineFrom = CPoint(CYTEXTMARGIN, CXTEXTMARGIN);
m_ptLineTo = CPoint(CYTEXTMARGIN, CXTEXTMARGIN + rcTo.Width());
}
else {
CRect rcFrom, rcTo;
CWindowDC dc(NULL);
CFont* pOldFont = dc.SelectObject(&fontHorz);
dc.DrawText(m_strBtn.Left(nIndex), &rcFrom, DT_SINGLELINE | DT_CALCRECT);
dc.DrawText(m_strBtn.Left(nIndex+2), &rcTo, DT_SINGLELINE | DT_CALCRECT);
dc.SelectObject(pOldFont);
m_ptLineFrom = CPoint(CYTEXTMARGIN, CXTEXTMARGIN + rcFrom.Width());
m_ptLineTo = CPoint(CYTEXTMARGIN, CXTEXTMARGIN + rcTo.Width());
}
}
void CMenuButton::Layout(CPoint point, BOOL bHorz)
{
if (bHorz == TRUE) {
m_rcItem = CRect(point, m_sizeHorz);
}
else {
m_rcItem = CRect(point, CSize(m_sizeHorz.cy, m_sizeHorz.cx));
}
m_bHorz = bHorz;
}
void CMenuButton::Update(CDC* pDC)
{
// clean background
COLORREF clr = ::GetSysColor(COLOR_BTNFACE);
pDC->FillSolidRect(m_rcItem, clr);
switch (m_itemState) {
case hot:
DrawHot(pDC);
break;
case select:
DrawSelect(pDC);
break;
case none:
DrawNone(pDC);
break;
default:
ASSERT(TRUE);
}
}
void CMenuButton::TrackPopup(CWnd* pWnd)
{
TPMPARAMS tpm;
CPoint pt = ComputeMenuTrackPoint(pWnd, m_hSubMenu, tpm, &fontHorz);
::TrackPopupMenuEx(m_hSubMenu,
TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_VERTICAL,
pt.x, pt.y, pWnd->GetOwner()->GetSafeHwnd(), &tpm);
}
void CMenuButton::DrawHorzText(CDC* pDC, CPoint ptOffset)
{
CRect rcBtn = m_rcItem;
pDC->SetBkMode(TRANSPARENT);
CFont* pOldFont = pDC->SelectObject(&fontHorz);
// I know precise text size
//rcBtn.DeflateRect(CXTEXTMARGIN, CYTEXTMARGIN);
rcBtn.DeflateRect(CXTEXTMARGIN, CYTEXTMARGIN-1); //libin.
pDC->DrawText(m_strBtn, rcBtn + ptOffset,
DT_SINGLELINE);// | DT_CENTER | DT_VCENTER); no need
pDC->SelectObject(pOldFont);
}
void CMenuButton::DrawVertText(CDC* pDC, CPoint ptOffset)
{
CRect rcBtn = m_rcItem;
int nLength = m_strBtn.GetLength();
int nIndex = m_strBtn.Find('&');
CString strBtn = m_strBtn.Left(nIndex) + m_strBtn.Right(nLength - (nIndex+1));
pDC->SetBkMode(TRANSPARENT);
CFont* pOldFont = pDC->SelectObject(&fontVert);
// I must know precise text size
CRect rcString = CRect(
CPoint(rcBtn.right - CYTEXTMARGIN, rcBtn.top + CXTEXTMARGIN), m_sizeHorz);
pDC->DrawText(strBtn, rcString + ptOffset,
DT_SINGLELINE | DT_NOCLIP | DT_NOPREFIX); // don't forget DT_NOCLIP
pDC->SelectObject(pOldFont);
// DrawText is poor, so we have to draw vertical line by ourselves
pDC->MoveTo(rcBtn.TopLeft() + m_ptLineFrom + ptOffset);
pDC->LineTo(rcBtn.TopLeft() + m_ptLineTo + ptOffset);
}
void CMenuButton::DrawHot(CDC* pDC)
{
if (m_bHorz) {
// draw down button
pDC->DrawEdge(m_rcItem, BDR_RAISEDINNER, BF_RECT);
DrawHorzText(pDC);
}
else {
pDC->DrawEdge(m_rcItem, BDR_RAISEDINNER, BF_RECT);
DrawVertText(pDC);
}
}
void CMenuButton::DrawSelect(CDC* pDC)
{
if (m_bHorz) {
// draw pressed button
pDC->DrawEdge(m_rcItem, BDR_SUNKENOUTER, BF_RECT);
DrawHorzText(pDC, CPoint(1, 1));
}
else {
pDC->DrawEdge(m_rcItem, BDR_SUNKENOUTER, BF_RECT);
DrawVertText(pDC, CPoint(1, 1));
}
}
void CMenuButton::DrawNone(CDC* pDC)
{
if (m_bHorz) {
DrawHorzText(pDC);
}
else {
DrawVertText(pDC);
}
}
int CMenuBar::OnActivateFrame(int nCmdShow)
{
CFrameWnd* pFrame = GetParentFrame();
ASSERT_VALID(pFrame);
if (pFrame->GetMenu() != NULL) {
LTRACE(" has menu\n");
pFrame->SetMenu(NULL);
}
m_nCmdShow = nCmdShow;
return SW_HIDE;
}
BOOL CMenuBar::OnEraseBkgnd(CDC* pDC)
{
// TODO: Add your message handler code here and/or call default
CRect rect;
GetClientRect(&rect);
return CControlBar::OnEraseBkgnd(pDC);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -