📄 menubar.cpp
字号:
////////////////////////////////////////////////////////////////
// Copyright 1998 Paul DiLascia
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
//
// CMenuBar implements menu bar for MFC. See MenuBar.h for how
// to use, and also the MBTest sample application.
//
#include "StdAfx.h"
#include "MenuBar.h"
#include "ToolMenu.h"
#include "GreenBrowser.h"
#include "function.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
//##############################################################
#define countof(x) (sizeof(x)/sizeof(x[0]))
//##############################################################
BOOL g_bNoHook = FALSE;
//give WM_NCHITTEST a chance to handle before WM_MOUSEMOVE
int g_nDelay = 10;
//##############################################################
extern BOOL g_bRTab;
//##############################################################
IMPLEMENT_DYNAMIC(CMenuBar, CToolBar)
BEGIN_MESSAGE_MAP(CMenuBar, CToolBar)
ON_WM_CREATE()
ON_WM_LBUTTONDOWN()
ON_WM_MOUSEMOVE()
ON_UPDATE_COMMAND_UI_RANGE(0, 256, OnUpdateMenuButton)
ON_WM_NCHITTEST()
END_MESSAGE_MAP()
CMenuBar::CMenuBar()
{
m_iTrackingState = TRACK_NONE; // initial state: not tracking
m_iPopupTracking = m_iNewPopup = -1; // invalid
m_hmenu = NULL;
m_nMenuItems = 0;
//
g_bNoHook = FALSE;
g_nDelay = 10;
}
CMenuBar::~CMenuBar()
{
DestroyMenuData(m_hmenu,0);
}
//////////////////
// Menu bar was created: install hook into owner window
//
int CMenuBar::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CToolBar::OnCreate(lpCreateStruct)==-1)
return -1;
UpdateFont();
return 0; // OK
}
//////////////////
// Load a different menu. The HMENU must not belong to any CMenu,
// and you must free it when you're done. Returns old menu.
//
HMENU CMenuBar::LoadMenu(HMENU hmenu)
{
UINT iPrevID=(UINT)-1;
ASSERT(::IsMenu(hmenu));
ASSERT_VALID(this);
HMENU hOldMenu = m_hmenu;
m_hmenu = hmenu;
// delete existing buttons
int nCount = GetToolBarCtrl().GetButtonCount();
while (nCount--) {
VERIFY(GetToolBarCtrl().DeleteButton(0));
}
GetToolBarCtrl().SetImageList(NULL);
DWORD dwStyle = GetStyle();
BOOL bModifyStyle = ModifyStyle(0, TBSTYLE_FLAT|TBSTYLE_TRANSPARENT);
// add text buttons
UINT nMenuItems = hmenu ? ::GetMenuItemCount(hmenu) : 0;
for (UINT i=0; i < nMenuItems; i++)
{
TCHAR name[64];
memset(name, 0, sizeof(name)); // guarantees double-0 at end
if (theApp.m_bUseLngFile)
{
char num[10];
sprintf(num,"X%d",i);
if (_GetPrivateProfileString("MenuMain", num, NULL, name, countof(name)-1, theApp.m_strLngFile)==FALSE)
::GetMenuString(hmenu, i, name, countof(name)-1, MF_BYPOSITION);
}
else
::GetMenuString(hmenu, i, name, countof(name)-1, MF_BYPOSITION);
//
TBBUTTON tbb;
memset(&tbb, 0, sizeof(tbb));
tbb.idCommand = ::GetMenuItemID(hmenu, i);
// Because the toolbar is too brain-damaged to know if it already has
// a string, and is also too brain-dead to even let you delete strings,
// I have to determine if each string has been added already. Otherwise
// in a MDI app, as the menus are repeatedly switched between doc and
// no-doc menus, I will keep adding strings until somebody runs out of
// memory. Sheesh!
//
int iString = -1;
for (int j=0; j<m_arStrings.GetSize(); j++) {
if (m_arStrings[j] == name) {
iString = j; // found it
break;
}
}
if (iString <0) {
// string not found: add it
iString = GetToolBarCtrl().AddStrings(name);
m_arStrings.SetAtGrow(iString, name);
}
tbb.iString = iString;
tbb.fsState = TBSTATE_ENABLED;
tbb.fsStyle = TBSTYLE_AUTOSIZE;
tbb.iBitmap = -1;
tbb.idCommand = i;
VERIFY(GetToolBarCtrl().AddButtons(1, &tbb));
}
if (bModifyStyle)
SetWindowLong(m_hWnd, GWL_STYLE, dwStyle);
if (hmenu) {
GetToolBarCtrl().AutoSize();// size buttons
m_nMenuItems = GetToolBarCtrl().GetButtonCount();
}
return hOldMenu;
}
//////////////////
// Load menu from resource
//
HMENU CMenuBar::LoadMenu(LPCSTR lpszMenuName)
{
return LoadMenu(::LoadMenu(AfxGetResourceHandle(), lpszMenuName));
}
//////////////////
// Set menu bar font from current system menu font
//
void CMenuBar::UpdateFont()
{
static CFont font;
NONCLIENTMETRICS info;
info.cbSize = sizeof(info);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0);
if ((HFONT)font)
font.DeleteObject();
VERIFY(font.CreateFontIndirect(&info.lfMenuFont));
SetFont(&font);
}
//////////////////
// The reason for having this is so MFC won't automatically disable
// the menu buttons. Assumes < 256 top-level menu items. The ID of
// the ith menu button is i. IOW, the index and ID are the same.
//
void CMenuBar::OnUpdateMenuButton(CCmdUI* pCmdUI)
{
ASSERT_VALID(this);
if (IsValidButton(pCmdUI->m_nID))
pCmdUI->Enable(TRUE);
}
//////////////////
// Set tracking state: none, button, or popup
//
void CMenuBar::SetTrackingState(TRACKINGSTATE iState, int iButton)
{
ASSERT_VALID(this);
if (iState != m_iTrackingState)
{
if (iState == TRACK_NONE)
iButton = -1;
GetToolBarCtrl().SetHotItem(iButton);// could be none (-1)
if (iState==TRACK_POPUP)
{
// set related state stuff
m_bEscapeWasPressed = FALSE; // assume Esc key not pressed
m_bProcessRightArrow = // assume left/right arrow..
m_bProcessLeftArrow = TRUE; // ..will move to prev/next popup
m_iPopupTracking = iButton; // which popup I'm tracking
}
m_iTrackingState = iState;
}
}
//////////////////
// Toggle state from home state to button-tracking and back
//
void CMenuBar::ToggleTrackButtonMode()
{
ASSERT_VALID(this);
if (m_iTrackingState == TRACK_NONE || m_iTrackingState == TRACK_BUTTON)
{
SetTrackingState(m_iTrackingState == TRACK_NONE ?
TRACK_BUTTON : TRACK_NONE, 0);
}
}
//////////////////
// Get button index before/after a given button
//
int CMenuBar::GetNextOrPrevButton(int iButton, BOOL bPrev)
{
ASSERT_VALID(this);
if (bPrev)
{
iButton--;
if (iButton <0)
iButton = m_nMenuItems - 1;//GetToolBarCtrl().GetButtonCount()
}
else
{
iButton++;
if (iButton >= m_nMenuItems)//GetToolBarCtrl().GetButtonCount()
iButton = 0;
}
return iButton;
}
/////////////////
// This is to correct a bug in the system toolbar control: TB_HITTEST only
// looks at the buttons, not the size of the window. So it returns a button
// hit even if that button is totally outside the size of the window!
//
int CMenuBar::HitTest(CPoint p) const
{
int iHit = GetToolBarCtrl().HitTest(&p);
if (iHit>0)
{
CRect rc;
GetClientRect(&rc);
if (!rc.PtInRect(p)) // if point is outside window
iHit = -1; // can't be a hit!
}
return iHit;
}
//////////////////
// Handle mouse click: if clicked on button, press it
// and go into main menu loop.
//
void CMenuBar::OnLButtonDown(UINT nFlags, CPoint pt)
{
try{
ASSERT_VALID(this);
int iButton = HitTest(pt);
if (iButton >= 0 && iButton<m_nMenuItems) //GetToolBarCtrl().GetButtonCount() if mouse is over a button:
TrackPopup(iButton); // track it
else // otherwise:
CToolBar::OnLButtonDown(nFlags, pt); // pass it on...
}catch(...){}
}
//////////////////
// Handle mouse movement
//
void CMenuBar::OnMouseMove(UINT nFlags, CPoint pt)
{
ASSERT_VALID(this);
if (m_iTrackingState==TRACK_BUTTON)
{
// In button-tracking state, ignore mouse-over to non-button area.
// Normally, the toolbar would de-select the hot item in this case.
//
// Only change the hot item if the mouse has actually moved.
// This is necessary to avoid a bug where the user moves to a different
// button from the one the mouse is over, and presses arrow-down to get
// the menu, then Esc to cancel it. Without this code, the button will
// jump to wherever the mouse is--not right.
int iHot = HitTest(pt);
if (IsValidButton(iHot) && pt != m_ptMouse)
GetToolBarCtrl().SetHotItem(iHot);
return;// don't let toolbar get it
}
m_ptMouse = pt; // remember point
CToolBar::OnMouseMove(nFlags, pt);
}
/////////////////
// When user selects a new menu item, note whether it has a submenu
// and/or parent menu, so I know whether right/left arrow should
// move to the next popup.
//
void CMenuBar::OnMenuSelect(HMENU hmenu, UINT iItem)
{
if (m_iTrackingState > 0)
{
// process right-arrow iff item is NOT a submenu
m_bProcessRightArrow = (::GetSubMenu(hmenu, iItem) == NULL);
// process left-arrow iff curent menu is one I'm tracking
//m_bProcessLeftArrow = hmenu==m_hMenuTracking;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -