MenuBar.cpp
上传用户:liudazhe
上传日期:2007-01-02
资源大小:51k
文件大小:58k
- // MenuBar.cpp :
- //
- #include "stdafx.h"
- #include "MenuBar.h"
- #include "resource.h"
- #include <afxpriv.h>
- // pasted from MFC source
- #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)
- //}}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 |
- 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))) {
- 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()) {
- TRACE("Failed to create bar resourcen");
- 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) {
- TRACE("Failed to load menun");
- 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::LoadMenun");
- 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);
- }
- /////////////////////////////////////////////////////////////////////////////
- // 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=%dn"),
- // 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::OnLButtonDownn");
- 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::OnMouseMoven");
- 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);
- }
- 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 = TRUEn");
- m_bIgnoreAlt = TRUE; // next SysKeyUp will be ignored
- break;
- }
- return FALSE; // pass along...
- }
- BOOL CMenuBar::TranslateFrameMessage(MSG* pMsg)
- {
- ASSERT_VALID(this);
- ASSERT(pMsg);
- 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(" ignore ALT key upn");
- m_bIgnoreAlt = FALSE;
- break;
- }
- UpdateBar(button, GetNextOrPrevButton(0, FALSE));
- 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) && isalnum(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) {
- TCHAR cKey;
- if (m_arrItem[i]->GetAccessKey(cKey) == TRUE &&
- cKey == cAccessKey) {
- nIndex = i;
- return TRUE;
- }
- }
- return FALSE;
- }
- /////////////////////////////////////////////////////////////////////////////
- // CMenuBar layout
- // calculate only layout from m_bWrapped
- void CMenuBar::CalcFloatingLayout()
- {
- ASSERT_VALID(this);
- ASSERT(::IsWindow(m_hWnd));
- int xStart = CXGAP;
- if (!IsFloating()) {
- xStart += CXGRIPPER;
- }
- int xOffset = xStart;
- int yOffset = CYGAP;
- for (int i = 0; i < GetItemCount(); ++i) {
- CMenuItem* pItem = m_arrItem[i];
- if (pItem->IsValid()) {
- CPoint ptItem(xOffset, yOffset);
- pItem->Layout(ptItem, TRUE); // layout by itself!
- if (pItem->m_bWrapped == TRUE) {
- xOffset = xStart; // reset xOffset
- yOffset += pItem->m_sizeHorz.cy;
- }
- else
- xOffset += pItem->m_sizeHorz.cx;
- }
- }
- }
- // calulate ordinary layout and size without m_bWrapped
- CSize CMenuBar::CalcLayout(DWORD dwMode, int nLength)
- {
- ASSERT_VALID(this);
- ASSERT(::IsWindow(m_hWnd));
- if (dwMode & LM_HORZDOCK)
- ASSERT(dwMode & LM_HORZ);
- CSize sizeResult(0, 0);
- if (!(dwMode & LM_HORZ)) { // if vertical
- int yOffset = CXGAP;
- if (!IsFloating())
- yOffset += CXGRIPPER;
- for (int i = 0; i < GetItemCount(); ++i) {
- CMenuItem* pItem = m_arrItem[i];
- if (pItem->IsValid()) {
- CPoint ptItem(CYGAPVERT, yOffset);
- pItem->Layout(ptItem, FALSE); // layout by itself
- yOffset += pItem->m_rcItem.Height();
- }
- }
- int cxBar = max(::GetSystemMetrics(SM_CXSMICON), cyMenuButton + (CYGAPVERT)*2);
- sizeResult = CSize(cxBar, yOffset+CXGAP);
- }
- else { // if horizontal
- int xOffset = CXGAP;
- if (!IsFloating())
- xOffset += CXGRIPPER;
- for (int i = 0; i < GetItemCount(); ++i) {
- CMenuItem* pItem = m_arrItem[i];
- if (pItem->IsValid()) {
- CPoint ptItem(xOffset, CYGAP);
- pItem->Layout(ptItem, TRUE); // layout by itself
- xOffset += pItem->m_rcItem.Width();
- }
- }
- int cyBar = max(::GetSystemMetrics(SM_CYSMICON), cyMenuButton + CYGAP*2);
- sizeResult = CSize(xOffset+CXGAP, cyBar);
- }
- return sizeResult;
- }
- // in fact, it's never called
- CSize CMenuBar::CalcFixedLayout(BOOL bStretch, BOOL bHorz)
- {
- // LTRACE("CMenuBar::CalcFixedLayoutn");
- DWORD dwMode = bStretch ? LM_STRETCH : 0;
- dwMode |= bHorz ? LM_HORZ : 0;
- return CalcLayout(dwMode);
- }
- CSize CMenuBar::CalcDynamicLayout(int nLength, DWORD dwMode)
- {
- LTRACE("CMenuBar::CalcDynamicLayoutn");
- // Who can understand what "dwMode" means?
- //
- // If you want it be pricisely same as DevStudio style,
- // I think you have to create a "CDockContext" derived class.
- // This is the reason why everyone think "CControlBar class" junk ?
- ASSERT_VALID(this);
- ASSERT_VALID(m_pDockSite);
- ASSERT_VALID(m_pDockBar);
- if (m_hMenu == NULL) // if have no menu yet, just return
- return CSize(0, 0);
- if (IsFloating()) {
- CFrameWnd* pFrame = GetParentFrame();
- ASSERT_VALID(pFrame);
- CMenu* pSysMenu = pFrame->GetSystemMenu(FALSE);
- ASSERT_VALID(pSysMenu);
- pSysMenu->EnableMenuItem(SC_CLOSE, MF_BYCOMMAND | MF_DISABLED);
- }
- if (dwMode & LM_HORZ) { // horizontal
- // LTRACE(" horizontaln");
- if (dwMode & LM_HORZDOCK) {
- if (IsFloating() || (m_dwStyle & CBRS_ORIENT_VERT)) { // if Floating->Docking, return min size
- // LTRACE(" return min sizen");
- return CalcLayout(dwMode);
- }
- else {
- if (m_pDockContext->m_pDC) { // now dragging
- // return DockBar size
- //LTRACE(" now dragging, so calc with DockBarn");
- CSize size = CalcSize(GetItemCount());//CalcLayout(dwMode);
- CRect rcFrame;
- m_pDockBar->GetWindowRect(rcFrame);
- CRect rcBar;
- GetWindowRect(rcBar);
- rcBar.right = rcFrame.right;
- return CSize(rcBar.Width() + cxBorder2, size.cy);
- }
- else {
- //LTRACE(" no draggin calc bigger sizen");
- CRect rcFrame;
- m_pDockSite->GetWindowRect(rcFrame);
- SizeMenuBar(GetItemCount(), rcFrame.Width() - cxBorder2*2, FALSE);
- CalcFloatingLayout();
- CSize size1 = CalcSize(GetItemCount());
- return CSize(rcFrame.Width(), size1.cy);
- }
- }
- }
- else if (dwMode & LM_MRUWIDTH) { // floating size
- //LTRACE(" return floating sizen");
- SizeMenuBar(GetItemCount(), m_nMRUWidth, FALSE); // load floating Bar Width!
- CalcFloatingLayout();
- return CalcSize(GetItemCount());
- }
- else if (dwMode & LM_COMMIT) {
- //LTRACE(" commit, just calc: %dn", nLength);
- m_nMRUWidth = nLength; // save floating Bar Width!!! (used when SaveBarState)
- CalcFloatingLayout();
- return CSize(0, 0); // MFC does'nt use this Size
- }
- else if (dwMode & LM_LENGTHY) {
- //LTRACE(" nLength is height : %dn", nLength);
- SizeMenuBar(GetItemCount(), nLength, TRUE);
- return CalcSize(GetItemCount());
- }
- else {
- //LTRACE(" nLength is width : %dn", nLength);
- SizeMenuBar(GetItemCount(), nLength, FALSE);
- return CalcSize(GetItemCount());
- }
- ASSERT(TRUE);
- }
- else { // vertical
- InvalidateRect(NULL); // force to repaint!!!
- //LTRACE(" verticaln");
- if (IsFloating() || (m_dwStyle & CBRS_ORIENT_HORZ)) { // if Floating->Docking, return min size
- //LTRACE(" return min sizen");
- return CalcLayout(dwMode);
- }
- else { // return large size
- if (m_pDockContext->m_pDC) { // CDockContext::m_bDragging is not helpful :(
- //LTRACE(" now dragging, so calc with DockBarn");
- CSize size = CalcLayout(dwMode);
- CRect rcFrame;
- m_pDockBar->GetWindowRect(rcFrame);
- CRect rcBar;
- GetWindowRect(rcBar);
- rcBar.bottom = rcFrame.bottom;
- return CSize(size.cx, rcBar.Height());
- }
- else {
- //LTRACE(" no dragging, return biggest sizen");
-
- CSize size = CalcLayout(dwMode);
- CRect rcFrame;
- m_pDockSite->GetWindowRect(rcFrame);
- CRect rcBar;
- GetWindowRect(rcBar);
- rcBar.bottom = rcFrame.bottom;
- return CSize(size.cx, rcFrame.Height());
- }
- }
- }
- ASSERT(TRUE); // never come here
- return CalcLayout(dwMode, nLength);
- }
- void CMenuBar::DrawGripper(CDC* pDC)
- {
- if( (m_dwStyle & CBRS_FLOATING) || m_dwDockStyle == 0 )
- return;
- CRect rcGrip;
- GetClientRect(&rcGrip);
- if(m_dwStyle & CBRS_ORIENT_HORZ) {
- // gripper at left
- rcGrip.DeflateRect(4, 3);
- rcGrip.right = rcGrip.left + 3;
- pDC->DrawEdge(rcGrip, BDR_RAISEDINNER, BF_RECT);
- rcGrip.OffsetRect(4, 0);
- pDC->DrawEdge(rcGrip, BDR_RAISEDINNER, BF_RECT);
- }
- else {
- // gripper at top
- rcGrip.DeflateRect(3, 4);
- rcGrip.bottom = rcGrip.top + 3;
- pDC->DrawEdge(rcGrip, BDR_RAISEDINNER, BF_RECT);
- rcGrip.OffsetRect(0, 4);
- pDC->DrawEdge(rcGrip, BDR_RAISEDINNER, BF_RECT);
- }
- }
- #define CX_BORDER 1
- #define CY_BORDER 1
- void CMenuBar::DrawBorder(CDC* pDC)
- {
- if( (m_dwStyle & CBRS_FLOATING) || m_dwDockStyle == 0 )
- return;
- CRect rect;
- GetClientRect(rect);
- DWORD dwStyle = m_dwStyle;
- if (!(dwStyle & CBRS_BORDER_ANY))
- return;
- CRect rect3 = rect;
- if (m_dwStyle & CBRS_ORIENT_HORZ) {
- rect3.left += cxBorder2;//rect.DeflateRect(2, 0);
- pDC->DrawEdge(rect3, BDR_RAISEDINNER, BF_LEFT);
- }
- else {
- rect3.top += cyBorder2;//rect.DeflateRect(0, 2);
- pDC->DrawEdge(rect3, BDR_RAISEDINNER, BF_TOP);
- }
- // prepare for dark lines
- ASSERT(rect.top == 0 && rect.left == 0);
- CRect rect1, rect2;
- rect1 = rect;
- rect2 = rect;
- COLORREF clr = ::GetSysColor(COLOR_BTNSHADOW);//afxData.bWin4 ? afxData.clrBtnShadow : afxData.clrWindowFrame;
- // 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 += CY_BORDER;//cyBorder2;
- if (dwStyle & CBRS_BORDER_BOTTOM)
- rect2.bottom -= CY_BORDER;
- if (dwStyle & CBRS_BORDER_LEFT)
- rect2.left += CX_BORDER;
- if (dwStyle & CBRS_BORDER_RIGHT)
- rect2.right -= CX_BORDER;
- if (dwStyle & CBRS_BORDER_3D)
- {
- // draw left and top
- if (dwStyle & CBRS_BORDER_LEFT)
- pDC->DrawEdge(rect2, BDR_RAISEDINNER, BF_LEFT);//pDC->FillSolidRect(1, rect2.top, CX_BORDER, rect2.Height(), clr);
- if (dwStyle & CBRS_BORDER_TOP)
- pDC->DrawEdge(rect2, BDR_RAISEDINNER, BF_TOP);//pDC->FillSolidRect(0, 1, rect.right, CY_BORDER, clr);
- // draw right and bottom
- if (dwStyle & CBRS_BORDER_RIGHT)
- pDC->DrawEdge(rect2, BDR_RAISEDINNER, BF_RIGHT);//pDC->FillSolidRect(rect.right, rect2.top, -CX_BORDER, rect2.Height(), clr);
- if (dwStyle & CBRS_BORDER_BOTTOM)
- pDC->DrawEdge(rect2, BDR_RAISEDINNER, BF_BOTTOM);//pDC->FillSolidRect(0, rect.bottom, rect.right, -CY_BORDER, clr);
- }
-
- }
- /////////////////////////////////////////////////////////////////////////////
- // CMenuBarFrameHook implementation
- CMenuBarFrameHook::CMenuBarFrameHook()
- {
- m_pMenuBar = NULL;
- }
- BOOL CMenuBarFrameHook::Install(CMenuBar* pMenuBar, HWND hWndToHook)
- {
- ASSERT_VALID(pMenuBar);
- ASSERT(m_pMenuBar == NULL);
- m_pMenuBar = pMenuBar;
- return HookWindow(hWndToHook);//CWnd::FromHandlePermanent(hWndToHook));
- }
- CMenuBarFrameHook::~CMenuBarFrameHook()
- {
- }
- LRESULT CMenuBarFrameHook::WindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam)
- {
- ASSERT_VALID(m_pMenuBar);
- switch (nMsg) {
- case WM_MENUSELECT:
- m_pMenuBar->OnMenuSelect((HMENU)lParam, (UINT)LOWORD(wParam));
- break;
- // The following messages are trapped for the MDI client window
- case WM_INITMENUPOPUP:
- LTRACE("CMenuBar::WM_INITMENUPOPUPn");
- if (!HIWORD(lParam) && (HMENU)wParam == m_pMenuBar->m_hWindowMenu)
- m_pMenuBar->OnInitMenuPopup();
- break;
- case WM_MDISETMENU: // only sent to MDI client window
- // Setting new frame/window menu: bypass MDI. wParam is new menu.
- if (wParam) {
- LTRACE("CMenuBar::WM_MDISETMENU 0x%04xn", wParam);
- // HMENU hNewMenu = (HMENU)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("CMenuBar::WM_MDIREFRESHMENUn");
- return 0;
- case WM_PAINT:
- // 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->OnPaintMDIClient();//CheckMinMaxState();
- break;
- }
- return CSubclassWnd::WindowProc(nMsg, wParam, lParam);
- }
- void CMenuBar::OnLButtonUp(UINT nFlags, CPoint point)
- {
- //LTRACE("CMenuBar::OnLButtonUpn");
- // TODO:
- ASSERT(m_pMenuControl);
- if (m_pMenuControl->OnMouseMsg(WM_LBUTTONUP, nFlags, point)) {
- CControlBar::OnLButtonUp(nFlags, point);
- return;
- }
- int nIndex = HitTestOnTrack(point);
- /*
- if (IsValidIndex(nIndex) && m_bDown == TRUE) {
- HMENU hSubMenu = ::GetSubMenu(m_hMenu, nIndex);
- if (hSubMenu == NULL) {
- UINT nID = ::GetMenuItemID(m_hMenu, nIndex);
- ASSERT(nID != -1);
- GetOwner()->SendMessage(WM_COMMAND, (WPARAM)nID, (LPARAM)GetSafeHwnd());
- UpdateBar();
- }
- }
- */
- CControlBar::OnLButtonUp(nFlags, point);
- }
- void CMenuBar::DoPaint(CDC* pDC)
- {
- //LTRACE("CMenuBar::DoPaintn");
- CRect rect;
- GetClientRect(rect);
- // draw buttons
- for (int i = 0; i < m_arrItem.GetSize(); ++i) {
- CMenuItem* pItem = m_arrItem[i];
- if (pItem->IsValid())
- m_arrItem[i]->Update(pDC);
- }
- // draw decorations
- DrawGripper(pDC);
- DrawBorder(pDC);
- // draw captions
- if (m_pMenuControl) {
- CRect rcDockBar;
- m_pDockBar->GetClientRect(rcDockBar);
- if (m_dwStyle & CBRS_ORIENT_HORZ) {
- m_pMenuControl->DelayLayoutAndDraw(pDC, CSize(rcDockBar.Width() + cxBorder2, rect.Height()));
- }
- else {
- m_pMenuControl->DelayLayoutAndDraw(pDC, CSize(rect.Width(), rcDockBar.Height()));
- }
- }
- }
- void CMenuBar::_KillTimer()
- {
- if (m_nIDEvent) {
- KillTimer(m_nIDEvent);
- m_nIDEvent = NULL;
- }
- }
- int getPrevValidIndex(int nIndex)
- {
- --nIndex;
- return nIndex;
- }
- // set only m_bWrapped by nWidth
- int CMenuBar::WrapMenuBar(int nCount, int nWidth)
- {
- // LTRACE("CMenuBar::WrapMenuBarn");
- int nResult = 0;
- int xStart = CXGAP;
- if (!IsFloating() && !m_pDockContext->m_pDC) // if not floating and ****not dragging!!!****
- xStart += CXGRIPPER;
-
- int x = xStart;
-
- for (int i = 0; i < nCount; ++i) {
- CMenuItem* pItem = m_arrItem[i];
- if (pItem->IsValid()) {
- if (i+1 == nCount)
- return ++nResult;
-
- if (x + pItem->m_sizeHorz.cx + CXGAP> nWidth) {// itself is over
- if (pItem->CanWrap()) {
- pItem->m_bWrapped = TRUE;
- ++nResult;
- x = xStart;
- }
- }
- else if (x + pItem->m_sizeHorz.cx + m_arrItem[i+1]->m_sizeHorz.cx + CXGAP > nWidth) {
- if (pItem->CanWrap()) {
- pItem->m_bWrapped = TRUE;
- ++nResult;
- x = xStart;
- }
- }
- else {
- pItem->m_bWrapped = FALSE;
- x += pItem->m_sizeHorz.cx;
- }
- }
- }
- /* //another algorithm
- int dx = pItem->m_sizeHorz.cx;
- if (dx + CXGAP > nWidth) { // bigger than nWidth
- if (pItem->CanWrap()) {
- pItem->m_bWrapped = TRUE;
- // if (i != nCount - 1)
- ++nResult;
- }
- }
- else if (dx + x + CXGAP > nWidth) {
- if (i > 0 && m_arrItem[i-1]->CanWrap()) {
- // LTRACE("index %d is wrapn", i-1);
- m_arrItem[i-1]->m_bWrapped = TRUE;
- pItem->m_bWrapped = FALSE;
- x = xStart;
- // if (i != nCount - 1)///////////////////////////
- ++nResult;
- }
- }
- else {
- pItem->m_bWrapped = FALSE;
- }
- x += dx;
- }
- }
- */
- return nResult + 1;
- }
- // calc only size, by using m_bWrapped
- CSize CMenuBar::CalcSize(int nCount)
- {
- ASSERT(nCount > 0);
- CPoint cur(CXGAP, CYGAP);
- CSize sizeResult(0, 0);
- int nWrap = 0;
- for (int i = 0; i < nCount; ++i) {
- CMenuItem* pItem = m_arrItem[i];
- if (pItem->IsValid()) {
- sizeResult.cx = max(cur.x + pItem->m_sizeHorz.cx, sizeResult.cx);
- sizeResult.cy = max(cur.y + pItem->m_sizeHorz.cy, sizeResult.cy);
- cur.x += pItem->m_sizeHorz.cx;
-
- if (pItem->m_bWrapped == TRUE) {
- LTRACE(" nIndex:%d is wrappedn", i);
- cur.x = CXGAP; // reset x pos
- cur.y += pItem->m_sizeHorz.cy;
- ++nWrap;
- }
- }
- }
- sizeResult.cy += CYGAP;
- sizeResult.cx += CXGAP;
- return sizeResult;
- }
- void CMenuBar::SizeMenuBar(int nCount, int nLength, BOOL bVert)
- {
- //LTRACE("CMenuBar::SizeMenuBarn");
- 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 know this algorithm :), see CToolBar implementation
- while (sizeMin.cx < sizeMax.cx) {
- // LTRACE("looping sizeMin.cx:%d < sizeMax.cx:%dn", 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 %dn", sizeMid.cx, sizeMid.cy);
- if (nLength >= sizeMax.cx) {
- // LTRACE(" nLength:%d >= sizeMax.cx:%dn", nLength, sizeMax.cx);
- if (sizeMin == sizeMid) {
- WrapMenuBar(nCount, sizeMax.cx);
- // LTRACE("out SizeMenuBarn");
- return;
- }
- sizeMin = sizeMid;
- }
- else if (nLength < sizeMax.cx) {
- // LTRACE(" nLength:%d < sizeMax.cx:%dn", nLength, sizeMax.cx);
- sizeMax = sizeMid;
- }
- else {
- // LTRACE("out SizeMenuBarn");
- return;
- }
- }
- }
- else { // each one wrapping
- LTRACE(" just each one wrappingn");
- 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 SizeMenuBarn");
- return;
- }
- sizeMin = sizeMid;
- }
- else if (nLength > sizeMid.cy)
- sizeMax = sizeMid;
- else {
- //LTRACE("out SizeMenuBarn");
- return;
- }
- }
- }
- //LTRACE("out SizeMenuBarn");
- }
- 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;
- }
- void CMenuBar::OnDestroy()
- {
- CControlBar::OnDestroy();
-
- // TODO: 偙偺埵抲偵儊僢僙乕僕 僴儞僪儔梡偺僐乕僪傪捛壛偟偰偔偩偝偄
- _KillTimer();
- DeleteItems();
- }
- 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]->CanTrack() || !m_arrItem[nIndex]->IsValid()) {
- return GetNextOrPrevButton(nIndex, bPrev);
- }
- return nIndex;
- }
- void CMenuBar::AddIcon(HICON hIcon)
- {
- // ASSERT(m_bIcon == FALSE);
- // m_bIcon = TRUE;
- }
- CMenuControl::CMenuControl(CControlBar* pBar)
- {
- m_bValid = FALSE;
- m_pBar = pBar;
- m_bDown = FALSE;
- m_nTracking = -1;
- int cxCaption = cyMenuButton - CYGAP + 1;
- m_sizeHorz = CSize(cxCaption*3 + CXGAP/2, cyMenuButton);
- }
- CMenuControl::~CMenuControl()
- {
- }
- void CMenuControl::Update(CDC* pDC)
- {
- // do nothing
- }
- void CMenuControl::Layout(CPoint point, BOOL bHorz)
- {
- LTRACE("CMenuControl::Layout bHorz:%dn", bHorz);
- m_bHorz = bHorz;
- // 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)
- {
- // if (!IsValid())
- // return;
- // layout
- if (m_bHorz) {
- int cxCaption = cyMenuButton - CYGAP + 1;
- int cyCaption = cxCaption - 1;
- CRect rcCaption;
- rcCaption.right = sizeBar.cx;
- rcCaption.bottom = sizeBar.cy - CYGAP;
- rcCaption.left = rcCaption.right - cxCaption;
- rcCaption.top = rcCaption.bottom - cyCaption;
- m_arrCaption[0] = rcCaption;
- rcCaption -= CPoint(cxCaption+CXGAP/2, 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 {
- int cxCaption = cyMenuButton - CYGAPVERT - 1;
- int cyCaption = cxCaption - 1;
- CRect rcCaption;
- rcCaption.left = CYGAPVERT;
- rcCaption.bottom = sizeBar.cy;
- rcCaption.right = rcCaption.left + cxCaption;
- rcCaption.top = rcCaption.bottom - cyCaption;
- m_arrCaption[0] = rcCaption;
- rcCaption -= CPoint(0, cyCaption+CXGAP/2);
- 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 (!IsValid())
- return;
- // draw frame controls
- for (int i = 0; i < 3; ++i) {
- DrawControl(pDC, i, FALSE);
- }
- // pDC->DrawFrameControl(m_arrCaption[0], DFC_CAPTION, DFCS_CAPTIONCLOSE);
- // pDC->DrawFrameControl(m_arrCaption[1], DFC_CAPTION, DFCS_CAPTIONRESTORE);
- // pDC->DrawFrameControl(m_arrCaption[2], DFC_CAPTION, DFCS_CAPTIONMIN);
- }
- // pasted from CDockContext
- void CMenuBarDockContext::StartDrag(CPoint pt)
- {
- ASSERT_VALID(m_pBar);
- m_bDragging = TRUE;
- InitLoop();
- if (m_pBar->m_dwStyle & CBRS_SIZE_DYNAMIC)
- {
- // get TRUE bar size (including borders)
- CRect rect;
- m_pBar->GetWindowRect(rect);
- m_ptLast = pt;
- CSize sizeHorz = m_pBar->CalcDynamicLayout(0, LM_HORZ | LM_HORZDOCK);
- CSize sizeVert = m_pBar->CalcDynamicLayout(0, LM_VERTDOCK);
- CSize sizeFloat = m_pBar->CalcDynamicLayout(0, LM_HORZ | LM_MRUWIDTH);
- m_rectDragHorz = CRect(rect.TopLeft(), sizeHorz);
- m_rectDragVert = CRect(rect.TopLeft(), sizeVert);
- // calculate frame dragging rectangle
- m_rectFrameDragHorz = CRect(rect.TopLeft(), sizeFloat);
- m_rectFrameDragVert = CRect(rect.TopLeft(), sizeFloat);
- #ifdef _MAC
- CMiniFrameWnd::CalcBorders(&m_rectFrameDragHorz,
- WS_THICKFRAME | WS_CAPTION, WS_EX_FORCESIZEBOX);
- CMiniFrameWnd::CalcBorders(&m_rectFrameDragVert,
- WS_THICKFRAME | WS_CAPTION, WS_EX_FORCESIZEBOX);
- #else
- CMiniFrameWnd::CalcBorders(&m_rectFrameDragHorz);
- CMiniFrameWnd::CalcBorders(&m_rectFrameDragVert);
- #endif
- m_rectFrameDragHorz.InflateRect(-cxBorder2, -cyBorder2);
- m_rectFrameDragVert.InflateRect(-cxBorder2, -cyBorder2);
- }
- else if (m_pBar->m_dwStyle & CBRS_SIZE_FIXED)
- {
- // get TRUE bar size (including borders)
- CRect rect;
- m_pBar->GetWindowRect(rect);
- m_ptLast = pt;
- CSize sizeHorz = m_pBar->CalcDynamicLayout(-1, LM_HORZ | LM_HORZDOCK);
- CSize sizeVert = m_pBar->CalcDynamicLayout(-1, LM_VERTDOCK);
- // calculate frame dragging rectangle
- m_rectFrameDragHorz = m_rectDragHorz = CRect(rect.TopLeft(), sizeHorz);
- m_rectFrameDragVert = m_rectDragVert = CRect(rect.TopLeft(), sizeVert);
- CMiniFrameWnd::CalcBorders(&m_rectFrameDragHorz);
- CMiniFrameWnd::CalcBorders(&m_rectFrameDragVert);
- m_rectFrameDragHorz.InflateRect(-cxBorder2, -cyBorder2);
- m_rectFrameDragVert.InflateRect(-cxBorder2, -cyBorder2);
- }
- else
- {
- // get TRUE bar size (including borders)
- CRect rect;
- m_pBar->GetWindowRect(rect);
- m_ptLast = pt;
- BOOL bHorz = HORZF(m_dwStyle);
- DWORD dwMode = !bHorz ? (LM_HORZ | LM_HORZDOCK) : LM_VERTDOCK;
- CSize size = m_pBar->CalcDynamicLayout(-1, dwMode);
- // calculate inverted dragging rect
- if (bHorz)
- {
- m_rectDragHorz = rect;
- m_rectDragVert = CRect(CPoint(pt.x - rect.Height()/2, rect.top), size);
- }
- else // vertical orientation
- {
- m_rectDragVert = rect;
- m_rectDragHorz = CRect(CPoint(rect.left, pt.y - rect.Width()/2), size);
- }
- // calculate frame dragging rectangle
- m_rectFrameDragHorz = m_rectDragHorz;
- m_rectFrameDragVert = m_rectDragVert;
- CMiniFrameWnd::CalcBorders(&m_rectFrameDragHorz);
- CMiniFrameWnd::CalcBorders(&m_rectFrameDragVert);
- m_rectFrameDragHorz.InflateRect(-cxBorder2, -cyBorder2);
- m_rectFrameDragVert.InflateRect(-cxBorder2, -cyBorder2);
- }
- // adjust rectangles so that point is inside
- AdjustRectangle(m_rectDragHorz, pt);
- AdjustRectangle(m_rectDragVert, pt);
- AdjustRectangle(m_rectFrameDragHorz, pt);
- AdjustRectangle(m_rectFrameDragVert, pt);
- // initialize tracking state and enter tracking loop
- m_dwOverDockStyle = CanDock();
- Move(pt); // call it here to handle special keys
- _Track();
- }
- BOOL CMenuBarDockContext::_Track()
- {
- // don't handle if capture already set
- if (::GetCapture() != NULL)
- return FALSE;
- // set capture to the window which received this message
- m_pBar->SetCapture();
- ASSERT(m_pBar == CWnd::GetCapture());
- #ifndef _MAC
- // get messages until capture lost or cancelled/accepted
- while (CWnd::GetCapture() == m_pBar)
- {
- MSG msg;
- if (!::GetMessage(&msg, NULL, 0, 0))
- {
- AfxPostQuitMessage(msg.wParam);
- break;
- }
- switch (msg.message)
- {
- case WM_LBUTTONUP:
- if (m_bDragging)
- _EndDrag();
- else
- EndResize();
- return TRUE;
- case WM_MOUSEMOVE:
- if (m_bDragging)
- Move(msg.pt);
- else
- Stretch(msg.pt);
- break;
- case WM_KEYUP:
- if (m_bDragging)
- OnKey((int)msg.wParam, FALSE);
- break;
- case WM_KEYDOWN:
- if (m_bDragging)
- OnKey((int)msg.wParam, TRUE);
- if (msg.wParam == VK_ESCAPE)
- {
- CancelLoop();
- return FALSE;
- }
- break;
- case WM_RBUTTONDOWN:
- CancelLoop();
- return FALSE;
- // just dispatch rest of the messages
- default:
- DispatchMessage(&msg);
- break;
- }
- }
- #else
- Point ptCur = {0};
- // get messages until capture lost or cancelled/accepted
- while (CWnd::GetCapture() == m_pBar)
- {
- EventRecord er;
- if (OSEventAvail(everyEvent, &er))
- {
- GetNextEvent(everyEvent, &er);
- switch (er.what)
- {
- case mouseUp:
- if (m_bDragging)
- EndDrag();
- else
- EndResize();
- return TRUE;
- case keyDown:
- case keyUp:
- case autoKey:
- case app2Evt:
- {
- MSG msg;
- if (WrapEvent(&er, &msg, PM_REMOVE))
- {
- if (m_bDragging)
- OnKey((int)msg.wParam, msg.message == WM_KEYDOWN);
- if (msg.message == WM_KEYUP && msg.wParam == VK_ESCAPE)
- {
- CancelLoop();
- return FALSE;
- }
- }
- break;
- }
- default:
- break;
- }
- }
- else
- {
- if (!EqualPt(er.where, ptCur))
- {
- POINT pt = {er.where.h, er.where.v};
- if (m_bDragging)
- Move(pt);
- else
- Stretch(pt);
- }
- }
- }
- #endif
- CancelLoop();
- return FALSE;
- }
- void CMenuBarDockContext::_EndDrag()
- {
- CancelLoop();
- if (m_dwOverDockStyle != 0)
- {
- CDockBar* pDockBar = GetDockBar(m_dwOverDockStyle);
- ASSERT(pDockBar != NULL);
- CRect rect = (m_dwOverDockStyle & CBRS_ORIENT_VERT) ?
- m_rectDragVert : m_rectDragHorz;
- UINT uID = _AfxGetDlgCtrlID(pDockBar->m_hWnd);
- if (uID >= AFX_IDW_DOCKBAR_TOP &&
- uID <= AFX_IDW_DOCKBAR_BOTTOM)
- {
- m_uMRUDockID = uID;
- m_rectMRUDockPos = rect;
- pDockBar->ScreenToClient(&m_rectMRUDockPos);
- }
- // dock it at the specified position, RecalcLayout will snap
- // insisting own line trick!
- CRect rcDockBar;
- pDockBar->GetWindowRect(rcDockBar);
- if (m_dwOverDockStyle & CBRS_ORIENT_VERT) {
- rect.top = rcDockBar.top - 1;
- }
- else {
- rect.left = rcDockBar.left - 10;
- }
- m_pDockSite->DockControlBar(m_pBar, pDockBar, &rect);
- m_pDockSite->RecalcLayout();
- }
- else if ((m_dwStyle & CBRS_SIZE_DYNAMIC) || (HORZF(m_dwStyle) && !m_bFlip) ||
- (VERTF(m_dwStyle) && m_bFlip))
- {
- m_dwMRUFloatStyle = CBRS_ALIGN_TOP | (m_dwDockStyle & CBRS_FLOAT_MULTI);
- m_ptMRUFloatPos = m_rectFrameDragHorz.TopLeft();
- m_pDockSite->FloatControlBar(m_pBar, m_ptMRUFloatPos, m_dwMRUFloatStyle);
- }
- else // vertical float
- {
- m_dwMRUFloatStyle = CBRS_ALIGN_LEFT | (m_dwDockStyle & CBRS_FLOAT_MULTI);
- m_ptMRUFloatPos = m_rectFrameDragVert.TopLeft();
- m_pDockSite->FloatControlBar(m_pBar, m_ptMRUFloatPos, m_dwMRUFloatStyle);
- }
- }
- void CMenuBar::OnPaintMDIClient()
- {
- LTRACE("CMenuBar::OnPaintMDIClientn");
- if (m_hWndMDIClient) {
- BOOL bMax = FALSE;
- // get active MDI child window
- HWND hWndChild = (HWND)::SendMessage(m_hWndMDIClient, WM_MDIGETACTIVE, 0,
- (LPARAM)&bMax);
- //ASSERT(::IsWindow(hWndChild)); crash! tell me why!
- if (bMax != m_bMDIMaximized) {
- LTRACE(" max state changedn");
- m_bMDIMaximized = bMax;
-
- if (bMax) {
- LTRACE(" maximizedn");
- m_pMenuControl->Validate(TRUE);
- m_pMenuIcon->Validate(TRUE);
- }
- else {
- LTRACE(" not maximizedn");
- m_pMenuControl->Validate(FALSE);
- m_pMenuIcon->Validate(FALSE);
- }
- RefreshBar();
- }
- }
- }
- void CMenuBar::OnInitMenuPopup()
- {
- CMenu menu;
- menu.Attach((HMENU)m_hWindowMenu);
- // scan for first window command
- int n = menu.GetMenuItemCount();
- BOOL bAddSeperator = TRUE;
- for (int iPos=0; iPos<n; iPos++) {
- if (menu.GetMenuItemID(iPos) >= AFX_IDM_FIRST_MDICHILD) {
- bAddSeperator = FALSE;
- break;
- }
- }
- // iPos is either first window item, or end if none found.
- // delete everything after.
- while (iPos < (int)menu.GetMenuItemCount())
- menu.RemoveMenu(iPos, MF_BYPOSITION);
- // get active window so I can check its menu item
- ASSERT(m_hWndMDIClient);
- HWND hwndActive = (HWND)::SendMessage(m_hWndMDIClient,
- WM_MDIGETACTIVE, 0, NULL);
- // append window names in the form "# title"
- int iWin=1;
- for (HWND hwnd=::GetWindow(m_hWndMDIClient, GW_CHILD);
- hwnd;
- hwnd = ::GetWindow(hwnd, GW_HWNDNEXT)) {
- if (bAddSeperator) {
- menu.InsertMenu(iPos++, MF_BYPOSITION|MF_SEPARATOR);
- bAddSeperator = FALSE;
- }
- // build item name and add it to the menu
- CString sWinName, sMenuItem;
- CWnd::FromHandle(hwnd)->GetWindowText(sWinName);
- sMenuItem.Format(_T("&%d %s"), iWin++, (LPCTSTR)sWinName);
- menu.InsertMenu(iPos, MF_BYPOSITION,
- ::GetDlgCtrlID(hwnd), sMenuItem);
- if (hwnd==hwndActive)
- menu.CheckMenuItem(iPos, MF_BYPOSITION|MF_CHECKED);
- iPos++;
- }
- menu.Detach();
- }
- void CMenuBar::OnSetMenu(HMENU hNewMenu, HMENU hWindowMenu)
- {
- // We can get active MDI child window on this message!
- BOOL bMax;
- HWND hWndChild = GetActiveChildWnd(bMax);
- if (!m_hWndActiveChild || m_hWndActiveChild != hWndChild) {
- // active child window changed
- LTRACE(" active child window changedn");
- m_hWndActiveChild = hWndChild;
- // tell MenuIcon child window has been changed
- m_pMenuIcon->OnActivateChildWnd(hWndChild);
- }
- LTRACE("CMenuBar::OnSetMenun");
- if (!m_hMenu || m_hMenu != hNewMenu) { // menu changed
- LTRACE(" menu changedn");
- LoadMenu(hNewMenu, hWindowMenu); // set toolbar menu
- GetOwner()->SetMenu(NULL); // clear frame menu
- }
- }
- HWND CMenuBar::GetActiveChildWnd(BOOL& bMaximized)
- {
- if (!m_hWndMDIClient)
- return NULL;
- BOOL bMax = FALSE;
- HWND hWnd = (HWND)::SendMessage(m_hWndMDIClient,
- WM_MDIGETACTIVE, 0, (LPARAM)&bMax);
- bMaximized = bMax;
- return hWnd;
- }
- CMenuItem::CMenuItem()
- {
- m_itemState = none;
- m_rcItem = CRect(0, 0, 0, 0);
- m_sizeHorz = CSize(0, 0);
- m_bHorz = TRUE;
- m_bWrapped = FALSE;
- }
- CMenuItem::~CMenuItem()
- {
- }
- CPoint CMenuItem::ComputeMenuTrackPoint(CWnd* pWnd, HMENU hSubMenu, TPMPARAMS& tpm, CFont* pFont)
- {
- ASSERT_VALID(pWnd);
- ASSERT_VALID(pFont);
- ASSERT(::IsMenu(hSubMenu));
- tpm.cbSize = sizeof(tpm);
- CRect& rcExclude = (CRect&)tpm.rcExclude;
- CWnd::GetDesktopWindow()->GetWindowRect(&rcExclude);
- CPoint pt;
- CRect rcItem = m_rcItem;
- pWnd->ClientToScreen(&rcItem);
- // if (hSubMenu == NULL) // it's possible no sub menu
- // return CPoint();
- if (m_bHorz) { // horizontal
- int nCount = ::GetMenuItemCount(hSubMenu);
- ASSERT(nCount != -1);
- int cyPopup = nCount * rcItem.Height(); // I want it be not owner drawn but ordinary menu..
- if (rcItem.bottom + cyPopup > rcExclude.bottom) {
- pt = CPoint(rcItem.left, rcItem.top); // over Screen
- rcExclude.top = rcItem.top;
- }
- else {
- pt = CPoint(rcItem.left, rcItem.bottom);
- }
- pt += CPoint(-1, 1); // precisely same as DevStudio
- }
- else { // vertical
- // we never get the width of popup up menu, but I will try
- int nCount = ::GetMenuItemCount(hSubMenu);
- ASSERT(nCount != -1);
-
- int cxPopup = 0;
- CWindowDC dc(NULL);
- CFont* pOldFont = dc.SelectObject(pFont);
- for (int i = 0; i < nCount; ++i) {
- char szName[256];
- MENUITEMINFO info;
- ::ZeroMemory(&info, sizeof(MENUITEMINFO));
- info.cbSize = sizeof(MENUITEMINFO);
- info.fMask = MIIM_ID | MIIM_TYPE;
- info.dwTypeData = szName;
- info.cch = sizeof(szName);
- ::GetMenuItemInfo(hSubMenu, i, TRUE, &info);
-
- CString strItem(szName);
- CRect rcText(0, 0, 0, 0);
- dc.DrawText(strItem, &rcText,
- DT_SINGLELINE | DT_VCENTER | DT_CALCRECT | DT_NOPREFIX);
- int cxOffset = ::GetSystemMetrics(SM_CXMENUCHECK) * 2;
- cxPopup = max(rcText.Width() + 4*2 + CXGAP*2 + cxOffset, cxPopup);
- }
- dc.SelectObject(pOldFont);
- if (rcItem.right + cxPopup > rcExclude.right) { // over right-side
- pt = CPoint(rcItem.left, rcItem.top);
- rcExclude.left = rcItem.left;
- }
- else {
- pt = CPoint(rcItem.right, rcItem.top);
- rcExclude.right = rcItem.right;
- }
- pt += CPoint(1, -1); // precisely same as DevStudio
- }
- return pt;
- }
- CMenuIcon::CMenuIcon(CWnd* pWnd)
- {
- m_hDocIcon = NULL;//hIcon;
- m_sizeHorz = CSize(::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON));
- m_bValid = FALSE;
- m_hSysMenu = NULL;//::GetSystemMenu(pWnd->GetSafeHwnd(), FALSE);
- }
- CMenuIcon::~CMenuIcon()
- {
- }
- void CMenuIcon::Update(CDC* pDC)
- {
- ASSERT(m_hDocIcon);
- ASSERT(m_bValid);
- ::DrawIconEx(pDC->m_hDC, m_rcItem.left, m_rcItem.top, m_hDocIcon,
- m_sizeHorz.cx, m_sizeHorz.cy, 0, NULL, DI_NORMAL);
- }
- void CMenuIcon::TrackPopup(CWnd* pWnd)
- {
- ASSERT(m_hDocIcon);
- ASSERT(m_bValid);
- ASSERT(::IsMenu(m_hSysMenu));
- NONCLIENTMETRICS info;
- info.cbSize = sizeof(info);
- ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0);
- CFont fontSys;
- if (!fontSys.CreateFontIndirect(&info.lfMenuFont))
- return;
- TPMPARAMS tpm;
- CPoint pt = ComputeMenuTrackPoint(pWnd, m_hSysMenu, tpm, &fontSys);
- ::TrackPopupMenuEx(m_hSysMenu,
- TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_VERTICAL,
- pt.x, pt.y, pWnd->GetOwner()->GetSafeHwnd(), &tpm);
- }
- void CMenuIcon::Layout(CPoint point, BOOL bHorz)
- {
- ASSERT(m_bValid);
- m_bHorz = bHorz;
- m_rcItem = CRect(point, m_sizeHorz);
- }
- void CMenuIcon::OnActivateChildWnd(HWND hWndChild)
- {
- TRACE("CMenuIcon::OnActivateChildWndn");
- ASSERT(::IsWindow(hWndChild));
- m_hSysMenu = ::GetSystemMenu(hWndChild, FALSE);
- ASSERT(::IsMenu(m_hSysMenu));
- m_hDocIcon = (HICON)GetClassLong(hWndChild, GCL_HICONSM);
- }
- BOOL CMenuControl::OnMouseMsg(UINT msg, UINT nFlags, CPoint pt)
- {
- if (!IsValid())
- return FALSE;
- if (msg == WM_LBUTTONDOWN) {
- m_nTracking = HitTest(pt);
- if (m_nTracking >= 0) {
- CClientDC dc(m_pBar);
- DrawControl(&dc, m_nTracking, TRUE);
- m_bDown = TRUE;
- m_pBar->SetCapture(); // grab mouse input
- return TRUE;
- }
- }
- else if ((msg == WM_MOUSEMOVE) && m_nTracking >= 0) {
- // mouse moved, and I am tracking: possibly draw button up/down
- BOOL bOldDown = m_bDown;
- m_bDown = m_arrCaption[m_nTracking].PtInRect(pt);
- if (bOldDown != m_bDown) {
- // up/down state changed: need to redraw button
- CClientDC dc(m_pBar);
- DrawControl(&dc, m_nTracking, m_bDown);
- }
- return TRUE; // handled
- }
- else if (msg == WM_LBUTTONUP && m_nTracking >= 0) {
- // user released the mouse and I am tracking: do button command
- ReleaseCapture(); // let go the mouse
- if (m_bDown) {
- // if button was down when released: draw button up, and do system cmd
- CClientDC dc(m_pBar);
- DrawControl(&dc, m_nTracking, FALSE);
- CFrameWnd* pFrame = m_pBar->GetTopLevelFrame()->GetActiveFrame();
- ASSERT_VALID(pFrame);
- static syscmd[3] =
- { /*SC_MOUSEMENU,*/ SC_CLOSE, SC_RESTORE, SC_MINIMIZE };
- pFrame->SendMessage(WM_SYSCOMMAND, syscmd[m_nTracking]);
- }
- m_nTracking = -1; // stop tracking
- return TRUE; // handled (eat)
- }
- return FALSE;
- }
- int CMenuControl::HitTest(CPoint point)
- {
- for (int i = 0; i < 3; ++i) {
- if (m_arrCaption[i].PtInRect(point))
- return i;
- }
- return -1;
- }
- void CMenuControl::DrawControl(CDC* pDC, int nIndex, BOOL bPressed)
- {
- // draw frame controls
- CRect& rc = m_arrCaption[nIndex];
- static UINT dfcs[3] = { DFCS_CAPTIONCLOSE, DFCS_CAPTIONRESTORE, DFCS_CAPTIONMIN };
- UINT uState = dfcs[nIndex];
- if (bPressed)
- uState |= DFCS_PUSHED;
- pDC->DrawFrameControl(rc, DFC_CAPTION, uState);
- }
- void CMenuControl::ForceDrawControl(CDC * pDC)
- {
- if (!IsValid())
- return;
- for (int i = 0; i < 3; ++i) {
- DrawControl(pDC, i, FALSE);
- }
- }
- namespace {
- const int CXTEXTMARGIN = 5;
- int CYTEXTMARGIN = 0;
- const int CYTEXTMARGINMIN = 2;
-
- CFont fontHorz, fontVert;
- // const int CXGAP = 3;
- }// anonymouse namespace
- CMenuButton::CMenuButton(HMENU hMenu, int nIndex)
- {
- ASSERT(hMenu);
- InitButtonStringAndSubMenuHandle(hMenu, nIndex);
- InitHorizontalButtonSize();
- InitAccessKeyAndVerticalLinePoint();
- }
- CMenuButton::~CMenuButton()
- {
- }
- BOOL CMenuButton::InitCommonResource()
- {
- // clean up
- fontHorz.DeleteObject();
- fontVert.DeleteObject();
- // create fonts
- NONCLIENTMETRICS info;
- info.cbSize = sizeof(info);
- ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0);
- if (!fontHorz.CreateFontIndirect(&info.lfMenuFont))
- return FALSE;
- info.lfMenuFont.lfEscapement = -900;
- info.lfMenuFont.lfOrientation = -900;
- if (!fontVert.CreateFontIndirect(&info.lfMenuFont))
- return FALSE;
- // get font height
- LOGFONT logfont;
- fontHorz.GetLogFont(&logfont);
- int cyFont = abs(logfont.lfHeight);
- // calc Y text margin
- int cyText = cyFont + CYTEXTMARGINMIN*2;
- int cyMenu = ::GetSystemMetrics(SM_CYMENU);
- if (cyMenu > cyText) {
- CYTEXTMARGIN = (cyMenu - cyFont)/2;
- }
- else {
- CYTEXTMARGIN = CYTEXTMARGINMIN;
- }
- return TRUE;
- }
- void CMenuButton::InitButtonStringAndSubMenuHandle(HMENU hMenu, int nIndex)
- {
- // get menu button Text
- char szText[256];
- MENUITEMINFO info; ::ZeroMemory(&info, sizeof(MENUITEMINFO));
- info.cbSize = sizeof(MENUITEMINFO);
- info.fMask = MIIM_ID | MIIM_TYPE;
- info.dwTypeData = szText;
- info.cch = sizeof(szText);
- ::GetMenuItemInfo(hMenu, nIndex, TRUE, &info);
- m_strBtn = CString(szText);
- m_hSubMenu = ::GetSubMenu(hMenu, nIndex);
- }
- void CMenuButton::InitHorizontalButtonSize()
- {
- // get menu button Text size
- ASSERT(m_strBtn.IsEmpty() == FALSE);
- CWindowDC dc(NULL);
- CRect rcText(0, 0, 0, 0);
- CFont* pOldFont = dc.SelectObject(&fontHorz);
- dc.DrawText(m_strBtn, &rcText, DT_SINGLELINE | DT_CALCRECT);
- dc.SelectObject(pOldFont);
- m_sizeHorz.cx = rcText.Width() + CXTEXTMARGIN*2;
- LOGFONT logfont;
- fontHorz.GetLogFont(&logfont);
- int cyFont = abs(logfont.lfHeight);
- m_sizeHorz.cy = cyFont + CYTEXTMARGIN*2;
- }
- void CMenuButton::InitAccessKeyAndVerticalLinePoint()
- {
- int nIndex = m_strBtn.Find('&');
- m_cAccessKey = m_strBtn[nIndex + 1]; // -1 + 1 = 0; it's ok
- if (nIndex == -1) {
- m_ptLineFrom = m_ptLineTo = CPoint(0, 0);
- }
- else if (nIndex == 0) {
- CRect rcTo;
- CWindowDC dc(NULL);
- CFont* pOldFont = dc.SelectObject(&fontHorz);
- dc.DrawText(m_strBtn.Left(nIndex+2), &rcTo, DT_SINGLELINE | DT_CALCRECT);
- dc.SelectObject(pOldFont);
- m_ptLineFrom = CPoint(CYTEXTMARGIN, CXTEXTMARGIN);
- m_ptLineTo = CPoint(CYTEXTMARGIN, CXTEXTMARGIN + rcTo.Width());
- }
- else {
- CRect rcFrom, rcTo;
- CWindowDC dc(NULL);
- CFont* pOldFont = dc.SelectObject(&fontHorz);
- dc.DrawText(m_strBtn.Left(nIndex), &rcFrom, DT_SINGLELINE | DT_CALCRECT);
- dc.DrawText(m_strBtn.Left(nIndex+2), &rcTo, DT_SINGLELINE | DT_CALCRECT);
- dc.SelectObject(pOldFont);
- m_ptLineFrom = CPoint(CYTEXTMARGIN, CXTEXTMARGIN + rcFrom.Width());
- m_ptLineTo = CPoint(CYTEXTMARGIN, CXTEXTMARGIN + rcTo.Width());
- }
- }
- void CMenuButton::Layout(CPoint point, BOOL bHorz)
- {
- if (bHorz == TRUE) {
- m_rcItem = CRect(point, m_sizeHorz);
- }
- else {
- m_rcItem = CRect(point, CSize(m_sizeHorz.cy, m_sizeHorz.cx));
- }
- m_bHorz = bHorz;
- }
- void CMenuButton::Update(CDC* pDC)
- {
- // clean background
- COLORREF clr = ::GetSysColor(COLOR_BTNFACE);
- pDC->FillSolidRect(m_rcItem, clr);
- switch (m_itemState) {
- case hot:
- DrawHot(pDC);
- break;
- case select:
- DrawSelect(pDC);
- break;
- case none:
- DrawNone(pDC);
- break;
- default:
- ASSERT(TRUE);
- }
- }
- void CMenuButton::TrackPopup(CWnd* pWnd)
- {
- TPMPARAMS tpm;
- CPoint pt = ComputeMenuTrackPoint(pWnd, m_hSubMenu, tpm, &fontHorz);
- ::TrackPopupMenuEx(m_hSubMenu,
- TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_VERTICAL,
- pt.x, pt.y, pWnd->GetOwner()->GetSafeHwnd(), &tpm);
- }
- void CMenuButton::DrawHorzText(CDC* pDC, CPoint ptOffset)
- {
- CRect rcBtn = m_rcItem;
- pDC->SetBkMode(TRANSPARENT);
- CFont* pOldFont = pDC->SelectObject(&fontHorz);
- // I know precise text size
- rcBtn.DeflateRect(CXTEXTMARGIN, CYTEXTMARGIN);
- pDC->DrawText(m_strBtn, rcBtn + ptOffset,
- DT_SINGLELINE);// | DT_CENTER | DT_VCENTER); no need
-
- pDC->SelectObject(pOldFont);
- }
- void CMenuButton::DrawVertText(CDC* pDC, CPoint ptOffset)
- {
- CRect rcBtn = m_rcItem;
- int nLength = m_strBtn.GetLength();
- int nIndex = m_strBtn.Find('&');
- CString strBtn = m_strBtn.Left(nIndex) + m_strBtn.Right(nLength - (nIndex+1));
- pDC->SetBkMode(TRANSPARENT);
- CFont* pOldFont = pDC->SelectObject(&fontVert);
- // I must know precise text size
- CRect rcString = CRect(
- CPoint(rcBtn.right - CYTEXTMARGIN, rcBtn.top + CXTEXTMARGIN), m_sizeHorz);
- pDC->DrawText(strBtn, rcString + ptOffset,
- DT_SINGLELINE | DT_NOCLIP | DT_NOPREFIX); // don't forget DT_NOCLIP
-
- pDC->SelectObject(pOldFont);
- // DrawText is poor, so we have to draw vertical line by ourselves
- pDC->MoveTo(rcBtn.TopLeft() + m_ptLineFrom + ptOffset);
- pDC->LineTo(rcBtn.TopLeft() + m_ptLineTo + ptOffset);
- }
- void CMenuButton::DrawHot(CDC* pDC)
- {
- if (m_bHorz) {
- // draw down button
- pDC->DrawEdge(m_rcItem, BDR_RAISEDINNER, BF_RECT);
- DrawHorzText(pDC);
- }
- else {
- pDC->DrawEdge(m_rcItem, BDR_RAISEDINNER, BF_RECT);
- DrawVertText(pDC);
- }
- }
- void CMenuButton::DrawSelect(CDC* pDC)
- {
- if (m_bHorz) {
- // draw pressed button
- pDC->DrawEdge(m_rcItem, BDR_SUNKENOUTER, BF_RECT);
- DrawHorzText(pDC, CPoint(1, 1));
- }
- else {
- pDC->DrawEdge(m_rcItem, BDR_SUNKENOUTER, BF_RECT);
- DrawVertText(pDC, CPoint(1, 1));
- }
- }
- void CMenuButton::DrawNone(CDC* pDC)
- {
- if (m_bHorz) {
- DrawHorzText(pDC);
- }
- else {
- DrawVertText(pDC);
- }
- }
- int CMenuBar::OnActivateFrame(int nCmdShow)
- {
- CFrameWnd* pFrame = GetParentFrame();
- ASSERT_VALID(pFrame);
- if (pFrame->GetMenu() != NULL) {
- LTRACE(" has menun");
- pFrame->SetMenu(NULL);
- }
- m_nCmdShow = nCmdShow;
- return SW_HIDE;
- }