www.pudn.com > SCIDE.rar > MenuBar.cpp


// MenuBar.cpp : implementation file 
// CMenuBar version 2.12 
 
#include "stdafx.h" 
#include "MenuBar.h" 
#include  
 
#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() 
	//}}AFX_MSG_MAP 
	ON_REGISTERED_MESSAGE(MB_SET_MENU_NULL, OnSetMenuNull) 
END_MESSAGE_MAP() 
 
IMPLEMENT_DYNAMIC(CMenuBar, CControlBar) 
 
///////////////////////////////////////////////////////////////////////////// 
// CMenuBar Construction 
CMenuBar::CMenuBar() 
{ 
	m_nCurIndex  = -1; 
	m_nTrackingState = none; 
	m_bProcessRightArrow = m_bProcessLeftArrow = TRUE; 
	m_bIgnoreAlt = FALSE; 
	m_hMenu = NULL; 
	m_nIDEvent = 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; 
} 
 
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)); 
 
	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))) { 
		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_hMenu); 
 
	// clean up all items 
	DeleteItems(); 
 
	// buttons 
	for (int i = 0; i < ::GetMenuItemCount(m_hMenu); ++i) { 
		m_arrItem.Add(new CMenuButton(m_hMenu, 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_hMenu == NULL); 
//	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) { 
		TRACE(_T("Failed to load menu\n")); 
		return FALSE; 
	} 
 
	return InitItems(); 
} 
 
HMENU CMenuBar::LoadMenu(HMENU hMenu, HMENU hWindowMenu) 
{ 
	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; 
} 
 
void CMenuBar::RefreshBar() 
{ 
	InvalidateRect(NULL); 
 
#if _MFC_VER >= 0x600 
		if (GetParent()->IsKindOf(RUNTIME_CLASS(CReBar))) { 
			m_bDelayedButtonLayout = TRUE;// to avoid ASSERTION 
			Layout(); 
		} 
#endif 
 
	CFrameWnd* pFrame = (CFrameWnd*)GetTopLevelFrame(); 
	ASSERT_VALID(pFrame); ASSERT(pFrame->IsFrameWnd()); 
	pFrame->RecalcLayout(); 
 
	// floating frame 
	CFrameWnd* pMiniFrame = GetParentFrame(); 
	if (pMiniFrame->IsKindOf(RUNTIME_CLASS(CMiniFrameWnd))) 
		pMiniFrame->RecalcLayout(); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// CMenuBar clean up  
CMenuBar::~CMenuBar() 
{ 
 
} 
 
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 
 
	// 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; 
		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()) { 
				m_pMenuControl->ForceDrawControl(&dc); 
			} 
		} 
	} 
	else { 
		// must be default parameter 
		ASSERT(nNewIndex == -1); 
	} 
 
	m_bProcessRightArrow = m_bProcessLeftArrow = TRUE; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// CMenuBar message handler 
int CMenuBar::HitTestOnTrack(CPoint point) 
{ 
	for (int i = 0; i < GetItemCount(); ++i) { 
		CMenuItem* pItem = m_arrItem[i]; 
		CRect rcItem = pItem->GetRect(); 
		 
		if ((pItem->GetStyle() & MISTYLE_TRACKABLE) && 
			rcItem.PtInRect(point)) 
			return i; 
	} 
 
	return -1; 
} 
 
void CMenuBar::OnLButtonDown(UINT nFlags, CPoint point)  
{ 
//	LTRACE("CMenuBar::OnLButtonDown\n"); 
	if (m_pMenuControl && m_pMenuControl->OnMouseMsg(WM_LBUTTONDOWN, nFlags, point)) { 
		return;		// eat it! 
	}	 
 
	int nIndex = HitTestOnTrack(point); 
	if (IsValidIndex(nIndex) &&	(m_arrItem[nIndex]->GetStyle() & MISTYLE_TRACKABLE)) { 
		TrackPopup(nIndex); 
		return;		// eat it! 
	} 
 
	CControlBar::OnLButtonDown(nFlags, point); 
} 
 
void CMenuBar::OnMouseMove(UINT nFlags, CPoint point) 
{ 
//	LTRACE(_T("CMenuBar::OnMouseMove\n")); 
 
	if (m_pMenuControl && 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) {// if other button 
			UpdateBar(buttonmouse, nIndex);// button made hot with mouse 
 
			if (!m_nIDEvent) 
				m_nIDEvent = SetTimer(1, 100, NULL); 
		} 
	} 
	else { 
		UpdateBar(); 
	} 
 
	CControlBar::OnMouseMove(nFlags, point); 
} 
 
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) 
{ 
	// reinitialize fonts etc 
	if (!_InitCommonResources(TRUE)) { 
		TRACE(_T("Failed to create bar resource\n")); 
		return FALSE; 
	} 
 
	VERIFY(InitItems()); 
 
	CFrameWnd* pFrame = GetParentFrame(); 
	ASSERT_VALID(pFrame); 
	pFrame->RecalcLayout(); 
	return 0; 
} 
 
void CMenuBar::OnLButtonUp(UINT nFlags, CPoint point)  
{ 
	// TODO:  
//	LTRACE(_T("CMenuBar::OnLButtonUp\n")); 
	if (m_pMenuControl && m_pMenuControl->OnMouseMsg(WM_LBUTTONUP, nFlags, point)) { 
		CControlBar::OnLButtonUp(nFlags, point); 
		return; 
	}	 
 
	CControlBar::OnLButtonUp(nFlags, point); 
} 
 
void CMenuBar::CheckActiveChildWndMaximized() 
{ 
	//LTRACE(_T("CMenuBar::CheckActiveChildWndMaximized\n")); 
	ASSERT(m_pMenuControl); 
	ASSERT(m_pMenuIcon); 
 
	BOOL bMaximized = FALSE; 
	GetActiveChildWnd(bMaximized); 
	if (m_bMDIMaximized != bMaximized) { 
		LTRACE(_T("CMenuBar::CheckActiveChildWndMaximized---state changed, refreshing\n")); 
		m_bMDIMaximized = bMaximized; 
		m_pMenuControl->OnActivateChildWnd(); 
		m_pMenuIcon->OnActivateChildWnd(); 
		RefreshBar(); 
	} 
} 
 
void CMenuBar::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu) 
{ 
	LTRACE(_T("CMenuBar::OnInitMenuPopup\n")); 
	CMenu menu; 
	menu.Attach((HMENU)m_hWindowMenu); 
 
	// scan for first window command 
	int n = menu.GetMenuItemCount(); 
	BOOL bAddSeperator = TRUE; 
	for (int iPos=0; 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" 
	// *****fixed by VORGA, thanks!***** 
	int iWin; 
	int nID = AFX_IDM_FIRST_MDICHILD; 
	CString sWinName, sMenuItem; 
	HWND hwnd; 
	for (iWin = 1; iWin <= 10; iWin++, nID++) 
	{ 
		hwnd = ::GetDlgItem(m_hWndMDIClient, nID); 
		if (hwnd == NULL) 
			break; 
 
		if (bAddSeperator) 
		{ 
			menu.InsertMenu(iPos++, MF_BYPOSITION | MF_SEPARATOR); 
		bAddSeperator = FALSE; 
		} 
 
		if (iWin < 10) 
		{ 
			CWnd::FromHandle(hwnd)->GetWindowText(sWinName); 
			sMenuItem.Format(_T("&%d %s"), iWin, (LPCTSTR)sWinName); 
			menu.InsertMenu(iPos, MF_BYPOSITION, nID, sMenuItem); 
			if (hwnd == hwndActive) 
				menu.CheckMenuItem(iPos, MF_BYPOSITION | MF_CHECKED); 
		} 
		else 
		{ 
			menu.InsertMenu(iPos, MF_BYPOSITION, nID, _szMoreWindows); 
		} 
		iPos++; 
	} 
 
	menu.Detach(); 
} 
 
void CMenuBar::OnSetMenu(HMENU hNewMenu, HMENU hWindowMenu) 
{ 
	ASSERT(m_pMenuIcon && m_pMenuControl); 
	// We can get active MDI child window on this message! 
	BOOL bMax = FALSE; 
	HWND hWndChild = GetActiveChildWnd(bMax); 
 
	if (!m_hWndActiveChild || m_hWndActiveChild != hWndChild) {// an active child window changed 
		LTRACE(_T("CMenuBar::OnSetMenu---an active child window changed\n")); 
		m_hWndActiveChild = hWndChild; 
		// tell MenuIcon child window has been changed 
		m_pMenuIcon->OnActivateChildWnd(); 
	} 
 
	if (!m_hMenu || m_hMenu != hNewMenu) {	// menu changed 
		LTRACE(_T("CMenuBar::OnSetMenu---menu changed\n")); 
		LoadMenu(hNewMenu, hWindowMenu);	// set menubar menu 
		GetOwner()->SetMenu(NULL);			// clear frame menu 
	} 
} 
 
void CMenuBar::OnNcPaint()  
{ 
	EraseNonClientEx(); 
} 
 
UINT CMenuBar::OnNcHitTest(CPoint point)  
{ 
	// make nonclient area clickable 
	return HTCLIENT; 
} 
 
void CMenuBar::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS FAR* lpncsp)  
{ 
	// calculate border space (will add to top/bottom, subtract from right/bottom) 
	CRect rect; rect.SetRectEmpty(); 
	BOOL bHorz = (m_dwStyle & CBRS_ORIENT_HORZ) != 0; 
	_CalcInsideRect(rect, bHorz); 
//	ASSERT(_afxComCtlVersion != -1); 
//	ASSERT(_afxComCtlVersion >= VERSION_IE4 || rect.top >= 2); 
 
	// adjust non-client area for border space 
	lpncsp->rgrc[0].left += rect.left; 
	lpncsp->rgrc[0].top += rect.top; 
	// previous versions of COMCTL32.DLL had a built-in 2 pixel border 
//	if (_afxComCtlVersion < VERSION_IE4) 
//		lpncsp->rgrc[0].top -= 2; 
	lpncsp->rgrc[0].right += rect.right; 
	lpncsp->rgrc[0].bottom += rect.bottom; 
} 
 
void CMenuBar::OnDestroy()  
{ 
	CControlBar::OnDestroy(); 
	 
	// TODO:  
	DeleteItems(); 
	 
	if (m_nIDEvent) 
		KillTimer(m_nIDEvent); 
 
		// for SDI application 
	if (m_bMDIApp == FALSE && m_hMenu != NULL) 
		::FreeResource(m_hMenu); 
} 
 
void CMenuBar::OnTimer(UINT nIDEvent)  
{ 
	// TODO: この位置にメッセージ ハンドラ用のコードを追加するかまたはデフォルトの処理を呼び出してください 
	if (m_nTrackingState == buttonmouse) { 
		CPoint pt; ::GetCursorPos(&pt); 
		CRect rect; 
		GetWindowRect(&rect); 
 
		if (!rect.PtInRect(pt)) { 
			UpdateBar(); 
 
			if (m_nIDEvent) { 
				KillTimer(m_nIDEvent); 
				m_nIDEvent = NULL; 
			} 
		} 
	}	 
 
	CControlBar::OnTimer(nIDEvent); 
} 
 
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; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// CMenuBar system hook 
void CMenuBar::OnMenuSelect(HMENU hMenu, UINT nIndex) 
{ 
//	LTRACE(_T("CMenuBar::OnMenuSelect\n")); 
	if (m_nTrackingState == popup) { 
		m_bProcessRightArrow = (::GetSubMenu(hMenu, nIndex) == NULL); 
		HMENU hSubMenu = ::GetSubMenu(hMenu, m_nCurIndex); 
		if (hSubMenu == NULL) 
			return; 
		m_bProcessLeftArrow = (hMenu == hSubMenu); 
	} 
} 
 
void CMenuBar::OnFrameNcActivate(BOOL bActive)  
{ 
	CFrameWnd* pFrame = GetTopLevelFrame(); 
	ASSERT_VALID(pFrame); 
 
	if (pFrame->m_nFlags & WF_STAYACTIVE) 
		bActive = TRUE; 
	if (!pFrame->IsWindowEnabled()) 
		bActive = FALSE; 
	if (bActive == m_bFrameActive) 
		return; 
 
	if (!bActive) { 
		for (int i = 0; i < GetItemCount(); ++i) { 
			m_arrItem[i]->ModifyState(0, MISTATE_INACTIVE); 
		} 
	} 
	else { 
		for (int i = 0; i < GetItemCount(); ++i) { 
			m_arrItem[i]->ModifyState(MISTATE_INACTIVE, 0); 
		} 
	} 
 
	m_bFrameActive = bActive; 
 
	// InvalidateRect(NULL); is better, but too late 
	// while clicking the application title bar (like IE5) 
	// so we have to redraw now! 
	CClientDC dc(this); 
	DoPaint(&dc); 
} 
 
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; 
		_nPrevIndexForCmd = m_nCurIndex; 
		m_arrItem[m_nCurIndex]->TrackPopup(this, GetTopLevelParent()); 
 
		// 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 
				AfxGetMainWnd()->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 
			AfxGetMainWnd()->PostMessage(WM_CANCELMODE); // destroy popupped menu 
			UpdateBar(button, m_nCurIndex); 
			m_bLoop = FALSE;						// out of loop 
			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); 
			AfxGetMainWnd()->PostMessage(WM_CANCELMODE); // destroy popupped menu 
			UpdateBar(); 
			m_nCurIndex = nNewIndex; 
			m_bLoop = TRUE;							// continue loop			 
			return TRUE;							// eat it! 
		} 
						} 
		break; 
 
	case WM_SYSKEYDOWN: 
//		LTRACE(_T("    m_bIgnore = TRUE\n")); 
		m_bIgnoreAlt = TRUE;					// next SysKeyUp will be ignored 
		break; 
	} 
 
	return FALSE;	// pass along... 
} 
 
BOOL CMenuBar::TranslateFrameMessage(MSG* pMsg) 
{ 
	ASSERT_VALID(this); 
	ASSERT(pMsg); 
 
/*	if (_GetCmdSentWnd(NULL)->GetSafeHwnd() != GetTopLevelParent()->GetSafeHwnd()) { 
		if (m_nTrackingState == popup) { 
			LTRACE(_T("CMenuBar::TranslateMessage - SendMessage\n")); 
			pMsg->hwnd = _GetCmdSentWnd(NULL)->GetSafeHwnd(); 
			_GetCmdSentWnd(NULL)->SendMessage(pMsg->message, pMsg->wParam, pMsg->lParam); 
			return TRUE; 
		} 
	} 
*/ 
	UINT nMsg = pMsg->message; 
	if (WM_LBUTTONDOWN <= nMsg && nMsg <= WM_MOUSELAST) { 
		if (pMsg->hwnd != m_hWnd && m_nTrackingState > 0) { 
			// clicked outside 
			UpdateBar(); 
		} 
	} 
	else if (nMsg == WM_SYSKEYDOWN || nMsg == WM_SYSKEYUP || nMsg == WM_KEYDOWN) { 
		BOOL bAlt = HIWORD(pMsg->lParam) & KF_ALTDOWN;	// Alt key presed? 
		TCHAR vkey = pMsg->wParam;						// + X key 
		if (vkey == VK_MENU || 
			(vkey == VK_F10 && !((GetKeyState(VK_SHIFT) & 0x80000000) || 
			                   (GetKeyState(VK_CONTROL) & 0x80000000) || bAlt))) { 
			// only alt key pressed 
			if (nMsg == WM_SYSKEYUP) { 
				switch (m_nTrackingState) { 
				case none: 
					if (m_bIgnoreAlt == TRUE) { 
//						LTRACE(_T("    ignore ALT key up\n")); 
						m_bIgnoreAlt = FALSE; 
						break; 
					} 
				 
					if (m_bMDIApp) { 
						UpdateBar(button, GetNextOrPrevButton(0, FALSE)); 
					} 
					else { 
						UpdateBar(button, 0); 
					} 
					break; 
				case button: 
					UpdateBar(); 
					break; 
				case buttonmouse: 
					break;	// do nothing 
				} 
			} 
			return TRUE; 
		} 
		else if ((nMsg == WM_SYSKEYDOWN || nMsg == WM_KEYDOWN)) { 
			if (m_nTrackingState == button) { 
				if (m_dwStyle & CBRS_ORIENT_HORZ) {	// if horizontal 
					switch (vkey) { 
					case VK_LEFT: 
					case VK_RIGHT: { 
						int nNewIndex  = GetNextOrPrevButton(m_nCurIndex, vkey == VK_LEFT); 
						UpdateBar(button, nNewIndex); 
						return TRUE; 
								   } 
					case VK_SPACE: 
					case VK_UP: 
					case VK_DOWN: 
						TrackPopup(m_nCurIndex); 
						return TRUE; 
 
					case VK_ESCAPE: 
						UpdateBar(); 
						return TRUE; 
					} 
				} 
				else {								// if vertical 
					switch (vkey) { 
					case VK_UP: 
					case VK_DOWN:{ 
						int nNewIndex = GetNextOrPrevButton(m_nCurIndex, vkey == VK_UP); 
						UpdateBar(button, nNewIndex); 
						return TRUE; 
								   } 
					case VK_SPACE: 
					case VK_RIGHT: 
					case VK_LEFT: 
						TrackPopup(m_nCurIndex); 
						return TRUE; 
 
					case VK_ESCAPE: 
						UpdateBar(); 
						return TRUE; 
					} 
				} 
			} 
 
			// Alt + X pressed 
			if ((bAlt || m_nTrackingState == button) && _istalnum(vkey)) { 
				int nIndex; 
				if (MapAccessKey(vkey, nIndex) == TRUE) { 
					UpdateBar(); 
					TrackPopup(nIndex); 
					return TRUE;		// eat it! 
				} 
				else if (m_nTrackingState==button && !bAlt) { 
//					MessageBeep(0);		// if you want 
					return TRUE; 
				} 
			} 
 
			if (m_nTrackingState > 0) {	// unknown key 
				if (m_nTrackingState != buttonmouse) {	// if tracked with mouse, don't update bar 
					UpdateBar(); 
				} 
			} 
		} 
	} 
	return FALSE;	// pass along... 
} 
 
BOOL CMenuBar::MapAccessKey(TCHAR cAccessKey, int& nIndex) 
{ 
	for (int i = 0; i < GetItemCount(); ++i) { 
		// fixing point 
		TCHAR cKey = m_arrItem[i]->GetAccessKey(); 
		if (toupper(cKey)/*_totupper(cKey)*/ == cAccessKey) {// *****fixed by andi, thanx!***** 
			nIndex = i; 
			return TRUE; 
		} 
	} 
	return FALSE; 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// CMenuBar layout 
int CMenuBar::GetClipBoxLength(BOOL bHorz) 
{ 
	CFrameWnd* pFrame = GetTopLevelFrame(); ASSERT_VALID(pFrame); 
	CRect rcFrame; pFrame->GetWindowRect(rcFrame); 
 
	CWnd* pParent = GetParent(); ASSERT_VALID(pParent); 
	CRect rcParent; pParent->GetWindowRect(rcParent); 
 
	const int cxFrameBorder = ::GetSystemMetrics(SM_CXFRAME); 
	int cxNonClient = cxFrameBorder*2 + m_cxLeftBorder + m_cxRightBorder; 
	if (m_dwExStyle & CBRS_GRIPPER) 
		cxNonClient += CX_GRIPPER_ALL; 
 
	if (m_dwStyle & CBRS_SIZE_DYNAMIC) { 
		if (bHorz) { 
			return rcFrame.Width() - cxNonClient; 
		} 
		else { 
			int nResult = rcParent.Height(); 
			// I don't know the reason of the following code... 
			nResult -= m_cxRightBorder + m_cxLeftBorder + cyBorder2*2;	 
			if (m_dwExStyle & CBRS_GRIPPER) 
				nResult -= CY_GRIPPER_ALL; 
 
			return nResult; 
		} 
	} 
	else { 
		CRect rect; GetClientRect(rect); 
		if (bHorz) { 
			return rect.Width(); 
		} 
		else { 
			return rect.Height(); 
		} 
	} 
} 
 
CSize CMenuBar::CalcLayout(DWORD dwMode, int nLength) 
{ 
	ASSERT_VALID(this); 
	ASSERT(::IsWindow(m_hWnd)); 
	if (dwMode & LM_HORZDOCK) 
		ASSERT(dwMode & LM_HORZ); 
 
	// make SC_CLOSE button disable 
	if (m_dwStyle & CBRS_FLOATING) { 
		CFrameWnd* pMiniFrame = GetParentFrame(); ASSERT_KINDOF(CMiniFrameWnd, pMiniFrame); 
//		Don't do this, cause right click menu turns unavairable 
//		pMiniFrame->ModifyStyle(WS_SYSMENU, 0); 
		CMenu* pSysMenu = pMiniFrame->GetSystemMenu(FALSE);	ASSERT_VALID(pSysMenu); 
		pSysMenu->EnableMenuItem(SC_CLOSE, MF_BYCOMMAND | MF_GRAYED); 
	} 
 
	int nCount = GetItemCount(); 
	CSize sizeResult(0, 0); 
 
	if (nCount > 0) 
	{ 
		if (!(m_dwStyle & CBRS_SIZE_FIXED)) 
		{ 
			BOOL bDynamic = m_dwStyle & CBRS_SIZE_DYNAMIC; 
 
			if (bDynamic && (dwMode & LM_MRUWIDTH)) 
			{ 
				LTRACE(_T("CMenuBar::CalcLayout(CBRS_SIZE_DYNAMIC)---LM_MRUWIDTH\n")); 
				SizeMenuBar(m_nMRUWidth); 
				CalcItemLayout(nCount);// added 
 
				sizeResult = CalcSize(nCount); 
			} 
			else if (bDynamic && (dwMode & LM_HORZDOCK)) 
			{ 
				LTRACE(_T("CMenuBar::CalcLayout(CBRS_SIZE_DYNAMIC)---LM_HORZDOCK\n")); 
				if (IsFloating() || (m_dwStyle & CBRS_ORIENT_VERT)) { 
					// I can't synchronize horz size on dragging with size on dock bar 
					// as VC++ developer can't. 
					SizeMenuBar(32767); 
				} 
				else { 
					// Menu Button wrapped by frame width 
					SizeMenuBar(GetClipBoxLength(TRUE)); 
				} 
 
				CalcItemLayout(nCount);// added 
				 
				sizeResult = CalcSize(nCount); 
				if (!IsFloating() && !(m_dwStyle & CBRS_ORIENT_VERT)) { 
					if (m_pDockContext->m_pDC) {// while dragging (m_pDockContext->m_bDragging is helpless) 
						sizeResult.cx = GetClipBoxLength(TRUE); 
					} 
				} 
			} 
			else if (bDynamic && (dwMode & LM_VERTDOCK)) 
			{ 
				LTRACE(_T("CMenuBar::CalcLayout(CBRS_SIZE_DYNAMIC)---LM_VERTDOCK\n")); 
				//SizeMenuBar(0); 
				CalcItemLayout(nCount, TRUE);// added 
 
				sizeResult = CalcVertDockSize(nCount); 
				if (!IsFloating() && !(m_dwStyle & CBRS_ORIENT_HORZ)) { 
					if (m_pDockContext->m_pDC) {// while dragging 
						sizeResult.cy = GetClipBoxLength(FALSE);//GetrcParent.Height() - m_cxRightBorder - m_cxLeftBorder; 
					} 
				} 
			} 
			else if (bDynamic && (nLength != -1)) 
			{ 
				LTRACE(_T("CMenuBar::CalcLayout(CBRS_SIZE_DYNAMIC)---nLength != -1\n")); 
				CRect rect; rect.SetRectEmpty(); 
				_CalcInsideRect(rect, (dwMode & LM_HORZ)); 
				BOOL bVert = (dwMode & LM_LENGTHY); 
				int nLen = nLength + (bVert ? rect.Height() : rect.Width()); 
 
				SizeMenuBar(nLen, bVert); 
				CalcItemLayout(nCount, bVert);// added 
 
				sizeResult = CalcSize(nCount); 
			} 
			else if (bDynamic && (m_dwStyle & CBRS_FLOATING)) 
			{ 
				LTRACE(_T("CMenuBar::CalcLayout(CBRS_SIZE_DYNAMIC)---CBRS_FLOATING\n")); 
				SizeMenuBar(m_nMRUWidth); 
				CalcItemLayout(nCount);// added 
 
				sizeResult = CalcSize(nCount); 
			} 
			else 
			{ 
				if (!bDynamic) { 
					InvalidateRect(NULL); 
					goto Junk; 
				} 
 
				LTRACE(_T("CMenuBar::CalcLayout(CBRS_SIZE_DYNAMIC)---other\n")); 
				BOOL bVert = !(dwMode & LM_HORZ); 
				SizeMenuBar(GetClipBoxLength(TRUE)); 
				CalcItemLayout(nCount, bVert);// added 
 
				if (bVert) { 
					InvalidateRect(NULL);// draw forcefully for captions 
					sizeResult = CalcVertDockSize(nCount); 
					// DockBar not replaced yet, so I can't get precise size 
					sizeResult.cy = 10000; 
				} 
				else { 
					sizeResult = CalcSize(nCount); 
					sizeResult.cx = GetClipBoxLength(TRUE); 
				} 
			} 
		} 
		else {// CBRS_SIZE_FIXED 
			LTRACE(_T("CMenuBar::CalcLayout(CBRS_SIZE_FIXED)\n")); 
Junk: 
			BOOL bVert = !(dwMode & LM_HORZ); 
			SizeMenuBar(32767); 
			CalcItemLayout(nCount, bVert);// added 
 
			if (bVert) { 
				sizeResult = CalcVertDockSize(nCount); 
			} 
			else { 
				sizeResult = CalcSize(nCount); 
			} 
		} 
 
		if (dwMode & LM_COMMIT) 
		{ 
			LTRACE(_T("CMenuBar::CalcLayout---LM_COMMIT\n")); 
			int nControlCount = 0; 
			BOOL bIsDelayed = m_bDelayedButtonLayout; 
			m_bDelayedButtonLayout = FALSE; 
 
			if ((m_dwStyle & CBRS_FLOATING) && (m_dwStyle & CBRS_SIZE_DYNAMIC)) 
				m_nMRUWidth = sizeResult.cx; 
 
			//CalcItemLayout(nCount, dwMode); 
 
			m_bDelayedButtonLayout = bIsDelayed; 
		} 
	} 
 
	//BLOCK: Adjust Margins 
	{ 
		CRect rect; rect.SetRectEmpty(); 
		_CalcInsideRect(rect, (dwMode & LM_HORZ)); 
		sizeResult.cy -= rect.Height(); 
		sizeResult.cx -= rect.Width(); 
 
		CSize size = CControlBar::CalcFixedLayout((dwMode & LM_STRETCH), (dwMode & LM_HORZ)); 
		sizeResult.cx = max(sizeResult.cx, size.cx); 
		sizeResult.cy = max(sizeResult.cy, size.cy); 
	} 
	return sizeResult; 
} 
 
CSize CMenuBar::CalcFixedLayout(BOOL bStretch, BOOL bHorz) 
{ 
	LTRACE(_T("CMenuBar::CalcFixedLayout\n")); 
	ASSERT_VALID(this); 
	ASSERT(::IsWindow(m_hWnd)); 
 
	DWORD dwMode = bStretch ? LM_STRETCH : 0; 
	dwMode |= bHorz ? LM_HORZ : 0; 
 
	return CalcLayout(dwMode); 
} 
 
CSize CMenuBar::CalcDynamicLayout(int nLength, DWORD dwMode) 
{ 
	LTRACE(_T("CMenuBar::CalcDynamicLayout\n")); 
	if ((nLength == -1) && !(dwMode & LM_MRUWIDTH) && !(dwMode & LM_COMMIT) && 
		((dwMode & LM_HORZDOCK) || (dwMode & LM_VERTDOCK))) 
	{ 
		LTRACE(_T("    FixedLayout\n")); 
		return CalcFixedLayout(dwMode & LM_STRETCH, dwMode & LM_HORZDOCK); 
	} 
	return CalcLayout(dwMode, nLength); 
} 
 
// set m_bWrapped by nWidth 
int CMenuBar::WrapMenuBar(int nCount, int nWidth) 
{ 
//	LTRACE(_T("CMenuBar::WrapMenuBar\n")); 
	int nResult = 0; 
	int x = 0; 
 
	for (int i = 0; i < nCount; ++i) { 
		CMenuItem* pItem = m_arrItem[i]; 
		if (i+1 == nCount) 
			return ++nResult; 
		 
		if (x + pItem->GetHorizontalSize().cx> nWidth) {// itself is over 
			if (pItem->GetStyle() & MISTYLE_WRAPPABLE) { 
				pItem->ModifyState(0, MISTATE_WRAP); 
				++nResult; 
				x = 0; 
			} 
		} 
		else if (x + pItem->GetHorizontalSize().cx +  
				 m_arrItem[i+1]->GetHorizontalSize().cx> nWidth) { 
			if (pItem->GetStyle() & MISTYLE_WRAPPABLE) { 
				pItem->ModifyState(0, MISTATE_WRAP); 
				++nResult; 
				x = 0; 
			} 
		} 
		else { 
			pItem->ModifyState(MISTATE_WRAP, 0); 
			x += pItem->GetHorizontalSize().cx; 
		} 
	} 
 
	return nResult + 1; 
} 
 
// calc only size, by using m_bWrapped 
CSize CMenuBar::CalcSize(int nCount) 
{ 
	ASSERT(nCount > 0); 
	CPoint cur(0,0); 
	CSize sizeResult(0,0); 
	int nWrap = 0; 
	for (int i = 0; i < nCount; ++i) { 
		CMenuItem* pItem = m_arrItem[i]; 
		sizeResult.cx = max(cur.x + pItem->GetHorizontalSize().cx, sizeResult.cx); 
		sizeResult.cy = max(cur.y + pItem->GetHorizontalSize().cy, sizeResult.cy); 
 
		cur.x += pItem->GetHorizontalSize().cx; 
		 
		if (pItem->GetState() & MISTATE_WRAP) { 
			//LTRACE(_T("    nIndex:%d is wrapped\n"), i); 
			cur.x = 0;// reset x pos 
			cur.y += pItem->GetHorizontalSize().cy; 
			++nWrap; 
		} 
	} 
 
	return sizeResult; 
} 
 
void CMenuBar::Layout() 
{ 
	ASSERT(m_bDelayedButtonLayout); 
 
	m_bDelayedButtonLayout = FALSE; 
 
	BOOL bHorz = (m_dwStyle & CBRS_ORIENT_HORZ) != 0; 
	if ((m_dwStyle & CBRS_FLOATING) && (m_dwStyle & CBRS_SIZE_DYNAMIC)) 
		((CMenuBar*)this)->CalcDynamicLayout(0, LM_HORZ | LM_MRUWIDTH | LM_COMMIT); 
	else if (bHorz) 
		((CMenuBar*)this)->CalcDynamicLayout(0, LM_HORZ | LM_HORZDOCK | LM_COMMIT); 
	else 
		((CMenuBar*)this)->CalcDynamicLayout(0, LM_VERTDOCK | LM_COMMIT); 
} 
 
void CMenuBar::SizeMenuBar(int nLength, BOOL bVert) 
{ 
	//LTRACE("CMenuBar::SizeMenuBar\n"); 
	int nCount = GetItemCount(); ASSERT(nCount > 0); 
 
	if (!bVert) {				// nLength is horizontal length 
 
		if (IsFloating()) {		// half size wrapping 
 
			CSize sizeMax, sizeMin, sizeMid; 
 
			// Wrap MenuBar vertically 
			WrapMenuBar(nCount, 0); 
			sizeMin = CalcSize(nCount); 
 
			// Wrap MenuBar horizontally 
			WrapMenuBar(nCount, 32767); 
			sizeMax = CalcSize(nCount); 
 
			// we can never understand this algorithm :), see CToolBar implementation 
			while (sizeMin.cx < sizeMax.cx) { 
//				LTRACE("looping sizeMin.cx:%d < sizeMax.cx:%d\n", sizeMin.cx, sizeMax.cx); 
				sizeMid.cx = (sizeMin.cx + sizeMax.cx) / 2; 
				WrapMenuBar(nCount, sizeMid.cx); 
				sizeMid = CalcSize(nCount); 
				if (sizeMid.cx == sizeMax.cx) {	// if you forget, it loops forever! 
					return; 
				} 
//				LTRACE("    sizeMid : %d %d\n", sizeMid.cx, sizeMid.cy); 
 
				if (nLength >= sizeMax.cx) { 
//					LTRACE("    nLength:%d >= sizeMax.cx:%d\n", nLength, sizeMax.cx); 
					if (sizeMin == sizeMid) { 
						WrapMenuBar(nCount, sizeMax.cx); 
//						LTRACE("out SizeMenuBar\n"); 
						return; 
					} 
					sizeMin = sizeMid; 
				} 
				else if (nLength < sizeMax.cx) { 
//					LTRACE("    nLength:%d < sizeMax.cx:%d\n", nLength, sizeMax.cx); 
					sizeMax = sizeMid; 
				} 
				else { 
//					LTRACE("out SizeMenuBar\n"); 
					return; 
				} 
			} 
		} 
		else {								// each one wrapping 
			//LTRACE("    just each one wrapping\n"); 
			WrapMenuBar(nCount, nLength); 
		} 
	} 
	else {						// nLength is vertical length 
		CSize sizeMax, sizeMin, sizeMid; 
 
		// Wrap MenuBar vertically 
		WrapMenuBar(nCount, 0); 
		sizeMin = CalcSize(nCount); 
 
		// Wrap MenuBar horizontally 
		WrapMenuBar(nCount, 32767); 
		sizeMax = CalcSize(nCount); 
 
		while (sizeMin.cx < sizeMax.cx) { 
			sizeMid.cx = (sizeMin.cx + sizeMax.cx) / 2; 
			WrapMenuBar(nCount, sizeMid.cx); 
			sizeMid = CalcSize(nCount); 
			if (sizeMid.cx == sizeMax.cx) { 
				return; 
			} 
			if (nLength < sizeMid.cy) { 
				if (sizeMin == sizeMid) { 
					WrapMenuBar(nCount, sizeMax.cx); 
					//LTRACE("out SizeMenuBar\n"); 
					return; 
				} 
				sizeMin = sizeMid; 
			} 
			else if (nLength > sizeMid.cy) 
				sizeMax = sizeMid; 
			else { 
				//LTRACE("out SizeMenuBar\n"); 
				return; 
			} 
		} 
	} 
 
	//LTRACE("out SizeMenuBar\n"); 
} 
 
CSize CMenuBar::CalcVertDockSize(int nCount) 
{ 
	ASSERT(nCount > 0); 
	CSize sizeResult(0, 0); 
 
	for (int i = 0; i < nCount; ++i) { 
		CMenuItem* pItem = m_arrItem[i]; 
		sizeResult.cy += pItem->GetRect().Height(); 
	} 
 
	sizeResult.cx = _cyMenuOnBar; 
	return sizeResult; 
} 
 
void CMenuBar::CalcItemLayout(int nCount, BOOL bVert) 
{ 
	ASSERT(nCount > 0); 
	int x = 0; int y = 0; 
 
	if (!bVert) { 
		for (int i = 0; i < nCount; ++i) { 
			CMenuItem* pItem = m_arrItem[i]; 
			CPoint ptItem(x, y); 
			pItem->Layout(ptItem, TRUE);// layout by itself! 
			if (pItem->GetState() & MISTATE_WRAP) { 
				x = 0;// reset x to 0 
				y += pItem->GetRect().Height(); 
			} 
			else 
				x += pItem->GetRect().Width(); 
		}		 
	} 
	else { 
		for (int i = 0; i < nCount; ++i) { 
			CMenuItem* pItem = m_arrItem[i]; 
			CPoint	ptItem(0, y); 
			pItem->Layout(ptItem, FALSE);	// layout by itself 
			y += pItem->GetRect().Height(); 
		} 
	} 
} 
 
////////////////////////////////////////////////////////////////////// 
// Added by Koay Kah Hoe. Thanx! 
void CMenuBar::OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler) 
{ 
//	LTRACE(_T("CMenuBar::OnUpdateCmdUI\n")); 
	/* 
	// if mouse out of frame window, OnUpdateCmdUI never called... 
	if (m_nTrackingState == buttonmouse) { 
		CPoint pt; ::GetCursorPos(&pt); 
		CRect rect; 
		GetWindowRect(&rect); 
 
		if (!rect.PtInRect(pt)) 
			UpdateBar(); 
	} 
	*/ 
 
	// but thanks to Koay Kah Hoe, 
	// I've found it's nice place for checking child window status. 
	if (m_bMDIApp) 
		CheckActiveChildWndMaximized(); 
} 
 
////////////////////////////////////////////////////////////////////// 
// CMenuBar decoration 
void CMenuBar::EraseNonClientEx() 
{ 
	// get window DC that is clipped to the non-client area 
	CWindowDC dc(this); 
	CRect rectClient; 
	GetClientRect(rectClient); 
	CRect rectWindow; 
	GetWindowRect(rectWindow); 
	ScreenToClient(rectWindow); 
	rectClient.OffsetRect(-rectWindow.left, -rectWindow.top); 
	dc.ExcludeClipRect(rectClient); 
 
	// draw borders in non-client area 
	rectWindow.OffsetRect(-rectWindow.left, -rectWindow.top); 
 
	if (m_dwExStyle & CBRS_RAISEDBORDER) 
		DrawRaisedBorders(&dc, rectWindow); 
	else 
		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 components 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){ 
		DrawPressed(pDC); 
	} 
	else { 
		DrawNone(pDC); 
	} 
} 
 
void CMenuButton::TrackPopup(CWnd* pBar, CWnd* pWndSentCmd) 
{ 
	LTRACE(_T("CMenuButton::TrackPopup\n")); 
	ASSERT_VALID(pBar); 
	ASSERT(!(m_fsState & MISTATE_HIDDEN)); 
	CMenuBar* pMenuBar = STATIC_DOWNCAST(CMenuBar, pBar); 
	ASSERT_VALID(pMenuBar); 
 
	// "! menu" (no sub menu) 
	if (!m_hSubMenu) { 
		ASSERT(m_nID != -1); 
		pWndSentCmd->SendMessage(WM_COMMAND, (WPARAM)m_nID, (LPARAM)pBar->GetSafeHwnd());		 
		return; 
	} 
 
	CRect rcItem(m_rcItem);	pMenuBar->ClientToScreen(rcItem); 
	UINT fuFlags; TPMPARAMS tpm; 
	CPoint pt = _ComputeMenuTrackPoint(rcItem, pMenuBar->GetBarStyle(), fuFlags, tpm); 
 
	if (m_hSubMenu == pMenuBar->m_hWindowMenu) 
		_bWindowMenuSendCmd = TRUE; 
	else 
		_bWindowMenuSendCmd = FALSE; 
 
	::TrackPopupMenuEx(m_hSubMenu, fuFlags, 
		pt.x, pt.y, pWndSentCmd->GetSafeHwnd(), &tpm); 
} 
 
void CMenuButton::DrawHorzText(CDC* pDC, CPoint ptOffset) 
{ 
	COLORREF clr = (m_fsState & MISTATE_INACTIVE) ?  
		::GetSysColor(COLOR_GRAYTEXT) : ::GetSysColor(COLOR_MENUTEXT); 
	pDC->SetTextColor(clr); 
 
	CRect rcBtn = m_rcItem; 
	pDC->SetBkMode(TRANSPARENT); 
	CFont* pOldFont = pDC->SelectObject(&_fontHorzMenu); 
	// I know precise text size, but better to leave this job to Windows 
	// *****fixed by andi, thanks!***** 
	pDC->DrawText(m_strBtn, rcBtn + ptOffset, 
		DT_SINGLELINE | DT_CENTER | DT_VCENTER); 
	 
	pDC->SelectObject(pOldFont); 
} 
 
void CMenuButton::DrawVertText(CDC* pDC, CPoint ptOffset) 
{ 
	COLORREF clr = (m_fsState & MISTATE_INACTIVE) ?  
		::GetSysColor(COLOR_GRAYTEXT) : ::GetSysColor(COLOR_MENUTEXT); 
	pDC->SetTextColor(clr); 
 
	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)); 
 
	// fixed for WinNT. *****fixed by Simon, thanks!***** 
	int iGraphicsMode = ::GetGraphicsMode(pDC->m_hDC); 
	::SetGraphicsMode(pDC->m_hDC, GM_ADVANCED); 
 
	pDC->SetBkMode(TRANSPARENT); 
	CFont* pOldFont = pDC->SelectObject(&_fontVertMenu); 
	// I 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); 
 
	// CDC::DrawText is poor, so we have to draw vertical line by ourselves 
	CPen pen(PS_SOLID, 0, clr); 
	CPen* pOldPen = pDC->SelectObject(&pen); 
 
	pDC->MoveTo(rcBtn.TopLeft() + m_ptLineFrom + ptOffset); 
	pDC->LineTo(rcBtn.TopLeft() + m_ptLineTo + ptOffset); 
 
	pDC->SelectObject(pOldPen); 
	::SetGraphicsMode( pDC->m_hDC, iGraphicsMode ); 
} 
 
void CMenuButton::DrawHot(CDC* pDC) 
{ 
	if (m_fsState & MISTATE_HORZ) { 
		// draw pressed button 
		pDC->DrawEdge(m_rcItem, BDR_RAISEDINNER, BF_RECT); 
		DrawHorzText(pDC); 
	} 
	else { 
		pDC->DrawEdge(m_rcItem, BDR_RAISEDINNER, BF_RECT); 
		DrawVertText(pDC); 
	} 
} 
 
void CMenuButton::DrawPressed(CDC* pDC) 
{ 
	if (m_fsState & MISTATE_HORZ) { 
		pDC->DrawEdge(m_rcItem, BDR_SUNKENOUTER, BF_RECT);// draw pressed button 
		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_fsState & MISTATE_HORZ) { 
		DrawHorzText(pDC); 
	} 
	else { 
		DrawVertText(pDC); 
	} 
} 
 
////////////////////////////////////////////////////////////////////// 
// CMenuIcon class 
CMenuIcon::CMenuIcon(CWnd* pMenuBar) 
{ 
	ASSERT_VALID(pMenuBar); 
	m_pMenuBar = pMenuBar; 
	m_hIconWinLogo = AfxGetApp()->LoadStandardIcon(IDI_WINLOGO); 
	ASSERT(m_hIconWinLogo); 
 
	m_fsStyle |= MISTYLE_TRACKABLE; 
	m_fsState |= MISTATE_HIDDEN; 
	m_sizeHorz = CSize(::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON)); 
} 
 
CMenuIcon::~CMenuIcon() 
{ 
	if (m_hIconWinLogo != NULL) 
		::FreeResource(m_hIconWinLogo); 
} 
 
void CMenuIcon::OnActivateChildWnd() 
{ 
	//LTRACE(_T("CMenuIcon::OnActivateChildWnd\n")); 
 
	ASSERT_VALID(m_pMenuBar); 
	 
	CWnd* pFrame = m_pMenuBar->GetTopLevelFrame(); 
	ASSERT_VALID(pFrame); 
	CMDIFrameWnd* pMDIFrame = STATIC_DOWNCAST(CMDIFrameWnd, pFrame); 
	HWND hWndMDIClient = pMDIFrame->m_hWndMDIClient; 
	ASSERT(::IsWindow(hWndMDIClient)); 
 
	BOOL bMaximized = FALSE; 
	HWND hWndChild = (HWND)::SendMessage(hWndMDIClient, 
		WM_MDIGETACTIVE, 0, (LPARAM)&bMaximized); 
 
	if (bMaximized == FALSE) { 
		//LTRACE(_T("    not maximized\n")); 
		m_fsState |= MISTATE_HIDDEN; 
	} 
	else { 
		//LTRACE(_T("    maximized\n")); 
		m_fsState &= ~MISTATE_HIDDEN; 
	} 
 
	m_hDocIcon = (HICON)::GetClassLong(hWndChild, GCL_HICONSM); 
 
	if (m_hDocIcon == NULL) // if hWndChild doesn't have own icon 
		m_hDocIcon = m_hIconWinLogo; 
} 
 
void CMenuIcon::Update(CDC* pDC) 
{ 
	if (m_fsState & MISTATE_HIDDEN) 
		return; 
 
	ASSERT(m_hDocIcon); 
	ASSERT(m_rcItem.IsRectEmpty() == FALSE); 
	::DrawIconEx(pDC->m_hDC, m_rcItem.left, m_rcItem.top, m_hDocIcon, 
		m_rcItem.Width(), m_rcItem.Height(), 0, NULL, DI_NORMAL); 
} 
 
void CMenuIcon::TrackPopup(CWnd* /*pBar*/, CWnd* pWndSentCmd) 
{ 
	ASSERT(!(m_fsState & MISTATE_HIDDEN)); 
	ASSERT_VALID(m_pMenuBar); 
	 
	CWnd* pFrame = m_pMenuBar->GetTopLevelFrame(); 
	ASSERT_VALID(pFrame); 
	CMDIFrameWnd* pMDIFrame = STATIC_DOWNCAST(CMDIFrameWnd, pFrame); 
	HWND hWndMDIClient = pMDIFrame->m_hWndMDIClient; 
	ASSERT(::IsWindow(hWndMDIClient)); 
 
	BOOL bMaximized = FALSE; 
	HWND hWndChild = (HWND)::SendMessage(hWndMDIClient, 
		WM_MDIGETACTIVE, 0, (LPARAM)&bMaximized); 
	ASSERT(bMaximized); 
	HMENU hSysMenu = ::GetSystemMenu(hWndChild, FALSE); 
	ASSERT(::IsMenu(hSysMenu));	 
 
	CControlBar* pControlBar = STATIC_DOWNCAST(CControlBar, m_pMenuBar); 
	ASSERT_VALID(pControlBar); 
	CRect rcItem(m_rcItem);	m_pMenuBar->ClientToScreen(rcItem); 
	UINT fuFlags; TPMPARAMS tpm; 
	CPoint pt = _ComputeMenuTrackPoint(rcItem, pControlBar->GetBarStyle(), fuFlags, tpm); 
 
	::TrackPopupMenuEx(hSysMenu, fuFlags, pt.x, pt.y, pWndSentCmd->GetSafeHwnd(), &tpm); 
} 
 
void CMenuIcon::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; 
	} 
	 
	m_rcItem = CRect(point, CSize(::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON))); 
} 
 
////////////////////////////////////////////////////////////////////// 
// CMenuControl class 
#define CX_GAP_CAPTION 2 
 
CMenuControl::CMenuControl(CWnd* pMenuBar) 
{ 
	ASSERT_VALID(pMenuBar); 
	m_pMenuBar = pMenuBar; 
	m_bDown = FALSE; 
	m_nTracking = -1; 
 
	m_fsState |= MISTATE_HIDDEN; 
 
	CSize sizeCaption = GetCaptionSize(); 
	m_sizeHorz = CSize(sizeCaption.cx*3 + CX_GAP_CAPTION + 1, sizeCaption.cy + 2); 
} 
 
void CMenuControl::Update(CDC* pDC) 
{ 
	// do nothing 
} 
 
void CMenuControl::Layout(CPoint point, BOOL bHorz) 
{ 
	//LTRACE(_T("CMenuControl::Layout bHorz:%d\n"), bHorz); 
 
	if (bHorz) 
		m_fsState |= MISTATE_HORZ; 
	else 
		m_fsState &= ~MISTATE_HORZ; 
 
	if (m_fsState & MISTATE_HIDDEN) { 
		m_rcItem.SetRectEmpty(); 
		return; 
	} 
 
	// just layout easily 
	if (bHorz) { 
		m_rcItem = CRect(point, m_sizeHorz); 
	} 
	else { 
		m_rcItem = CRect(point, CSize(m_sizeHorz.cy, m_sizeHorz.cx)); 
	} 
} 
 
void CMenuControl::DelayLayoutAndDraw(CDC* pDC, CSize sizeBar) 
{ 
	//LTRACE(_T("CMenuControl::DelayLayoutAndDraw\n")); 
	//LTRACE(_T("    %d, %d\n"), sizeBar.cx, sizeBar.cy); 
	// layout 
	CSize sizeCaption = GetCaptionSize(); 
	int cxCaption = sizeCaption.cx; 
	int cyCaption = sizeCaption.cy; 
 
	if (m_fsState & MISTATE_HORZ) { 
		CRect rcCaption; 
		rcCaption.right = sizeBar.cx; 
		rcCaption.bottom = sizeBar.cy; 
		rcCaption.left = rcCaption.right - cxCaption; 
		rcCaption.top = rcCaption.bottom - cyCaption; 
 
		m_arrCaption[0] = rcCaption; 
 
		rcCaption -= CPoint(cxCaption+CX_GAP_CAPTION, 0); 
		m_arrCaption[1] = rcCaption; 
 
		rcCaption -= CPoint(cxCaption, 0); 
		m_arrCaption[2] = rcCaption; 
 
		m_rcItem = CRect(m_arrCaption[2].left, m_arrCaption[2].top, 
			m_arrCaption[0].right, m_arrCaption[0].bottom); 
	} 
	else { 
		CRect rcCaption; 
		rcCaption.left = 0; 
		rcCaption.bottom = sizeBar.cy; 
		rcCaption.right = rcCaption.left + cxCaption; 
		rcCaption.top = rcCaption.bottom - cyCaption; 
 
		m_arrCaption[0] = rcCaption;	 
 
		rcCaption -= CPoint(0, cyCaption+CX_GAP_CAPTION); 
		m_arrCaption[1] = rcCaption; 
 
		rcCaption -= CPoint(0, cyCaption); 
		m_arrCaption[2] = rcCaption; 
 
		m_rcItem = CRect(m_arrCaption[2].left, m_arrCaption[2].top, 
			m_arrCaption[0].right, m_arrCaption[0].bottom); 
	} 
 
	if (m_fsState & MISTATE_HIDDEN) { 
		//LTRACE(_T("    hidden\n")); 
		return; 
	} 
 
	// draw frame controls 
	for (int i = 0; i < 3; ++i) { 
		DrawControl(pDC, i, FALSE); 
	}	 
} 
 
BOOL CMenuControl::OnMouseMsg(UINT msg, UINT nFlags, CPoint pt) 
{ 
	if (m_fsState & MISTATE_HIDDEN) 
		return FALSE; 
 
	if (msg == WM_LBUTTONDOWN) { 
		//LTRACE(_T("    WM_LBUTTONDOWN\n")); 
		m_nTracking = HitTest(pt); 
		if (m_nTracking >= 0) { 
			CClientDC dc(m_pMenuBar); 
			DrawControl(&dc, m_nTracking, TRUE); 
			m_bDown = TRUE; 
			m_pMenuBar->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_pMenuBar); 
			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_pMenuBar); 
			DrawControl(&dc, m_nTracking, FALSE); 
			CFrameWnd* pFrame = m_pMenuBar->GetTopLevelFrame()->GetActiveFrame(); 
			ASSERT_VALID(pFrame); 
			static int syscmd[3] = 
			{ /*SC_MOUSEMENU,*/ SC_CLOSE, SC_RESTORE, SC_MINIMIZE }; 
			// SendMessage occur access violation! 
			// *****fixed by Koay Kah Hoe. Thanks!***** 
			pFrame->PostMessage(WM_SYSCOMMAND, syscmd[m_nTracking]); 
		} 
		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) 
{ 
	//LTRACE(_T("CMenuControl::DrawControl\n")); 
	// draw frame controls 
	CRect& rc = m_arrCaption[nIndex]; 
	//LTRACE(_T("    %d, %d, %d, %d\n"), rc.left, rc.top, rc.right, rc.bottom); 
	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 (m_fsState & MISTATE_HIDDEN) 
		return; 
 
	for (int i = 0; i < 3; ++i) { 
		DrawControl(pDC, i, FALSE); 
	} 
} 
 
void CMenuControl::OnActivateChildWnd() 
{ 
	//LTRACE(_T("CMenuControl::OnActivateChildWnd\n")); 
	ASSERT_VALID(m_pMenuBar); 
	 
	CWnd* pFrame = m_pMenuBar->GetTopLevelFrame(); 
	ASSERT_VALID(pFrame); 
	CMDIFrameWnd* pMDIFrame = STATIC_DOWNCAST(CMDIFrameWnd, pFrame); 
	HWND hWndMDIClient = pMDIFrame->m_hWndMDIClient; 
	ASSERT(::IsWindow(hWndMDIClient)); 
 
	BOOL bMaximized = FALSE; 
	HWND hWndChild = (HWND)::SendMessage(hWndMDIClient, 
		WM_MDIGETACTIVE, 0, (LPARAM)&bMaximized); 
 
	if (bMaximized == FALSE) { 
		m_fsState |= MISTATE_HIDDEN; 
	} 
	else { 
		m_fsState &= ~MISTATE_HIDDEN; 
	} 
} 
 
CSize CMenuControl::GetCaptionSize() 
{ 
	NONCLIENTMETRICS info; info.cbSize = sizeof(info); 
	::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0); 
 
	// due to my own feeling 
	return CSize(info.iMenuHeight - info.iBorderWidth*2, info.iMenuHeight - info.iBorderWidth*4); 
} 
 
#if _MFC_VER < 0x0600 
void CMenuBar::SetBorders(int cxLeft, int cyTop, int cxRight, int cyBottom) 
{ 
	ASSERT(cxLeft >= 0); 
	ASSERT(cyTop >= 0); 
	ASSERT(cxRight >= 0); 
	ASSERT(cyBottom >= 0); 
 
	m_cxLeftBorder = cxLeft; 
	m_cyTopBorder = cyTop; 
	m_cxRightBorder = cxRight; 
	m_cyBottomBorder = cyBottom; 
} 
#endif 
 
void CMenuBar::_DrawGripper(CDC* pDC, const CRect& rect) 
{ 
	COLORREF clrBtnHilite = ::GetSysColor(COLOR_BTNHILIGHT); 
	COLORREF clrBtnShadow = ::GetSysColor(COLOR_BTNSHADOW); 
 
	BOOL bDrawGripper = !(m_dwStyle & CBRS_FLOATING) && (m_dwExStyle & CBRS_GRIPPER); 
 
	// only draw the gripper if not floating and gripper is specified 
	if (bDrawGripper) 
	{ 
		// draw the gripper in the border 
		if (m_dwStyle & CBRS_ORIENT_HORZ) 
		{ 
			if (bDrawGripper) { 
				pDC->Draw3dRect(rect.left+CX_BORDER_GRIPPER, 
					rect.top+m_cyTopBorder, 
					CX_GRIPPER, rect.Height()-m_cyTopBorder-m_cyBottomBorder, 
					clrBtnHilite, clrBtnShadow); 
			}		 
		} 
		else 
		{ 
			if (bDrawGripper) { 
				pDC->Draw3dRect(rect.left+m_cyTopBorder, 
					rect.top+CY_BORDER_GRIPPER, 
					rect.Width()-m_cyTopBorder-m_cyBottomBorder, CY_GRIPPER, 
					clrBtnHilite, clrBtnShadow); 
			} 
		} 
	} 
} 
 
// input CRect should be client rectangle size 
void CMenuBar::_CalcInsideRect(CRect& rect, BOOL bHorz) const 
{ 
	LTRACE(_T("CMenuBar::_CalcInsideRect\n")); 
	ASSERT_VALID(this); 
	DWORD dwStyle = m_dwStyle; 
 
	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; 
 
	BOOL bDrawGripper = !(m_dwStyle & CBRS_FLOATING) && (m_dwExStyle & CBRS_GRIPPER); 
 
	// inset the top and bottom. 
	if (bHorz) 
	{ 
		rect.left += m_cxLeftBorder; 
		rect.top += m_cyTopBorder; 
		rect.right -= m_cxRightBorder; 
		rect.bottom -= m_cyBottomBorder; 
		if (bDrawGripper) 
			rect.left += CX_GRIPPER_ALL; 
	} 
	else 
	{ 
		rect.left += m_cyTopBorder; 
		rect.top += m_cxLeftBorder; 
		rect.right -= m_cyBottomBorder; 
		rect.bottom -= m_cxRightBorder; 
		if (bDrawGripper) 
			rect.top += CY_GRIPPER_ALL; 
	} 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// CMenuDockBar implementation 
// a little changed from CDockBar implementation 
 
static BOOL _IsMenuBar(int nPos, CPtrArray& arrBars) 
{ 
	if (nPos < arrBars.GetSize()) { 
		CControlBar* pBar = (CControlBar*)arrBars[nPos]; 
		if (pBar && pBar->GetDlgCtrlID() == AFX_IDW_MENUBAR) 
			return TRUE; 
		else 
			return FALSE; 
	} 
	else 
		return FALSE; 
} 
 
CSize CMenuDockBar::CalcFixedLayout(BOOL bStretch, BOOL bHorz) 
{ 
	LTRACE(_T("CMenuDockBar::CalcFixedLayout\n")); 
	ASSERT_VALID(this); 
 
	CSize sizeFixed = CControlBar::CalcFixedLayout(bStretch, bHorz); 
 
	// get max size 
	CSize sizeMax; 
	if (!m_rectLayout.IsRectEmpty()) 
		sizeMax = m_rectLayout.Size(); 
	else 
	{ 
		CRect rectFrame; 
		CFrameWnd* pFrame = GetParentFrame(); 
		pFrame->GetClientRect(&rectFrame); 
		sizeMax = rectFrame.Size(); 
	} 
 
	// prepare for layout 
	AFX_SIZEPARENTPARAMS layout; 
	layout.hDWP = m_bLayoutQuery ? 
		NULL : ::BeginDeferWindowPos(m_arrBars.GetSize()); 
	CPoint pt(-cxBorder2, -cyBorder2); 
	int nWidth = 0; 
 
	BOOL bWrapped = FALSE; 
 
	// layout all the control bars 
	for (int nPos = 0; nPos < m_arrBars.GetSize(); nPos++) 
	{ 
		CControlBar* pBar = GetDockedControlBar(nPos); 
		void* pVoid = m_arrBars[nPos]; 
 
		if (pBar != NULL)// pBar is valid 
		{ 
			if (pBar->IsVisible())// visible 
			{ 
				// get ideal rect for bar 
				DWORD dwMode = 0; 
				if ((pBar->m_dwStyle & CBRS_SIZE_DYNAMIC) && 
					(pBar->m_dwStyle & CBRS_FLOATING)) 
					dwMode |= LM_HORZ | LM_MRUWIDTH; 
				else if (pBar->m_dwStyle & CBRS_ORIENT_HORZ) 
					dwMode |= LM_HORZ | LM_HORZDOCK; 
				else 
					dwMode |=  LM_VERTDOCK; 
 
				CSize sizeBar = pBar->CalcDynamicLayout(-1, dwMode); 
 
				CRect rect(pt, sizeBar); 
 
				// get current rect for bar 
				CRect rectBar; 
				pBar->GetWindowRect(&rectBar); 
				ScreenToClient(&rectBar); 
 
				if (bHorz)// horizontal 
				{ 
					// Offset Calculated Rect out to Actual 
					if (rectBar.left > rect.left && !m_bFloating) 
						rect.OffsetRect(rectBar.left - rect.left, 0); 
 
					// If ControlBar goes off the right, then right justify 
					if (rect.right > sizeMax.cx && !m_bFloating) 
					{ 
						int x = rect.Width() - cxBorder2; 
						x = max(sizeMax.cx - x, pt.x); 
						rect.OffsetRect(x - rect.left, 0); 
					} 
 
					// If ControlBar has been wrapped, then left justify 
					if (bWrapped) 
					{ 
						bWrapped = FALSE; 
						rect.OffsetRect(-(rect.left + cxBorder2), 0); 
					} 
					// If ControlBar is completely invisible, then wrap it 
					else if ((rect.left >= (sizeMax.cx - cxBorder2) || _IsMenuBar(nPos, m_arrBars)) 
						&& (nPos > 0) && (m_arrBars[nPos - 1] != NULL)) 
					{ 
						m_arrBars.InsertAt(nPos, (CObject*)NULL); 
						pBar = NULL; pVoid = NULL; 
						bWrapped = TRUE; 
					} 
					if (!bWrapped) 
					{ 
						if (rect != rectBar) 
						{ 
							if (!m_bLayoutQuery && 
								!(pBar->m_dwStyle & CBRS_FLOATING)) 
							{ 
								pBar->m_pDockContext->m_rectMRUDockPos = rect; 
							} 
							AfxRepositionWindow(&layout, pBar->m_hWnd, &rect); 
						} 
						pt.x = rect.left + sizeBar.cx - cxBorder2; 
						nWidth = max(nWidth, sizeBar.cy); 
					} 
				} 
				else	// vertical 
				{ 
					// Offset Calculated Rect out to Actual 
					if (rectBar.top > rect.top && !m_bFloating) 
						rect.OffsetRect(0, rectBar.top - rect.top); 
 
					// If ControlBar goes off the bottom, then bottom justify 
					if (rect.bottom > sizeMax.cy && !m_bFloating) 
					{ 
						int y = rect.Height() - cyBorder2; 
						y = max(sizeMax.cy - y, pt.y); 
						rect.OffsetRect(0, y - rect.top); 
					} 
 
					// If ControlBar has been wrapped, then top justify 
					if (bWrapped) 
					{ 
						bWrapped = FALSE; 
						rect.OffsetRect(0, -(rect.top + cyBorder2)); 
					} 
					// If ControlBar is completely invisible, then wrap it 
					else if ((rect.top >= (sizeMax.cy - cyBorder2) || _IsMenuBar(nPos, m_arrBars)) 
						&& (nPos > 0) && (m_arrBars[nPos - 1] != NULL)) 
					{ 
						m_arrBars.InsertAt(nPos, (CObject*)NULL); 
						pBar = NULL; pVoid = NULL; 
						bWrapped = TRUE; 
					} 
 
					if (!bWrapped) 
					{ 
						if (rect != rectBar) 
						{ 
							if (!m_bLayoutQuery && 
								!(pBar->m_dwStyle & CBRS_FLOATING)) 
							{ 
								pBar->m_pDockContext->m_rectMRUDockPos = rect; 
							} 
							AfxRepositionWindow(&layout, pBar->m_hWnd, &rect); 
						} 
						pt.y = rect.top + sizeBar.cy - cyBorder2; 
						nWidth = max(nWidth, sizeBar.cx); 
					} 
				}// if vertical 
			}// if visible 
			if (!bWrapped) 
			{ 
				// handle any delay/show hide for the bar 
				pBar->RecalcDelayShow(&layout); 
			} 
		}// if pBar is valid 
		if (pBar == NULL && pVoid == NULL && nWidth != 0) 
		{ 
			// end of row because pBar == NULL 
			if (bHorz) 
			{ 
				pt.y += nWidth - cyBorder2; 
				sizeFixed.cx = max(sizeFixed.cx, pt.x); 
				sizeFixed.cy = max(sizeFixed.cy, pt.y); 
				pt.x = -cxBorder2; 
			} 
			else 
			{ 
				pt.x += nWidth - cxBorder2; 
				sizeFixed.cx = max(sizeFixed.cx, pt.x); 
				sizeFixed.cy = max(sizeFixed.cy, pt.y); 
				pt.y = -cyBorder2; 
			} 
			nWidth = 0; 
		} 
	}// for 
	if (!m_bLayoutQuery) 
	{ 
		// move and resize all the windows at once! 
		if (layout.hDWP == NULL || !::EndDeferWindowPos(layout.hDWP)) 
			TRACE0("Warning: DeferWindowPos failed - low system resources.\n"); 
	} 
 
	// adjust size for borders on the dock bar itself 
	CRect rect; 
	rect.SetRectEmpty(); 
	CalcInsideRect(rect, bHorz); 
 
	if ((!bStretch || !bHorz) && sizeFixed.cx != 0) 
		sizeFixed.cx += -rect.right + rect.left; 
	if ((!bStretch || bHorz) && sizeFixed.cy != 0) 
		sizeFixed.cy += -rect.bottom + rect.top; 
 
	return sizeFixed; 
}