⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 menubar.cpp

📁 一个很好的LFP规约调试器
💻 CPP
📖 第 1 页 / 共 4 页
字号:
// MenuBar.cpp : 
//

#include "stdafx.h"
#include "MenuBar.h"
#include <afxpriv.h>

#define _AfxGetDlgCtrlID(hWnd)          ((UINT)(WORD)::GetDlgCtrlID(hWnd))

#define HORZF(dw) (dw & CBRS_ORIENT_HORZ)
#define VERTF(dw) (dw & CBRS_ORIENT_VERT)

static void AdjustRectangle(CRect& rect, CPoint pt)
{
	int nXOffset = (pt.x < rect.left) ? (pt.x - rect.left) :
					(pt.x > rect.right) ? (pt.x - rect.right) : 0;
	int nYOffset = (pt.y < rect.top) ? (pt.y - rect.top) :
					(pt.y > rect.bottom) ? (pt.y - rect.bottom) : 0;
	rect.OffsetRect(nXOffset, nYOffset);
}

#include <math.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CMenuBar 


// I want overide EndDrag, but it's not virtual.
// So I have to overide StartDrag!
class CMenuBarDockContext : public CDockContext
{
public:
	CMenuBarDockContext(CControlBar* pBar) : CDockContext(pBar) { }

	virtual void StartDrag(CPoint pt);

private:
	BOOL _Track();
	void _EndDrag();
};

namespace {

	// hook
	CMenuBar* g_pMenuBar = NULL;
	HHOOK	  g_hMsgHook = NULL;

	// message
	const UINT MB_SET_MENU_NULL = WM_USER + 1100;

	// layout
	const int CXGAP		   = 5;
	const int CYGAP		   = 5;
	const int CYGAPVERT	   = 3;
	const int CXGRIPPER	   = 7;

	int cyMenuButton = 0;

	int	cxBorder2 = ::GetSystemMetrics(SM_CXBORDER) * 2;//bWin4 ? CX_BORDER*2 : CX_BORDER;
	int	cyBorder2 = ::GetSystemMetrics(SM_CYBORDER) * 2;//bWin4 ? CY_BORDER*2 : CY_BORDER;

#ifdef _DEBUG
	// if you won't output TRACE in debug mode, make it FALSE;
	BOOL bTraceOn = TRUE;
#endif

}

#ifdef _DEBUG
	#define LTRACE if (bTraceOn) TRACE
#else
	#define LTRACE
#endif

BOOL CMenuBar::m_bMDIApp = FALSE;

BEGIN_MESSAGE_MAP(CMenuBar, CControlBar)
	//{{AFX_MSG_MAP(CMenuBar)
	ON_WM_LBUTTONDOWN()
	ON_WM_MOUSEMOVE()
	ON_WM_TIMER()
	ON_WM_KILLFOCUS()
	ON_WM_CREATE()
	ON_WM_LBUTTONUP()
	ON_WM_DESTROY()
	ON_MESSAGE(MB_SET_MENU_NULL, OnSetMenuNull)
	ON_MESSAGE(WM_SYSCOLORCHANGE, OnSettingChange)
	ON_WM_ERASEBKGND()
	//}}AFX_MSG_MAP
	ON_MESSAGE(WM_SETTINGCHANGE, OnSettingChange)
END_MESSAGE_MAP()

CMenuBar::CMenuBar()
{
	m_nCurIndex  = -1;
	m_nTrackingState = none;
	m_bProcessRightArrow = m_bProcessLeftArrow = TRUE;
	m_bIgnoreAlt = FALSE;
	m_bDown		 = FALSE;
	m_hMenu		 = NULL;
	m_nIDEvent	 = NULL;

	m_bIcon		 = FALSE;
	m_bMDIMaximized = FALSE;
	m_hWndMDIClient = NULL;
	m_hWndActiveChild = NULL;

	m_pMenuIcon = NULL;
	m_pMenuControl = NULL;

	m_nCmdShow = SW_SHOW;

}

BOOL CMenuBar::Create(CWnd* pParentWnd, DWORD dwStyle, UINT nID)
{
	ASSERT_VALID(pParentWnd);	// must have a parent
	ASSERT (!((dwStyle & CBRS_SIZE_FIXED) && (dwStyle & CBRS_SIZE_DYNAMIC)));

	// save the style
	m_dwStyle = dwStyle & CBRS_ALL;   // fixed by Mark Gentry, thanx!
	m_dwStyle |= CBRS_SIZE_DYNAMIC;

	CString strClass = AfxRegisterWndClass(
		CS_HREDRAW | CS_VREDRAW ,	// don't forget!
		AfxGetApp()->LoadStandardCursor(IDC_ARROW),
		(HBRUSH)(COLOR_BTNFACE + 1));

	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_hookFrame.Install(this, pFrame->GetSafeHwnd());

	// If this is an MDI app, hook client window to trap WM_MDISETMENU
	if (pFrame->IsKindOf(RUNTIME_CLASS(CMDIFrameWnd))) {
		CMenuBar::m_bMDIApp = TRUE;
		m_hWndMDIClient = ((CMDIFrameWnd*)pFrame)->m_hWndMDIClient;
		ASSERT(m_hWndMDIClient);
		m_hookMDIClient.Install(this, m_hWndMDIClient);
	}
	
	// my own DockContext!
	m_pDockContext = new CMenuBarDockContext(this);

	return 0;
}

BOOL CMenuBar::InitItems()
{
	ASSERT(m_hMenu);

	// clean up all items
	DeleteItems();

	// a little suitable
	int nCount = ::GetMenuItemCount(m_hMenu);
	ASSERT(nCount > 0);
	m_arrItem.SetSize(nCount);

	if (!CMenuButton::InitCommonResource()) {
		TRACE0("Failed to create bar resource\n");
		return FALSE;
	}

	// buttons
	for (int i = 0; i < nCount; ++i) {
		m_arrItem[i] = new CMenuButton(m_hMenu, i);
	}
	cyMenuButton = m_arrItem[0]->m_sizeHorz.cy;

	// 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_hWndActiveChild = GetActiveChildWnd(m_bMDIMaximized);
	if (m_hWndActiveChild) {// re set 
		m_pMenuIcon->OnActivateChildWnd(m_hWndActiveChild);
	}
	if (m_bMDIMaximized) {
		m_pMenuIcon->Validate(TRUE);
		m_pMenuControl->Validate(TRUE);
	}

	return TRUE;
}

BOOL CMenuBar::LoadMenuBar(UINT nIDResource)
{
	if (m_hMenu) {
		::DestroyMenu(m_hMenu);
		m_hMenu = NULL;
	}

	ASSERT_VALID(m_pDockSite);
	if (m_pDockSite->GetMenu()) {
		PostMessage(MB_SET_MENU_NULL, (WPARAM)m_pDockSite->GetSafeHwnd());
	}
	
	m_hMenu = ::LoadMenu(AfxGetInstanceHandle(), MAKEINTRESOURCE(nIDResource));
	if (m_hMenu == NULL) {
		TRACE0("Failed to load menu\n");
		return FALSE;
	}

	return InitItems();
}

void CMenuBar::RefreshBar()
{
	InvalidateRect(NULL);

	CFrameWnd* pFrame = (CFrameWnd*)GetOwner();
	ASSERT_VALID(pFrame);
	ASSERT(pFrame->IsFrameWnd());
	pFrame->RecalcLayout();

	// floating frame
	pFrame = GetParentFrame();
	if (pFrame->IsKindOf(RUNTIME_CLASS(CMiniFrameWnd)))
		pFrame->RecalcLayout();
}


HMENU CMenuBar::LoadMenu(HMENU hMenu, HMENU hWindowMenu)
{
	LTRACE("CMenuBar::LoadMenu\n");
	UINT iPrevID=(UINT)-1;
	ASSERT(::IsMenu(hMenu));
	ASSERT_VALID(this);

	
	CFrameWnd* pFrame = GetParentFrame();
	if (::GetMenu(pFrame->GetSafeHwnd()) != NULL) {
		// not to make MFC ignore SetMenu(NULL), post it.
		PostMessage(MB_SET_MENU_NULL, (WPARAM)pFrame->GetSafeHwnd());
	}
	

	HMENU hOldMenu = m_hMenu;
	m_hMenu = hMenu;			// menu is shared with MFC

	// initialize Items 
	VERIFY(InitItems());

	if (hMenu) {
		m_hWindowMenu = hWindowMenu;
		RefreshBar();				// and menubar itself
	}

	return hOldMenu;
}


CMenuBar::~CMenuBar()
{
	if (m_bMDIApp == FALSE && m_hMenu != NULL)
		::DestroyMenu(m_hMenu);

	m_bitmap.Detach();
	if(m_hBmp)
		::DeleteObject(m_hBmp);
}

/////////////////////////////////////////////////////////////////////////////
// CMenuBar 傾僀僥儉偺忣曬


/////////////////////////////////////////////////////////////////////////////
// CMenuBar 傾僀僥儉昤夋

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

	// clean up
	if (IsValidIndex(m_nCurIndex)) {
		CDC* pDC = GetDC();
		m_arrItem[m_nCurIndex]->SetState(CMenuButton::none);
		m_arrItem[m_nCurIndex]->Update(pDC);

		CRect rcCross = m_pMenuControl->m_rcItem & m_arrItem[m_nCurIndex]->m_rcItem;
		if (!rcCross.IsRectEmpty()) {
			m_pMenuControl->ForceDrawControl(pDC);
		}

		ReleaseDC(pDC);
		m_nCurIndex = -1;
	}

	if (nState != none) {
		ASSERT(IsValidIndex(nNewIndex));
		m_nCurIndex = nNewIndex;
		CDC* pDC = GetDC();

		if (nState == button || nState == buttonmouse) {
			m_arrItem[m_nCurIndex]->SetState(CMenuButton::hot);
			m_arrItem[m_nCurIndex]->Update(pDC);
		}
		else if (nState == popup) {
			m_arrItem[m_nCurIndex]->SetState(CMenuButton::select);
			m_arrItem[m_nCurIndex]->Update(pDC);
		}

		CRect rcCross = m_pMenuControl->m_rcItem & m_arrItem[m_nCurIndex]->m_rcItem;
		if (!rcCross.IsRectEmpty()) {
			m_pMenuControl->ForceDrawControl(pDC);
		}

		ReleaseDC(pDC);
	}
	else {
		// must be default parameter
		ASSERT(nNewIndex == -1);
	}

	m_bProcessRightArrow = m_bProcessLeftArrow = TRUE;
}

/////////////////////////////////////////////////////////////////////////////
// CMenuBar 儊僢僙乕僕 僴儞僪儔

int CMenuBar::HitTestOnTrack(CPoint point)
{
	for (int i = 0; i < GetItemCount(); ++i) {
		CMenuItem* pItem = m_arrItem[i];
		CRect rcItem = pItem->GetItemRect();
		
		if (pItem->IsValid() && pItem->CanTrack() &&
			rcItem.PtInRect(point))
			return i;
	}

	return -1;
}

void CMenuBar::OnLButtonDown(UINT nFlags, CPoint point) 
{
//	LTRACE("CMenuBar::OnLButtonDown\n");

	ASSERT(m_pMenuControl);
	if (m_pMenuControl->OnMouseMsg(WM_LBUTTONDOWN, nFlags, point)) {
		return;			// eat it!
	}	
	
	int nIndex = HitTestOnTrack(point);
	if (IsValidIndex(nIndex) && m_arrItem[nIndex]->CanTrack()) {
/*		HMENU hSubMenu = ::GetSubMenu(m_hMenu, nIndex);
		if (hSubMenu == NULL) {
			UpdateWindow();	// force to repaint
			CDC* pDC = GetDC();
			m_arrItem[m_nCurIndex]->SetState(CMenuButton::select);
			m_arrItem[nIndex]->Update(pDC);
			ReleaseDC(pDC);
			m_bDown = TRUE;
		}
		else {
			TrackPopup(nIndex);
		}
*/
		TrackPopup(nIndex);

		return;		// eat it!
	}

	CControlBar::OnLButtonDown(nFlags, point);
}

void CMenuBar::OnMouseMove(UINT nFlags, CPoint point) 
{
//	TRACE("CMenuBar::OnMouseMove\n");

	if (!IsTopParentActive() || !GetTopLevelParent()->IsWindowEnabled()) {
		// window is not active, ignore
		CControlBar::OnMouseMove(nFlags, point);
		return;
	}

	ASSERT(m_pMenuControl);
	if (m_pMenuControl->OnMouseMsg(WM_MOUSEMOVE, nFlags, point)) {
		CControlBar::OnMouseMove(nFlags, point);
		return;
	}

	int nIndex = HitTestOnTrack(point);
	if (IsValidIndex(nIndex)) {	
		if (m_nCurIndex == -1 || m_nCurIndex != nIndex) {	// other button
			UpdateBar(buttonmouse, nIndex);			// button tracked with mouse
			// I wanna know when mouse is away,
			// but SetCapture makes ALT+F4 uncatchable
			// and WM_CAPTURECHANGED is never sent(why?), so we have to set timer
			_KillTimer();
			m_nIDEvent = SetTimer(1, 250, 0);
		}
	}
	else {
		UpdateBar();
	}

	CControlBar::OnMouseMove(nFlags, point);
}

/*//////////////////////////////Libin
//也可不用时间片的方法,可重载OnUpdateCmdUI(..)
void CMenuBar::OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler)
{
   if (m_nTrackingState == buttonmouse)
   {
      CPoint pt; ::GetCursorPos(&pt);
      CRect rect;
      GetWindowRect(&rect);

      if (!rect.PtInRect(pt))
         UpdateBar();
   }
}
//////////////////////////////*/

void CMenuBar::OnTimer(UINT nIDEvent) 
{
	if( nIDEvent == m_nIDEvent && m_nTrackingState == buttonmouse) {
		CPoint pt; ::GetCursorPos(&pt);
		CRect rect;
		GetWindowRect(&rect);
		if (!rect.PtInRect(pt)) {
			UpdateBar();
			_KillTimer();
		}
	}

	CControlBar::OnTimer(nIDEvent);
}

void CMenuBar::OnKillFocus(CWnd* pNewWnd) 
{
	CControlBar::OnKillFocus(pNewWnd);
	
	// TODO: 
	UpdateBar();
}

LRESULT CMenuBar::OnSetMenuNull(WPARAM wParam, LPARAM)
{
	HWND hWnd = (HWND)wParam;
	ASSERT(::IsWindow(hWnd));
	::SetMenu(hWnd, NULL);
	
	return 0;
}

LRESULT CMenuBar::OnSettingChange(WPARAM wParam, LPARAM lParam)
{
	InitItems();

	CFrameWnd* pFrame = GetParentFrame();
	ASSERT_VALID(pFrame);
	pFrame->RecalcLayout();
	return 0;
}

/////////////////////////////////////////////////////////////////////////////
// CMenuBar

void CMenuBar::OnMenuSelect(HMENU hMenu, UINT nIndex)
{
	if (m_nTrackingState == popup) {
		m_bProcessRightArrow = (::GetSubMenu(hMenu, nIndex) == NULL);
		HMENU hSubMenu = ::GetSubMenu(hMenu, m_nCurIndex);
		if (hSubMenu == NULL)
			return;
		m_bProcessLeftArrow = (hMenu == hSubMenu);
	}
}

LRESULT CALLBACK CMenuBar::MenuInputFilter(int code, WPARAM wParam, LPARAM lParam)
{
	return (
		code == MSGF_MENU &&
		g_pMenuBar &&
		g_pMenuBar->OnMenuInput( *((MSG*)lParam) )
		) ? TRUE : CallNextHookEx(g_hMsgHook, code, wParam, lParam);
}

void CMenuBar::TrackPopup(int nIndex)
{
	ASSERT_VALID(this);

	m_nCurIndex = nIndex;
	m_bLoop = TRUE;
	while (m_bLoop == TRUE) {
		UpdateWindow();	// force to repaint when button hidden by other window
		UpdateBar(popup, m_nCurIndex);
	
		// install hook
		ASSERT(g_pMenuBar == NULL);
		g_pMenuBar = this;
		ASSERT(g_hMsgHook == NULL);

		m_bLoop = FALSE;
		g_hMsgHook = ::SetWindowsHookEx(WH_MSGFILTER,
			MenuInputFilter, NULL, AfxGetApp()->m_nThreadID);// m_bLoop may become TRUE

		// popup!!
		m_nTrackingState = popup;
		m_arrItem[m_nCurIndex]->TrackPopup(this);

		// uninstall hook
		::UnhookWindowsHookEx(g_hMsgHook);
		g_hMsgHook = NULL;
		g_pMenuBar = NULL;
	}

	UpdateBar();
}

BOOL CMenuBar::OnMenuInput(MSG& m)
{
	ASSERT_VALID(this);
	int nMsg = m.message;
	CPoint pt = m.lParam;
	ScreenToClient(&pt);

	switch (nMsg) {
	case WM_MOUSEMOVE:
		if (pt != m_ptMouse) {
			int nIndex = HitTestOnTrack(pt);
			if (IsValidIndex(nIndex) && nIndex != m_nCurIndex) {
				// defferent button clicked
				GetOwner()->PostMessage(WM_CANCELMODE); // destroy popupped menu
				UpdateBar();							// clean up
				m_nCurIndex = nIndex;
				m_bLoop = TRUE;							// continue loop
			}
			m_ptMouse = pt;
		}
		break;

	case WM_LBUTTONDOWN:
		if (HitTestOnTrack(pt) != -1 && HitTestOnTrack(pt) == m_nCurIndex) {
			// same button clicked
			GetOwner()->PostMessage(WM_CANCELMODE); // destroy popupped menu
			UpdateBar(button, m_nCurIndex);
			return TRUE;							// eat it!
		}
		break;

	case WM_KEYDOWN:	{
		TCHAR vKey = m.wParam;
		if (m_dwStyle & CBRS_ORIENT_VERT) {	// if vertical
			break; // do nothing
		}

		if ((vKey == VK_LEFT  && m_bProcessLeftArrow) ||
			(vKey == VK_RIGHT && m_bProcessRightArrow)) {
			// no submenu
			int nNewIndex = GetNextOrPrevButton(m_nCurIndex, vKey==VK_LEFT);
			GetOwner()->PostMessage(WM_CANCELMODE); // destroy popupped menu
			UpdateBar();
			m_nCurIndex = nNewIndex;
			m_bLoop = TRUE;							// continue loop			
			return TRUE;							// eat it!
		}
						}
		break;

	case WM_SYSKEYDOWN:
//		LTRACE("    m_bIgnore = TRUE\n");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -