?? menubar.cpp
字號:
// MenuBar.cpp : implementation file
// CMenuBar version 2.12
//類名:CMenuBar
//功能:使菜單顯示為Office2000風格
//修改人:徐景周(jingzhou_xu@163.net)
//組織:未來工作室(Future Studio)
//日期:2001.12.1
#include "stdafx.h"
#include "..\resource.h" //上一級目錄中
#include "MenuBar.h"
#include "DocTplEx.h"
#include "MDIFrmEx.h"
#include "SubClass.h"
#include <afxole.h>
#include "WinAppEx.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#ifdef _DEBUG
const BOOL bTraceOn = FALSE;
#define LTRACE if (bTraceOn) TRACE
const BOOL bTraceOn2 = TRUE;
#define LTRACE2 if (bTraceOn2) TRACE
#else
#define LTRACE
#define LTRACE2
#endif
//////////////////////////////////////////////////////////////////////
// I've found string resource of "More windows" in "user.exe".
// But I can't load it, so please replace a following with your language.
static const TCHAR _szMoreWindows[] = _T("&More windows...");
//////////////////////////////////////////////////////////////////////
// used for OLE menu (easy fix)
static BOOL _bWindowMenuSendCmd = FALSE;
static int _nPrevIndexForCmd = -1;
//////////////////////////////////////////////////////////////////////
// hook
static CMenuBar* g_pMenuBar = NULL;
static HHOOK g_hMsgHook = NULL;
// message
const UINT CMenuBar::WM_GETMENU = ::RegisterWindowMessage(_T("CMenuBar::WM_GETMENU"));
const UINT MB_SET_MENU_NULL = ::RegisterWindowMessage(_T("CMenuBar::MB_SET_MENU_NULL"));
const int cxBorder2 = ::GetSystemMetrics(SM_CXBORDER)*2;
const int cyBorder2 = ::GetSystemMetrics(SM_CYBORDER)*2;
// common resources
static CFont _fontHorzMenu, _fontVertMenu;
static int _cyHorzFont, _cyMenuOnBar, _cyTextMargin;
const int CXTEXTMARGIN = 5;
static BOOL _InitCommonResources(BOOL bForce = FALSE)
{
if (bForce == FALSE && _fontHorzMenu.m_hObject != NULL)
return TRUE;// no need to reinitialize
// clean up
_fontHorzMenu.DeleteObject();
_fontVertMenu.DeleteObject();
// create fonts
NONCLIENTMETRICS info; info.cbSize = sizeof(info);
::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0);
if (!_fontHorzMenu.CreateFontIndirect(&info.lfMenuFont))
return FALSE;
// create vertical font
info.lfMenuFont.lfEscapement = -900;
info.lfMenuFont.lfOrientation = -900;
if (!_fontVertMenu.CreateFontIndirect(&info.lfMenuFont))
return FALSE;
// get font height
_cyHorzFont = abs(info.lfMenuFont.lfHeight);
// calc Y text margin
_cyMenuOnBar = info.iMenuHeight;
_cyMenuOnBar = max(_cyMenuOnBar, ::GetSystemMetrics(SM_CYSMICON));
_cyTextMargin = (_cyMenuOnBar - _cyHorzFont) / 2;
return TRUE;
}
// I wanted to control popup point, but I've fount we can never get popupmenu rect before popup.
// even if not owner draw menu...
static CPoint _ComputeMenuTrackPoint(const CRect& rcItem, DWORD dwStyle, UINT& fuFlags, TPMPARAMS& tpm)
{
fuFlags = TPM_LEFTBUTTON | TPM_LEFTALIGN | TPM_HORIZONTAL;
tpm.cbSize = sizeof(tpm);
CPoint pt;
CRect& rcExclude = (CRect&)tpm.rcExclude;
CWnd::GetDesktopWindow()->GetWindowRect(&rcExclude);
CRect rcFrame;
AfxGetMainWnd()->GetWindowRect(&rcFrame);
switch (dwStyle & CBRS_ALIGN_ANY) {
case CBRS_ALIGN_RIGHT:
case CBRS_ALIGN_LEFT:
pt = CPoint(rcItem.right+1, rcItem.top-1);
// to avoid strange menu flip, won't do : [rcExclude.right = rcItem.right+1;]
// I want to use : fuFlags |= TPM_HORNEGANIMATION;
break;
default: // case CBRS_ALIGN_TOP:
pt = CPoint(rcItem.left-1, rcItem.bottom);
rcExclude.bottom = rcItem.bottom+1;// <- insead of [fuFlags |= TPM_VERPOSANIMATION;]
break;
}
return pt;
}
static int _CalcTextWidth(const CString& strText)
{
CWindowDC dc(NULL);
CRect rcText(0, 0, 0, 0);
CFont* pOldFont = dc.SelectObject(&_fontHorzMenu);
dc.DrawText(strText, &rcText, DT_SINGLELINE | DT_CALCRECT);
dc.SelectObject(pOldFont);
return rcText.Width();
}
// grippers pasted from MFC6
#define CX_GRIPPER 3
#define CY_GRIPPER 3
#define CX_BORDER_GRIPPER 2
#define CY_BORDER_GRIPPER 2
#define CX_GRIPPER_ALL CX_GRIPPER + CX_BORDER_GRIPPER*2
#define CY_GRIPPER_ALL CY_GRIPPER + CY_BORDER_GRIPPER*2
/////////////////////////////////////////////////////////////////////////////
// CMenuBar
BEGIN_MESSAGE_MAP(CMenuBar, CControlBar)
//{{AFX_MSG_MAP(CMenuBar)
ON_WM_LBUTTONDOWN()
ON_WM_MOUSEMOVE()
ON_WM_CREATE()
ON_WM_LBUTTONUP()
ON_WM_TIMER()
ON_WM_DESTROY()
ON_WM_NCCALCSIZE()
ON_WM_NCPAINT()
ON_WM_NCHITTEST()
ON_WM_WINDOWPOSCHANGED()
//}}AFX_MSG_MAP
ON_REGISTERED_MESSAGE(MB_SET_MENU_NULL, OnSetMenuNull)
END_MESSAGE_MAP()
IMPLEMENT_DYNAMIC(CMenuBar, CControlBar)
/////////////////////////////////////////////////////////////////////////////
// CMenuBar Construction
CMenuBar::CMenuBar()
{
m_bMode=TRUE;
m_nDirectionKey=0;
m_arrDepth=0;
m_bLoadedFromResource=FALSE;
m_bUpdating=FALSE;
m_bNoTimer=FALSE;
m_bEnableChange=TRUE;
m_nCurIndex = -1;
m_nTrackingState = none;
m_bProcessRightArrow = m_bProcessLeftArrow = TRUE;
m_bIgnoreAlt = FALSE;
m_nIDEvent = NULL;
m_pMenu=NULL;
m_pWindowMenu=NULL;
m_pMainWndHook=NULL;
m_bMDIMaximized = FALSE;
m_hWndMDIClient = NULL;
m_hWndActiveChild = NULL;
m_pMenuIcon = NULL;
m_pMenuControl = NULL;
m_bDelayedButtonLayout = TRUE;
m_dwExStyle = 0;
m_bFrameActive = FALSE;
m_bMDIApp = FALSE;
m_nTotUse=0x8000;
m_nMenuCmd=1;
}
BOOL CMenuBar::Create(CWnd* pParentWnd, DWORD dwStyle, UINT nID)
{
return CreateEx(pParentWnd, dwStyle,
CRect(m_cxLeftBorder, m_cyTopBorder, m_cxRightBorder, m_cyBottomBorder), nID);
}
BOOL CMenuBar::CreateEx(CWnd* pParentWnd, DWORD dwStyle, CRect rcBorders, UINT nID)
{
ASSERT_VALID(pParentWnd);// must have a parent
ASSERT (!((dwStyle & CBRS_SIZE_FIXED) && (dwStyle & CBRS_SIZE_DYNAMIC)));
SetBorders(rcBorders);
// save the original style
m_dwExStyle = dwStyle;
// save the style
m_dwStyle = (dwStyle & CBRS_ALL);// ******fixed by Mark Gentry, thanx!******
dwStyle &= ~CBRS_ALL;
CString strClass = AfxRegisterWndClass(
CS_HREDRAW | CS_VREDRAW |
CS_DBLCLKS,// don't forget!
AfxGetApp()->LoadStandardCursor(IDC_ARROW),
(HBRUSH)(COLOR_BTNFACE+1));
m_pParent=pParentWnd;
if(!m_pParent) m_pParent=AfxGetMainWnd();
return CWnd::Create(strClass, _T("MenuBar"), dwStyle, CRect(), pParentWnd, nID);
}
int CMenuBar::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CControlBar::OnCreate(lpCreateStruct) == -1)
return -1;
CWnd* pFrame = GetOwner();
ASSERT_VALID(pFrame);
// hook frame window to trap WM_MENUSELECT
/*
m_pMainWndHook=m_hookFrame.GetMainWndHook();
if(m_pMainWndHook)m_pMainWndHook->HookWindow((HWND)NULL);
*/
m_hookFrame.Install(this, pFrame->GetSafeHwnd());
// If this is an MDI app, hook client window to trap WM_MDISETMENU
if (pFrame->IsKindOf(RUNTIME_CLASS(CMDIFrameWnd))) {
m_bMDIApp = TRUE;
m_hWndMDIClient = ((CMDIFrameWnd*)pFrame)->m_hWndMDIClient;
ASSERT(::IsWindow(m_hWndMDIClient));
m_hookMDIClient.Install(this, m_hWndMDIClient);
}
if (!_InitCommonResources()) {
TRACE(_T("Failed to create menubar resource\n"));
return FALSE;
}
return 0;
}
BOOL CMenuBar::InitItems()
{
ASSERT(m_pMenu);
// clean up all items
DeleteItems();
// buttons
for (int i = 0; i < (signed) m_pMenu->GetMenuItemCount(); ++i) {
m_arrItem.Add(new CMenuButton(m_pMenu, i));
}
if (m_bMDIApp) {
// icon
m_pMenuIcon = new CMenuIcon(this);
m_arrItem.InsertAt(0, m_pMenuIcon);
// frame control
m_pMenuControl = new CMenuControl(this);
m_arrItem.Add(m_pMenuControl);
// reinitializing
m_pMenuIcon->OnActivateChildWnd();
m_pMenuControl->OnActivateChildWnd();
}
return TRUE;
}
BOOL CMenuBar::LoadMenuBar(UINT nIDResource)
{
ASSERT(m_pMenu == NULL);
ASSERT_VALID(m_pDockSite);
if (m_pDockSite->GetMenu()) {
PostMessage(MB_SET_MENU_NULL, (WPARAM)m_pDockSite->GetSafeHwnd());
}
m_pMenu = new CMenuEx();
m_arrDepth=0;
m_arrSel.SetSize(1);
m_arrNSel.SetSize(1);
m_arrSel[0]=m_pMenu;
m_arrNSel[0]=0;
if (m_pMenu == NULL) {
TRACE(_T("Failed to load menu\n"));
return FALSE;
}
m_bLoadedFromResource=TRUE;
if (!m_pMenu->LoadMenu(MAKEINTRESOURCE(nIDResource))) {
TRACE(_T("Failed to load menu\n"));
return FALSE;
}
ResetMenuUsages(m_pMenu);
UpdateMenuRefresh();
return InitItems();
}
CMenuEx* CMenuBar::LoadMenu(CMenuEx* pMenu, CMenuEx* pWindowMenu)
{
ASSERT_VALID(this);
CFrameWnd* pFrame = CControlBar::GetParentFrame();
if (pFrame && pFrame->GetMenu() != NULL) {
// not to make MFC ignore SetMenu(NULL), post it.
PostMessage(MB_SET_MENU_NULL, (WPARAM)pFrame->GetSafeHwnd());
}
CMenuEx* pOldMenu = m_pMenu;
m_pMenu = pMenu;// menu is shared with MFC
m_arrDepth=0;
m_arrSel.SetSize(1);
m_arrSel[0]=m_pMenu;
m_arrNSel.SetSize(1);
m_arrNSel[0]=0;
// initialize Items
VERIFY(InitItems());
if (pMenu) {
m_pWindowMenu = pWindowMenu;
RefreshBar();// and menubar itself
}
if(m_bLoadedFromResource)
{
pOldMenu->DestroyMenu();
delete pOldMenu;
pOldMenu=NULL;
m_bLoadedFromResource=FALSE;
}
UpdateMenuRefresh();
return pOldMenu;
}
void CMenuBar::RefreshBar(BOOL bReposition)
{
InvalidateRect(NULL);
#if _MFC_VER >= 0x600
if (GetParent()->IsKindOf(RUNTIME_CLASS(CReBar))) {
m_bDelayedButtonLayout = TRUE;// to avoid ASSERTION
Layout();
}
#endif
if(bReposition)
{
CFrameWnd* pFrame = (CFrameWnd*)GetTopLevelFrame();
ASSERT_VALID(pFrame); ASSERT(pFrame->IsFrameWnd());
pFrame->RecalcLayout();
// floating frame
CFrameWnd* pMiniFrame = CControlBar::GetParentFrame();
if (pMiniFrame->IsKindOf(RUNTIME_CLASS(CMiniFrameWnd)))
pMiniFrame->RecalcLayout();
CWnd* pWnd=GetParent();
if (pWnd->IsKindOf(RUNTIME_CLASS(CDockBar))) pWnd=pWnd->GetParent();
if (!pWnd->IsKindOf(RUNTIME_CLASS(CFrameWnd)))
pWnd->RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST);
}
}
/////////////////////////////////////////////////////////////////////////////
// CMenuBar clean up
CMenuBar::~CMenuBar()
{
if(m_pMainWndHook) m_pMainWndHook->HookWindow(AfxGetMainWnd());
}
void CMenuBar::DeleteItems()
{
for(int i = 0; i < m_arrItem.GetSize(); ++i) {
CMenuItem* pItem = m_arrItem[i];
delete pItem;
}
m_arrItem.RemoveAll();
m_pMenuIcon = NULL;
m_pMenuControl = NULL;
}
/////////////////////////////////////////////////////////////////////////////
// CMenuBar draw
void CMenuBar::DoPaint(CDC* pDC)
{
// if (m_bDelayedButtonLayout)
// Layout();
//LTRACE(_T("CMenuBar::DoPaint\n"));
CRect rect; GetClientRect(rect);
// draw items
for (int i = 0; i < m_arrItem.GetSize(); ++i) {
m_arrItem[i]->Update(pDC);
}
// delay draw captions
if (m_pMenuControl) {
if (IsFloating()) {
m_pMenuControl->DelayLayoutAndDraw(pDC, rect.Size());
}
else {
if (m_dwStyle & CBRS_ORIENT_HORZ)
m_pMenuControl->DelayLayoutAndDraw(pDC, CSize(GetClipBoxLength(TRUE), rect.Height()));
else
m_pMenuControl->DelayLayoutAndDraw(pDC, CSize(rect.Width(), GetClipBoxLength(FALSE)));
}
}
}
void CMenuBar::UpdateBar(TrackingState nState, int nNewIndex)
{
if (m_nTrackingState == buttonmouse)
m_bIgnoreAlt = FALSE;// if prev state is BUTTONMOUSE, always should be FALSE!
m_nTrackingState = nState;
#ifdef _DEBUG
// static LPCTSTR lpszStates[] = { _T("NONE"), _T("BUTTON"), _T("POPUP"), _T("BUTTONMOUSE") };
// LTRACE(_T("CMenuBar::UpdateBar state to %s, button=%d\n"),
// lpszStates[nState], nNewIndex);
#endif
/*static LPCTSTR lpszStates[] = { _T("NONE"), _T("BUTTON"), _T("POPUP"), _T("BUTTONMOUSE") };
TRACE(_T("CMenuBar::UpdateBar state to %s, button=%d\n"),
lpszStates[nState], nNewIndex);*/
// clean up
if (IsValidIndex(m_nCurIndex)) {
CMenuItem* pItem = m_arrItem[m_nCurIndex];
CClientDC dc(this);
pItem->ModifyState(MISTATE_HOT | MISTATE_PRESSED, 0);
pItem->Update(&dc);
// draw captions forcefully
if (m_pMenuControl) {
CRect rcCross = m_pMenuControl->GetRect() & m_arrItem[m_nCurIndex]->GetRect();
if (!rcCross.IsRectEmpty()) {
m_pMenuControl->ForceDrawControl(&dc);
}
}
m_nCurIndex = -1;
}
if (nState != none) {
ASSERT(IsValidIndex(nNewIndex));
m_nCurIndex = nNewIndex;
m_nLastIndex = nNewIndex;
CMenuItem* pItem = m_arrItem[m_nCurIndex];
CClientDC dc(this);
if (nState == button || nState == buttonmouse) {
pItem->ModifyState(MISTATE_PRESSED, MISTATE_HOT);
pItem->Update(&dc);
}
else if (nState == popup) {
pItem->ModifyState(MISTATE_HOT, MISTATE_PRESSED);
pItem->Update(&dc);
}
// draw captions forcefully
if (m_pMenuControl) {
CRect rcCross = m_pMenuControl->GetRect() & m_arrItem[m_nCurIndex]->GetRect();
if (!rcCross.IsRectEmpty()) {
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -