// ========================================================================== // Class Implementation : // COXMenuBar // ========================================================================== // Version: 9.3 // This software along with its related components, documentation and files ("The Libraries") // is © 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is // governed by a software license agreement ("Agreement"). Copies of the Agreement are // available at The Code Project (www.codeproject.com), as part of the package you downloaded // to obtain this file, or directly from our office. For a copy of the license governing // this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900. // ////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "OXMenuBar.h" #include "OXSkins.h" #include "OXBitmapMenuOrganizer.h" #ifdef OX_CUSTOMIZE_COMMANDS #include "OXDragDropCommands.h" #include "..\include\oxmenubar.h" #endif // OX_CUSTOMIZE_COMMANDS #include "UTB64Bit.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #ifndef IDT_OXCHECKFORDRAGDROPEVENT #define IDT_OXCHECKFORDRAGDROPEVENT 412 #endif // IDT_OXCHECKFORDRAGDROPEVENT #ifndef ID_OXCHECKFORDRAGDROPEVENT_DELAY #define ID_OXCHECKFORDRAGDROPEVENT_DELAY 500 #endif // ID_OXCHECKFORDRAGDROPEVENT_DELAY #if _MFC_VER>=0x0420 ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// // COXMenuBar ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// IMPLEMENT_DYNAMIC(COXMenuBar,COXCoolToolBar) HHOOK COXMenuBar::m_hMouseHook = NULL; HWND COXMenuBar::m_hwndPrevMouseMoveWnd = NULL; COXMenuBar::COXMenuBar() { // only works when comctl32.dll v4.71>= is installed if(m_dwComCtlVersion<_IE40_COMCTL_VERSION) { TRACE(_T("In order to use Menu Bar in your application you have to have comctl32.dll v 4.71 or higher installed\n")); AfxThrowNotSupportedException(); } // use entire row/column m_bTakeEntireRow=TRUE; m_hMenu=NULL; m_hMDIWindowMenu=NULL; m_nActiveMenuItem=-1; m_nActivateNextItem=-1; m_nForbiddenItem=-1; m_rectCloseBtn.SetRectEmpty(); m_rectRestoreBtn.SetRectEmpty(); m_rectMinimizeBtn.SetRectEmpty(); m_pressedBtn=OX_MNU_NONE; m_cxLeftBorder=0; m_cyTopBorder=0; m_cxRightBorder=0; m_cyBottomBorder=0; m_bIsInSurfingMode=FALSE; m_bForceEntireRow=FALSE; m_bIsMenuMetricInitialized=FALSE; m_nCheckForDragDropEventTimerID=0; m_nWouldBeDraggedItem=-1; m_bStaySurfing=FALSE; m_pMenuSkin = NULL; } COXMenuBar::~COXMenuBar() { for(int nIndex=PtrToInt(m_arrCreatedPopupMenus.GetSize()-1); nIndex>=0; nIndex--) { ::DestroyMenu(m_arrCreatedPopupMenus[nIndex]); } m_arrCreatedPopupMenus.RemoveAll(); if ( m_pMenuSkin != NULL ) delete m_pMenuSkin; } BEGIN_MESSAGE_MAP(COXMenuBar, COXCoolToolBar) //{{AFX_MSG_MAP(COXMenuBar) ON_WM_NCLBUTTONDOWN() ON_WM_NCHITTEST() ON_WM_LBUTTONDBLCLK() ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() ON_WM_RBUTTONDOWN() ON_WM_RBUTTONDBLCLK() ON_WM_MOUSEMOVE() ON_WM_NCLBUTTONDBLCLK() ON_WM_KILLFOCUS() ON_WM_SETTINGCHANGE() ON_WM_TIMER() ON_WM_CREATE() ON_WM_DESTROY() ON_WM_NCMOUSEMOVE() ON_WM_SIZE() //}}AFX_MSG_MAP ON_MESSAGE(WM_IDLEUPDATECMDUI, OnIdleUpdateCmdUI) ON_UPDATE_COMMAND_UI_RANGE(0,0xffff,OnUpdateMenuItem) ON_NOTIFY_REFLECT_EX(TBN_DROPDOWN,OnMenuDropDown) ON_MESSAGE(WM_DISPLAYPOPUPMENU, OnDisplayPopupMenu) ON_COMMAND(ID_OXCUSTTB_DELETE,OnCustTBDelete) // reflect messages to make customization work ON_NOTIFY_REFLECT_EX(TBN_BEGINDRAG, OnTBNBeginDrag) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// BOOL COXMenuBar::Create(CWnd* pParentWnd, DWORD dwStyle/*=WS_CHILD|WS_VISIBLE|CBRS_TOP|CBRS_SIZE_DYNAMIC*/, UINT nID/*=AFX_IDW_MENUBAR*/) { ASSERT(pParentWnd!=NULL); ASSERT(::IsWindow(pParentWnd->m_hWnd)); // CToolBar bug !!!!! // When menu bar is created again it uses data saved in m_sizeImage // variable for initializing button sizes. CToolBar reset this value // as aresult of applying different operations. COXMenuBar doesn't use // images so m_sizeImage will be set to (0,0). The thing is CToolBar::CreateEx // doesn't like m_sizeImage being set to (0,0)!!!! // So we need to set this variable to some reasonable non-zero value. // We will use the same numbers as in CToolBar initialization part if(m_sizeImage.cx==0 || m_sizeImage.cy==0) { // not the first creation, reset variables // default image sizes m_sizeImage.cx = 16; m_sizeImage.cy = 15; // default button sizes m_sizeButton.cx = 23; m_sizeButton.cy = 22; } // try to create cool toolbar if(!COXCoolToolBar::Create(pParentWnd,dwStyle,nID)) { return FALSE; } // make sure dropdown arrows are not appeared on the buttons SetDropDownArrow(FALSE); // set size of images to zero (cannot call SetSizes function // because it will assert if zero value is specified) SendMessage(TB_SETBITMAPSIZE,0,MAKELPARAM(0,0)); // set window text CString sText; VERIFY(sText.LoadString(IDS_OX_MENUBARTITLE));//"Menu" SetWindowText(sText); // save pointer to parent window m_pFrameWnd=pParentWnd; return TRUE; } void COXMenuBar::OnFloatingDocking(BOOL bFloating) { // TODO: Add your message handler code here COXCoolToolBar::OnFloatingDocking(bFloating); if(bFloating) { // remove all items form mini dock frame window system menu CFrameWnd* pMiniDockFrame=(CFrameWnd*)GetDockingFrame(); ASSERT(pMiniDockFrame!=NULL && pMiniDockFrame->IsKindOf(RUNTIME_CLASS(CMiniDockFrameWnd))); if(pMiniDockFrame!=NULL && pMiniDockFrame-> IsKindOf(RUNTIME_CLASS(CMiniDockFrameWnd))) { CMenu* pPopup=pMiniDockFrame->GetSystemMenu(FALSE); while(pPopup->DeleteMenu(0,MF_BYPOSITION)); } } } void COXMenuBar::OnChangeDockSide(DWORD dwDockSide) { UNREFERENCED_PARAMETER(dwDockSide); if(!IsFloating() && GetParentFrame()!=NULL) { GetParentFrame()->RecalcLayout(); } } LONG COXMenuBar::OnIdleUpdateCmdUI(WPARAM wParam, LPARAM lParam) { // refresh icon if any is displayed UpdateIcon(TRUE); COXCoolToolBar::OnIdleUpdateCmdUI(wParam,lParam); return 0L; } LONG COXMenuBar::OnDisplayPopupMenu(WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); MSG msg; // handle only the last one while(::PeekMessage(&msg,GetSafeHwnd(), WM_DISPLAYPOPUPMENU,WM_DISPLAYPOPUPMENU,PM_REMOVE)) { wParam=msg.wParam; } ASSERT(wParam>=0 && wParam<=(WPARAM)::GetMenuItemCount(m_hMenu)); DisplayPopupMenu(PtrToInt(wParam)); return 0; } void COXMenuBar::OnUpdateMenuItem(CCmdUI* pCmd) { // if there is nothing to update if(m_hMenu==NULL) return; CMenu* pMenu=CMenu::FromHandle(m_hMenu); ASSERT(pMenu!=NULL); if(pMenu==NULL) return; // enable menu items if(pCmd->m_nID-ID_CMDBASEGetMenuItemCount()) { pCmd->Enable((pMenu->GetMenuState(pCmd->m_nID-ID_CMDBASE, MF_BYPOSITION)&(MF_DISABLED|MF_GRAYED))==0); } } BOOL COXMenuBar::OnMenuDropDown(NMHDR* pNotifyStruct, LRESULT* result) { NMTOOLBAR* pNMTB=(NMTOOLBAR*)pNotifyStruct; *result=TBDDRET_DEFAULT; // don't call it twice for forbidden item if(m_nForbiddenItem!=pNMTB->iItem-ID_CMDBASE) { // analyze item CMenu* pMenu=CMenu::FromHandle(m_hMenu); ASSERT(pMenu!=NULL); UINT nCmdID=pMenu->GetMenuItemID(pNMTB->iItem-ID_CMDBASE); if(nCmdID==-1 || nCmdID==0xffff) { PostMessage(WM_DISPLAYPOPUPMENU,pNMTB->iItem-ID_CMDBASE); } else if(nCmdID>0) { if(!IsInAdvancedCustomizationMode()) { // make sure the state of previously active button is restored RestoreMenuButton(); // set current active item m_nActiveMenuItem=pNMTB->iItem-ID_CMDBASE; m_nActivateNextItem=-1; m_nForbiddenItem=m_nActiveMenuItem; // set button to pressed state CToolBarCtrl& tool=GetToolBarCtrl(); tool.PressButton(m_nActiveMenuItem+ID_CMDBASE); ASSERT(m_pFrameWnd!=NULL); m_pFrameWnd->SendMessage(WM_COMMAND,nCmdID,(LPARAM)NULL); m_nForbiddenItem=-1; RestoreMenuButton(); } } } else { m_nForbiddenItem=-1; } return FALSE; } #if _MSC_VER >= 1400 LRESULT COXMenuBar::OnNcHitTest(CPoint point) #else UINT COXMenuBar::OnNcHitTest(CPoint point) #endif { // TODO: Add your message handler code here and/or call default CRect rect; GetWindowRect(rect); CPoint ptTest=point; ptTest-=rect.TopLeft(); // handle areas where icon and close, restore, minimize buttons // are located in a specific way if(GetIcon()!=NULL && (m_iconRect.PtInRect(ptTest) || m_rectCloseBtn.PtInRect(ptTest) || m_rectRestoreBtn.PtInRect(ptTest) || m_rectMinimizeBtn.PtInRect(ptTest))) { return HTCAPTION; } return CToolBar::OnNcHitTest(point); } void COXMenuBar::OnNcLButtonDown(UINT nHitTest, CPoint point) { // TODO: Add your message handler code here and/or call default UNREFERENCED_PARAMETER(nHitTest); CRect rect; GetWindowRect(rect); CPoint ptTest=point; ptTest-=rect.TopLeft(); ASSERT(GetIcon()!=NULL && (m_iconRect.PtInRect(ptTest) || m_rectCloseBtn.PtInRect(ptTest) || m_rectRestoreBtn.PtInRect(ptTest) || m_rectMinimizeBtn.PtInRect(ptTest))); if(GetIcon()==NULL) return; // handle mouse click over icon and close, restore, minimize buttons // m_pressedBtn=OX_MNU_NONE; MENUBARHITTEST hitTest=(MENUBARHITTEST)HitTest(ptTest); if(hitTest==OX_MNU_ICON) { PostMessage(WM_DISPLAYPOPUPMENU,::GetMenuItemCount(m_hMenu)); } else if(hitTest==OX_MNU_CLOSEBTN || hitTest==OX_MNU_RESTOREBTN || hitTest==OX_MNU_MINIMIZEBTN) { SetCapture(); m_pressedBtn=hitTest; RedrawToolBar(FALSE,TRUE); } else { COXCoolToolBar::OnNcLButtonDown(nHitTest,point); } } void COXMenuBar::OnNcLButtonDblClk(UINT nHitTest, CPoint point) { // TODO: Add your message handler code here and/or call default // handle mouse double click over icon // if(GetIcon()!=NULL) { ASSERT_KINDOF(CMDIFrameWnd,m_pFrameWnd); BOOL bMaximize=FALSE; CMDIChildWnd* pChild=((CMDIFrameWnd*)m_pFrameWnd)-> MDIGetActive(&bMaximize); ASSERT(pChild!=NULL && bMaximize); if(pChild==NULL || !bMaximize) { COXCoolToolBar::OnNcLButtonDblClk(nHitTest, point); return; } int hitTest=HitTest(point,OX_MNU_SCREEN); if(hitTest==OX_MNU_ICON) pChild->PostMessage(WM_SYSCOMMAND,SC_CLOSE); } COXCoolToolBar::OnNcLButtonDblClk(nHitTest, point); } void COXMenuBar::OnLButtonDblClk(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default if(IsFloating()) { CToolBarCtrl& tool=GetToolBarCtrl(); tool.PressButton(ID_CMDBASE,FALSE); } if (!IsFloatingEnabled()) { if (HitTest(point, OX_MNU_CLIENT) != OX_MNU_NONE) COXCoolToolBar::OnLButtonDblClk(nFlags, point); } else COXCoolToolBar::OnLButtonDblClk(nFlags, point); return; } void COXMenuBar::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default if(IsFloating()) { CToolBarCtrl& tool=GetToolBarCtrl(); tool.PressButton(ID_CMDBASE,FALSE); } if (!IsFloatingEnabled()) { if (HitTest(point, OX_MNU_CLIENT) != OX_MNU_NONE) COXCoolToolBar::OnLButtonDown(nFlags, point); } else COXCoolToolBar::OnLButtonDown(nFlags, point); if(GetDraggedButton()==-1 && IsInAdvancedCustomizationMode()) { if(m_nCheckForDragDropEventTimerID==0) { m_nWouldBeDraggedItem=COXCoolToolBar::HitTest(&point); m_nCheckForDragDropEventTimerID=SetTimer(IDT_OXCHECKFORDRAGDROPEVENT, ID_OXCHECKFORDRAGDROPEVENT_DELAY,NULL); ASSERT(m_nCheckForDragDropEventTimerID!=0); } else { KillTimer(m_nCheckForDragDropEventTimerID); m_nCheckForDragDropEventTimerID=0; } } return; } void COXMenuBar::OnLButtonUp(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default // handle mouse click close, restore, minimize buttons // if (GetIcon() == NULL || ::GetCapture() != GetSafeHwnd() || m_bDragging) { COXCoolToolBar::OnLButtonUp(nFlags,point); return; } ::ReleaseCapture(); BOOL bMaximize=FALSE; ASSERT_KINDOF(CMDIFrameWnd,m_pFrameWnd); CMDIChildWnd* pChild=((CMDIFrameWnd*)m_pFrameWnd)->MDIGetActive(&bMaximize); ASSERT(pChild!=NULL && bMaximize); if(pChild==NULL || !bMaximize) { COXCoolToolBar::OnLButtonUp(nFlags,point); return; } CRect rect; GetWindowRect(rect); CPoint ptTest=point; ClientToScreen(&ptTest); ptTest-=rect.TopLeft(); MENUBARHITTEST hitTest=(MENUBARHITTEST)HitTest(ptTest); // send corresponding messages if(m_pressedBtn==hitTest) { if(m_pressedBtn==OX_MNU_CLOSEBTN) pChild->PostMessage(WM_SYSCOMMAND,SC_CLOSE); else if(m_pressedBtn==OX_MNU_RESTOREBTN) pChild->PostMessage(WM_SYSCOMMAND,SC_RESTORE); else if(m_pressedBtn==OX_MNU_MINIMIZEBTN) pChild->PostMessage(WM_SYSCOMMAND,SC_MINIMIZE); } m_pressedBtn=OX_MNU_NONE; RedrawToolBar(FALSE,TRUE); } void COXMenuBar::OnRButtonDown(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default if(IsFloating()) { CToolBarCtrl& tool=GetToolBarCtrl(); tool.PressButton(ID_CMDBASE,FALSE); } COXCoolToolBar::OnRButtonDown(nFlags,point); } void COXMenuBar::OnRButtonDblClk(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default if(IsFloating()) { CToolBarCtrl& tool=GetToolBarCtrl(); tool.PressButton(ID_CMDBASE,FALSE); } COXCoolToolBar::OnRButtonDblClk(nFlags,point); } void COXMenuBar::OnMouseMove(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default if (GetIcon()) { CWindowDC dc(this); GetToolbarSkin()->DrawMenuButtons(&dc, this); } if(m_nCheckForDragDropEventTimerID!=0 && ::GetKeyState(VK_LBUTTON)>=0) { KillTimer(m_nCheckForDragDropEventTimerID); m_nCheckForDragDropEventTimerID=0; } if(GetIcon()==NULL || ::GetCapture()!=GetSafeHwnd()) { COXCoolToolBar::OnMouseMove(nFlags, point); return; } CPoint ptTest=point; // handle mouse cursor movement over close, restore, minimize buttons // int hitTest=HitTest(ptTest,OX_MNU_CLIENT); hitTest=hitTest>=0 ? OX_MNU_NONE : hitTest; if(m_pressedBtn!=hitTest) { m_pressedBtn=(MENUBARHITTEST)hitTest; RedrawWindow(NULL,NULL,RDW_INVALIDATE|RDW_UPDATENOW|RDW_FRAME); } COXCoolToolBar::OnMouseMove(nFlags, point); } void COXMenuBar::OnKillFocus(CWnd* pNewWnd) { COXCoolToolBar::OnKillFocus(pNewWnd); // TODO: Add your message handler code here // reset the surfing mode m_bIsInSurfingMode=FALSE; } void COXMenuBar::OnTimer(UINT nIDEvent) { if((int)nIDEvent==m_nCheckForDragDropEventTimerID) { KillTimer(m_nCheckForDragDropEventTimerID); m_nCheckForDragDropEventTimerID=0; if(::IsWindow(GetSafeHwnd())) { // do drag and drop // if(::GetKeyState(VK_LBUTTON)<0 && IsInAdvancedCustomizationMode()) { if(m_nWouldBeDraggedItem>=0 && m_nWouldBeDraggedItem SendMessage(WM_NOTIFY,(WPARAM)nmtb.hdr.idFrom,(LPARAM)&nmtb); m_nWouldBeDraggedItem=-1; } } // //////////////////////////////////// } return; } COXCoolToolBar::OnTimer(nIDEvent); } void COXMenuBar::OnSettingChange(UINT uFlags, LPCTSTR lpszSection) { UpdateMenuMetrics(); COXCoolToolBar::OnSettingChange(uFlags, lpszSection); } BOOL COXMenuBar::OnTBNBeginDrag(NMHDR* pNMHDR, LRESULT* pResult) { NMTOOLBAR* pNMToolBar=(NMTOOLBAR*)pNMHDR; int nIndex=CommandToIndex(pNMToolBar->iItem); #ifdef OX_CUSTOMIZE_COMMANDS if(IsInAdvancedCustomizationMode()) { int nState=GetToolBarCtrl().GetState(GetItemID(nIndex)); if((nState&TBSTATE_PRESSED)!=0) { GetToolBarCtrl().SetState(GetItemID(nIndex),nState&~TBSTATE_PRESSED); } CWnd* pParentWnd=GetParent(); ASSERT(pParentWnd!=NULL); pNMToolBar->hdr.code=TBN_QUERYDELETE; if(pParentWnd->SendMessage(WM_NOTIFY,pNMToolBar->hdr.idFrom, (LPARAM)pNMToolBar)) { SendCustomizeNotification(ID_OXCUSTMB_RESET_POPUP_MENU); BOOL bWasInAdvancedCustomizationMode=IsInAdvancedCustomizationMode(); if(GetCustomizedButton()!=nIndex) { SetCustomizedButton(nIndex); } SetDraggedButton(nIndex); // mark the control as the one that launched drag'n'drop operation m_bDragDropOwner=TRUE; CMenu* pMenu=CMenu::FromHandle(GetMenu()); ASSERT(pMenu!=NULL); CString sText; pMenu->GetMenuString(nIndex,sText,MF_BYPOSITION); HMENU hSubmenu=::GetSubMenu(pMenu->GetSafeHmenu(),nIndex); UINT nCmdID=pMenu->GetMenuItemID(nIndex); if(nCmdID==0xffff) { nCmdID=(UINT)-1; } COleDataSource* pDataSource=COXDragDropCommands::PrepareDragDropData( sText,-1/*image index*/,nCmdID/*command ID*/,0/*button style*/,hSubmenu); ASSERT(pDataSource!=NULL); m_bDragDropOperation=TRUE; DROPEFFECT dropEffect= COXDragDropCommands::DoDragDrop(pDataSource,GetDropSource()); if(DROPEFFECT_MOVE==dropEffect || (DROPEFFECT_NONE==dropEffect && ::GetKeyState(VK_LBUTTON)>=0 && !m_bDragDropOperation)) { int nDraggedButtonIndex=GetDraggedButton(); OnRemoveDraggedButton(nDraggedButtonIndex); } SetDraggedButton(-1); //delete drag source (we are responsible to do that) delete pDataSource; // unmark as the control which launched drag'n'drop operation m_bDragDropOwner=FALSE; if(!bWasInAdvancedCustomizationMode) { SetCustomizedButton(-1); } } } #else UNREFERENCED_PARAMETER(nIndex); #endif // OX_CUSTOMIZE_COMMANDS *pResult=0; return FALSE; } LONG COXMenuBar::OnDragOver(WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(wParam); // toolbar must be in advanced customizable state if(!IsCustomizable(TRUE)) return (LONG)FALSE; // lParam is the pointer to SHBDROPTARGETACTION structure LPSHBDROPTARGETACTION pSHBDTAction=(LPSHBDROPTARGETACTION)lParam; ASSERT(pSHBDTAction!=NULL); ASSERT(pSHBDTAction->pWnd); ASSERT(pSHBDTAction->pWnd->GetSafeHwnd()==GetSafeHwnd()); pSHBDTAction->result=(LRESULT)DROPEFFECT_NONE; #ifdef OX_CUSTOMIZE_COMMANDS // Can we use this object? if(pSHBDTAction->pDataObject-> IsDataAvailable(COXDragDropCommands::m_cfCommandButton)) { BOOL bQualified=!(m_bDragDropOwner && (pSHBDTAction->dwKeyState & MK_CONTROL)==MK_CONTROL); if(bQualified) { BOOL bAllowToDrop=TRUE; if(!(m_bDragDropOwner && (pSHBDTAction->dwKeyState & MK_CONTROL)!=MK_CONTROL)) { // Get the drag item info // HGLOBAL hgData=pSHBDTAction->pDataObject-> GetGlobalData(COXDragDropCommands::m_cfCommandButton); ASSERT(hgData!=NULL); // lock it BYTE* lpItemData=(BYTE*)::GlobalLock(hgData); // get button command ID int nCommandID=*(int*)lpItemData; lpItemData+=sizeof(int); // get button text CString sText((LPTSTR)lpItemData); lpItemData+=(sText.GetLength()+1)*sizeof(TCHAR); // unlock it ::GlobalUnlock(hgData); // free it ::GlobalFree(hgData); if(nCommandID==0) { bAllowToDrop=FALSE; } if(sText.IsEmpty()) { bAllowToDrop=FALSE; } if(GetCustomButtonIndex(nCommandID)!=-1) { bQualified=FALSE; } } if(!bAllowToDrop && !IsInAdvancedCustomizationMode()) { bQualified=FALSE; } if(bQualified) { // analize the current cursor position // CPoint point=pSHBDTAction->point; int nButtonIndex=COXCoolToolBar::HitTest(&point); BOOL bIsOut=(nButtonIndex<0); nButtonIndex=(bIsOut ? -nButtonIndex : nButtonIndex); if(nButtonIndex>=GetToolBarCtrl().GetButtonCount() && GetToolBarCtrl().GetButtonCount()>0) { nButtonIndex=-1; bQualified=FALSE; } else { if(nButtonIndex!=GetCustomizedButton()) { SetCustomizedButton(nButtonIndex); if(!(m_bDragDropOwner && nButtonIndex==GetDraggedButton())) { DisplayPopupMenu(nButtonIndex); } } if(bAllowToDrop) { CWnd* pParentWnd=GetParent(); ASSERT(pParentWnd!=NULL); NMTOOLBAR nmtb; nmtb.hdr.hwndFrom=GetSafeHwnd(); nmtb.hdr.idFrom=GetDlgCtrlID(); nmtb.hdr.code=TBN_QUERYINSERT; nmtb.iItem=nButtonIndex; if(!pParentWnd-> SendMessage(WM_NOTIFY,nmtb.hdr.idFrom,(LPARAM)&nmtb)) { bQualified=FALSE; } else { TBINSERTMARK tbim; tbim.iButton=nButtonIndex; tbim.dwFlags=0; CRect rectItem; GetItemRect(tbim.iButton,rectItem); if(point.x>=rectItem.left+rectItem.Width()/2 || point.x<0) { tbim.dwFlags=TBIMHT_AFTER; } SetInsertMark(&tbim); // Check if the control key was pressed if((pSHBDTAction->dwKeyState & MK_CONTROL)==MK_CONTROL) { pSHBDTAction->result=(LRESULT)DROPEFFECT_COPY; } else { pSHBDTAction->result=(LRESULT)DROPEFFECT_MOVE; } } } } } } if(!bQualified) { SetInsertMark(-1); } } #endif // OX_CUSTOMIZE_COMMANDS return (LONG)TRUE; } LONG COXMenuBar::OnDrop(WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(wParam); if(!IsCustomizable(TRUE)) return (LONG)FALSE; // lParam is the pointer to SHBDROPTARGETACTION structure LPSHBDROPTARGETACTION pSHBDTAction=(LPSHBDROPTARGETACTION)lParam; ASSERT(pSHBDTAction!=NULL); ASSERT(pSHBDTAction->pWnd); ASSERT(pSHBDTAction->pWnd->GetSafeHwnd()==GetSafeHwnd()); pSHBDTAction->result=(LRESULT)FALSE; #ifdef OX_CUSTOMIZE_COMMANDS // if dragged item is to be copied or moved if((pSHBDTAction->dropEffect&DROPEFFECT_COPY)!=0 || (pSHBDTAction->dropEffect&DROPEFFECT_MOVE)!=0) { // data must be in the specific format ASSERT(pSHBDTAction->pDataObject-> IsDataAvailable(COXDragDropCommands::m_cfCommandButton)); TBINSERTMARK tbim; GetInsertMark(&tbim); int nButtonIndex=tbim.iButton; // remove insert mark SetInsertMark(-1); if(nButtonIndex!=-1 || GetToolBarCtrl().GetButtonCount()==0) { int nDraggedButtonIndex=GetDraggedButton(); if(m_bDragDropOwner && (pSHBDTAction->dropEffect&DROPEFFECT_COPY)==0) { ASSERT(GetToolBarCtrl().GetButtonCount()>0); ASSERT(nDraggedButtonIndex!=-1); if(nButtonIndex==nDraggedButtonIndex) { pSHBDTAction->result=(LRESULT)FALSE; return (LONG)TRUE; } } nButtonIndex=(tbim.dwFlags==0 ? nButtonIndex : nButtonIndex+1); int nButtonCount=GetToolBarCtrl().GetButtonCount(); if(nButtonIndex==-1) { ASSERT(nButtonCount==0 && !m_bDragDropOwner); nButtonIndex=0; } else if(nButtonIndex>nButtonCount) { nButtonIndex=nButtonCount; } HMENU hMenu=GetMenu(); ASSERT(hMenu!=NULL); // Get the drag item info // HGLOBAL hgData=pSHBDTAction->pDataObject-> GetGlobalData(COXDragDropCommands::m_cfCommandButton); ASSERT(hgData!=NULL); // lock it BYTE* lpItemData=(BYTE*)::GlobalLock(hgData); RetrieveDragDropMenuItem(lpItemData,hMenu,nButtonIndex); // unlock it ::GlobalUnlock(hgData); // free it ::GlobalFree(hgData); // update dragged item position if(nButtonIndexresult=(LRESULT)TRUE; MarkAsChanged(); DrawMenuBar(); } else { pSHBDTAction->result=(LRESULT)FALSE; } } #endif // OX_CUSTOMIZE_COMMANDS m_bDragDropOperation=FALSE; // we handled the message return (LONG)TRUE; } void COXMenuBar::RetrieveDragDropMenuItem(BYTE*& lpData, HMENU hMenu, int nButtonIndex) { ASSERT(lpData!=NULL); ASSERT(hMenu!=NULL); ASSERT(::IsMenu(hMenu)); while(TRUE) { // get button command ID int nCommandID=*(int*)lpData; lpData+=sizeof(int); // get button text CString sText((LPTSTR)lpData); lpData+=(sText.GetLength()+1)*sizeof(TCHAR); // get button image index int nImageIndex=*(int*)lpData; lpData+=sizeof(int); UNREFERENCED_PARAMETER(nImageIndex); // get button style BYTE fsStyle=*(BYTE*)lpData; lpData+=sizeof(BYTE); UNREFERENCED_PARAMETER(fsStyle); // get finish flag int nFinish=*(int*)lpData; lpData+=sizeof(int); // update menu if(nCommandID==-1) { HMENU hSubMenu=::CreatePopupMenu(); ASSERT(hSubMenu!=NULL); m_arrCreatedPopupMenus.Add(hSubMenu); VERIFY(::InsertMenu(hMenu,nButtonIndex, MF_BYPOSITION|MF_POPUP|MF_STRING,(UINT_PTR)hSubMenu,sText)!=0); if(nFinish!=0) { RetrieveDragDropMenuItem(lpData,hSubMenu,0); } } else { VERIFY(::InsertMenu(hMenu,nButtonIndex, MF_BYPOSITION|(nCommandID==0 ? MF_SEPARATOR : MF_STRING), (UINT)nCommandID,sText)!=0); } nButtonIndex++; if(nFinish==0 || nFinish==2) { break; } } } void COXMenuBar::OnRemoveDraggedButton(int nButtonIndex) { // update menu buttons ID int nButtonCount=GetToolBarCtrl().GetButtonCount(); for(int nIndex=nButtonIndex+1; nIndexGetClientRect(rect); if(bHorz) { sizeResult.cx=-afxData.cxBorder2; sizeResult.cy=rect.Width()+afxData.cxBorder2; } else { sizeResult.cx=-afxData.cyBorder2; sizeResult.cy=rect.Height()+afxData.cyBorder2; } if(pWndFrame->IsKindOf(RUNTIME_CLASS(CFrameWnd))) { // find corresponding dock bar CRect rectDockBar; CWnd* pDockBar; if(bHorz) { pDockBar=((CFrameWnd*)pWndFrame)-> GetControlBar(AFX_IDW_DOCKBAR_TOP); if(pDockBar!=NULL) pDockBar=((CFrameWnd*)pWndFrame)-> GetControlBar(AFX_IDW_DOCKBAR_BOTTOM); } else { pDockBar=((CFrameWnd*)pWndFrame)-> GetControlBar(AFX_IDW_DOCKBAR_LEFT); if(pDockBar!=NULL) pDockBar=((CFrameWnd*)pWndFrame)-> GetControlBar(AFX_IDW_DOCKBAR_RIGHT); } if(pDockBar!=NULL) { pDockBar->GetWindowRect(rectDockBar); pDockBar->ScreenToClient(rectDockBar); if(bHorz) { sizeResult.cx=-afxData.cxBorder2; sizeResult.cy=rectDockBar.right+afxData.cyBorder2; } else { sizeResult.cx=-afxData.cxBorder2; sizeResult.cy=rectDockBar.bottom+afxData.cyBorder2; } } } return sizeResult; } BOOL COXMenuBar::IsCustomizable(BOOL bAdvanced/*=TRUE*/) const { return (bAdvanced ? TRUE : FALSE); } // global handle of the window that had focus before the menu bar // was set in the surfing mode HWND g_hWndHadFocus=NULL; BOOL COXMenuBar::SetSurfingMode(BOOL bIsInSurfingMode/*=TRUE*/, int nItem/*=0*/) { ASSERT(::IsWindow(GetSafeHwnd())); ASSERT(nItem==-1 || (nItem>=0 && nItem<=GetToolBarCtrl().GetButtonCount())); if(nItem==GetToolBarCtrl().GetButtonCount()) { nItem=-1; } if(bIsInSurfingMode==m_bIsInSurfingMode) { ASSERT(!m_bIsInSurfingMode || !IsInDisplayingMode()); ASSERT((m_bIsInSurfingMode && ::GetFocus()==m_hWnd) || (!m_bIsInSurfingMode && ::GetFocus()!=m_hWnd)); // just reset the hot item if(m_bIsInSurfingMode) { SendMessage(TB_SETHOTITEM,nItem); } return TRUE; } // double check if(bIsInSurfingMode && IsInDisplayingMode()) { TRACE(_T("COXMenuBar::SetSurfingMode: Cannot be set in the surfing mode while displaying popup menus\n")); return FALSE; } if(bIsInSurfingMode) { // save thae handle of the window that had focus g_hWndHadFocus=::GetFocus(); SetFocus(); // reset hot item SendMessage(TB_SETHOTITEM,nItem); if(!m_bStaySurfing) { // send WM_ENTERMENULOOP and WM_INITMENU messages. m_pFrameWnd->SendMessage(WM_ENTERMENULOOP,(WPARAM)FALSE); m_pFrameWnd->SendMessage(WM_INITMENU,(WPARAM)m_hMenu); // send WM_MENUSELECT message m_pFrameWnd->SendMessage(WM_MENUSELECT, MAKEWPARAM(nItem,MF_POPUP|MF_HILITE),(LPARAM)m_hMenu); } } else { g_hWndHadFocus=::IsWindow(g_hWndHadFocus) ? g_hWndHadFocus : NULL; // reset focus window ::SetFocus(g_hWndHadFocus); g_hWndHadFocus=NULL; // reset hot item SendMessage(TB_SETHOTITEM,(WPARAM)-1); } m_bIsInSurfingMode=bIsInSurfingMode; return TRUE; } void COXMenuBar::BookSpace(CRect& rectBookedSpace, DWORD dwMode) { // book some space for close, restore, minimize buttons if(dwMode&LM_HORZ) rectBookedSpace.right=CalcButtonRects(); else rectBookedSpace.bottom=CalcButtonRects(); } void COXMenuBar::DrawInBookedSpace(CDC& dc, CRect& rectToDrawIn) { if(GetIcon()!=NULL) { ASSERT(m_pFrameWnd!=NULL); if(m_pFrameWnd->IsKindOf(RUNTIME_CLASS(CMDIFrameWnd))) { // recalculate close, restore, minimize buttons rectangles CalcButtonRects(); // and draw them DrawButtons(dc); // update the rectangle that can be used by parent window to draw // additional elements if(m_dwStyle&CBRS_ORIENT_HORZ) rectToDrawIn.right=(!m_rectMinimizeBtn.IsRectEmpty() ? m_rectMinimizeBtn.left : (!m_rectRestoreBtn.IsRectEmpty() ? m_rectRestoreBtn.left : m_rectCloseBtn.left))-6; else rectToDrawIn.bottom=(!m_rectMinimizeBtn.IsRectEmpty() ? m_rectMinimizeBtn.top : (!m_rectRestoreBtn.IsRectEmpty() ? m_rectRestoreBtn.top : m_rectCloseBtn.top))-6; } } } BOOL COXMenuBar::SetMenu(HMENU hMenu) { ASSERT(::IsWindow(GetSafeHwnd())); if(m_hMenu==hMenu) return TRUE; SaveCustomizedMenu(); m_hMenu=hMenu; if(IsCustomizable(TRUE)) { CDocTemplate* pDocTemplate=NULL; if(!m_mapCustomizableMenus.Lookup(m_hMenu,pDocTemplate)) { CDocument* pDocument=NULL; CWnd* pWnd=AfxGetMainWnd(); CFrameWnd* pFrameWnd=DYNAMIC_DOWNCAST(CFrameWnd,pWnd); if(pFrameWnd!=NULL) { if(pFrameWnd->IsKindOf(RUNTIME_CLASS(CMDIFrameWnd))) { CMDIChildWnd* pChildWnd=((CMDIFrameWnd*)pFrameWnd)->MDIGetActive(); if(pChildWnd==NULL) { pDocument=NULL; } else { pDocument=pChildWnd->GetActiveDocument(); } } else { pDocument=pFrameWnd->GetActiveDocument(); } } pDocTemplate=(pDocument==NULL ? NULL : pDocument->GetDocTemplate()); BOOL bAlreadyExist=FALSE; POSITION pos=m_mapCustomizableMenus.GetStartPosition(); while(pos!=NULL) { CDocTemplate* pTestDocTemplate=NULL; HMENU hTestMenu=NULL; m_mapCustomizableMenus.GetNextAssoc(pos,hTestMenu,pTestDocTemplate); ASSERT(hTestMenu!=NULL); if(pTestDocTemplate==pDocTemplate) { bAlreadyExist=TRUE; break; } } if(!bAlreadyExist) { m_mapCustomizableMenus.SetAt(m_hMenu,pDocTemplate); #ifndef _UNICODE VERIFY(LoadMenuState(m_hMenu,(pDocument==NULL ? NULL : pDocument->GetRuntimeClass()->m_lpszClassName))); #else if(pDocument!=NULL) { LPCSTR lpszUniqueName= pDocument->GetRuntimeClass()->m_lpszClassName; int nLength=sizeof(lpszUniqueName)/sizeof(lpszUniqueName[0])+1; LPTSTR lpszUnicodeUniqueName=new TCHAR[nLength]; memset(lpszUnicodeUniqueName,0,nLength*sizeof(TCHAR)); _mbstowcsz(lpszUnicodeUniqueName,lpszUniqueName,nLength); VERIFY(LoadMenuState(m_hMenu,lpszUnicodeUniqueName)); delete[] lpszUnicodeUniqueName; } else { VERIFY(LoadMenuState(m_hMenu,NULL)); } #endif } } } // repopulate menubar return RecreateMenuBar(); } BOOL COXMenuBar::RecreateMenuBar(BOOL bRedraw/*=TRUE*/) { ASSERT(::IsWindow(GetSafeHwnd())); // preserve old settings int nOldDraggedButton=GetDraggedButton(); int nOldCustomizedButton=GetCustomizedButton(); // delete existing buttons CToolBarCtrl& tool=GetToolBarCtrl(); // don't redraw the menubar contents yet m_bNoInternalRedraw=TRUE; while(tool.DeleteButton(0)); m_bNoInternalRedraw=FALSE; // clean up accelerator table m_accelTable.RemoveAll(); // work out currently active MDIChild window icon (only for MDI applications) UpdateIcon(FALSE); BOOL bResult=TRUE; if(m_hMenu!=NULL) { // create one button for every menu item // CMenu menu; if(!menu.Attach(m_hMenu)) { return FALSE; } // number of menu items int nItems=menu.GetMenuItemCount(); CString sMenuItem; TBBUTTON* pButtons=new TBBUTTON[nItems]; // add buttons and set text to them for(int nIndex=0; nIndex=0 && nOldDraggedButton=0 && nOldCustomizedButtonIsKindOf(RUNTIME_CLASS(CFrameWnd))) ((CFrameWnd*)m_pFrameWnd)->ShowControlBar(this,FALSE,FALSE); else ShowWindow(SW_HIDE); } else { if(bRedraw) { // redraw the toolbar if specified RedrawToolBar(TRUE,TRUE); m_bDelayedButtonLayout=TRUE; } if(m_pFrameWnd->IsKindOf(RUNTIME_CLASS(CFrameWnd))) { ((CFrameWnd*)m_pFrameWnd)->ShowControlBar(this,TRUE,FALSE); } else { CRect rect; m_pFrameWnd->GetClientRect(rect); CSize szToolbar=CalcFixedLayout(TRUE,TRUE); rect.top-=2; rect.bottom=rect.top+szToolbar.cy; MoveWindow(rect); ShowWindow(SW_SHOWNA); } } return bResult; } void COXMenuBar::UpdateIcon(BOOL bRedraw/*=TRUE*/) { ASSERT(::IsWindow(GetSafeHwnd())); // refresh the icon HICON hIcon=NULL; if(m_pFrameWnd->IsKindOf(RUNTIME_CLASS(CMDIFrameWnd))) { BOOL bMaximize=FALSE; CMDIChildWnd* pChild=((CMDIFrameWnd*)m_pFrameWnd)-> MDIGetActive(&bMaximize); if(pChild!=NULL && bMaximize) { hIcon=(HICON)(INT_PTR)::GetClassLongPtr(pChild->m_hWnd,GCL_HICONSM); if(hIcon==NULL) hIcon=(HICON)(INT_PTR)::GetClassLongPtr(pChild->m_hWnd,GCL_HICON); if(hIcon==NULL) { if(!::SendMessageTimeout(pChild->m_hWnd, WM_GETICON,ICON_SMALL,0,SMTO_ABORTIFHUNG,1000, (LPDWORD)&hIcon) || hIcon==NULL) { ::SendMessageTimeout(pChild->m_hWnd, WM_GETICON,ICON_BIG,0,SMTO_ABORTIFHUNG,1000, (LPDWORD)&hIcon); } if(hIcon==NULL) hIcon=::LoadIcon(NULL,IDI_WINLOGO); } } } if(hIcon!=GetIcon()) SetIcon(hIcon,bRedraw); } void COXMenuBar::DisplayPopupMenu(int nMenuItem) { ASSERT(m_hMenu!=NULL); ASSERT((nMenuItem>=0 && nMenuItem<::GetMenuItemCount(m_hMenu)) || (GetIcon()!=NULL && nMenuItem==::GetMenuItemCount(m_hMenu))); if (IsInAdvancedCustomizationMode()) SaveCustomizedMenu(); if(m_hMenu==NULL || nMenuItem<0 || nMenuItem>::GetMenuItemCount(m_hMenu) || (GetIcon()==NULL && nMenuItem==::GetMenuItemCount(m_hMenu)) || (::GetMenuItemID(m_hMenu,nMenuItem)!=-1 && ::GetMenuItemID(m_hMenu,nMenuItem)!=0xffff)) { // make sure the state of previously active button is restored if (m_hMenu && IsInSurfingMode()) { CMenu* pMenu=CMenu::FromHandle(m_hMenu); ASSERT(pMenu); CMenu* pSubMenu=pMenu->GetSubMenu(nMenuItem); ASSERT(pSubMenu==NULL); UINT nID=pMenu->GetMenuItemID(nMenuItem); CWnd* pMainWnd=AfxGetMainWnd(); pMainWnd->SendMessage(WM_COMMAND,nID); } RestoreMenuButton(); return; } BOOL bWasInDisplayingMode=IsInDisplayingMode(); // reset the surfing mode BOOL bWasInSurfingMode=IsInSurfingMode(); SetSurfingMode(FALSE); // if system menu should be displayed BOOL bSysMenu=(nMenuItem==::GetMenuItemCount(m_hMenu)); CMenu* pPopup=NULL; if(bSysMenu) { if(IsInAdvancedCustomizationMode()) return; // work out system menu ASSERT_KINDOF(CMDIFrameWnd,m_pFrameWnd); BOOL bMaximize=FALSE; CMDIChildWnd* pChild=((CMDIFrameWnd*)m_pFrameWnd)-> MDIGetActive(&bMaximize); ASSERT(pChild!=NULL && bMaximize); if(pChild==NULL || !bMaximize) return; pPopup=pChild->GetSystemMenu(FALSE); } else { // work out popup menu CMenu* pMenu=CMenu::FromHandle(m_hMenu); ASSERT(pMenu!=NULL); if(pMenu!=NULL && (pMenu->GetMenuState(nMenuItem,MF_BYPOSITION)& (MF_DISABLED|MF_GRAYED))==0) { pPopup=pMenu->GetSubMenu(nMenuItem); } } if(pPopup==NULL && !IsInAdvancedCustomizationMode()) { // make sure the state of previously active button is restored RestoreMenuButton(); return; } ASSERT(m_pFrameWnd!=NULL); if(!bWasInSurfingMode) { // send WM_ENTERMENULOOP and WM_INITMENU messages. if(!bWasInDisplayingMode) { m_pFrameWnd->SendMessage(WM_ENTERMENULOOP,(WPARAM)FALSE); m_pFrameWnd->SendMessage(WM_INITMENU,(WPARAM)m_hMenu); } // send WM_MENUSELECT message m_pFrameWnd->SendMessage(WM_MENUSELECT,MAKEWPARAM((bSysMenu ? 0 : nMenuItem), ((bSysMenu ? MF_SYSMENU : MF_POPUP|MF_HILITE))),(LPARAM)m_hMenu); } UINT nFlags=TPM_LEFTBUTTON; CRect rect; GetItemRect(nMenuItem,&rect); // translate the current toolbar item rectangle into screen coordinates // so that we'll know where to pop up the menu ClientToScreen(&rect); // Attach the COXBitmapMenu object if not done already COXBitmapMenu* pBitmapMenu = DYNAMIC_DOWNCAST(COXBitmapMenu, pPopup); BOOL bConvert = FALSE; COXBitmapMenuOrganizer* pOrganizer = COXBitmapMenuOrganizer::FindOrganizer(AfxGetMainWnd()->GetSafeHwnd()); if (pOrganizer != NULL) { if (pBitmapMenu == NULL) { pBitmapMenu = new COXBitmapMenu(); TRACE(_T("\nCreated menu at %x - Line: %d, %s"), pBitmapMenu, __LINE__, __FILE__); pBitmapMenu->Attach(pPopup->Detach()); pPopup = (CMenu *) pBitmapMenu; pOrganizer->m_BitmapMenuList.AddTail(pBitmapMenu); bConvert = TRUE; } pOrganizer->ConvertBitmapMenu(pBitmapMenu, bConvert); } // Determine top left point of the popup menu CPoint ptPos; UINT nDummy; COXBitmapMenu::DeterminePosition(pPopup, rect, m_dwStyle, ptPos, nFlags, nDummy); // make sure the state of previously active button is restored RestoreMenuButton(); // set current active item m_nActiveMenuItem=nMenuItem; m_nActivateNextItem=-1; // set button to pressed state CToolBarCtrl& tool=GetToolBarCtrl(); if(!IsInAdvancedCustomizationMode()) { tool.PressButton(m_nActiveMenuItem+ID_CMDBASE); } // display popup menu CWnd* pWndOwner=AfxGetMainWnd(); if(pPopup!=NULL) { if(IsInAdvancedCustomizationMode()) { OXCUSTOMIZEPOPUPMENUINFO cpmi; cpmi.hMenu=pPopup->GetSafeHmenu(); cpmi.nFlags=nFlags; cpmi.ptStart = ptPos; SendCustomizeNotification(ID_OXCUSTMB_CUSTOMIZE_POPUP_MENU,(LPARAM)&cpmi); m_nForbiddenItem=-1; RestoreMenuButton(); } else { if (pBitmapMenu != NULL) pBitmapMenu->TrackPopupMenu(this, pWndOwner); else pPopup->TrackPopupMenu(nFlags, ptPos.x, ptPos.y, pWndOwner, rect); // while deactivating popup menu the user could have set to // activate another menu item. In this case just post the // corresponding message if(m_nActivateNextItem!=-1) { PostMessage(WM_DISPLAYPOPUPMENU,m_nActivateNextItem); } else { // Check whether we are still on the original button CPoint cursorPos; GetCursorPos(&cursorPos); ScreenToClient(&cursorPos); #if _MFC_VER>0x0421 int hitPos=tool.HitTest(&cursorPos); #else int hitPos=tool.SendMessage(TB_HITTEST,0,(LPARAM)&cursorPos); #endif if(hitPos==m_nActiveMenuItem) { // Don't allow it to drop down again m_nForbiddenItem=m_nActiveMenuItem; } RestoreMenuButton(); } } } } void COXMenuBar::RestoreMenuButton() { // set button to unpressed state if(m_nActiveMenuItem!=-1) { CToolBarCtrl& tool=GetToolBarCtrl(); tool.PressButton(m_nActiveMenuItem+ID_CMDBASE,FALSE); int nSavedActiveMenuItem=m_nActiveMenuItem; m_nActiveMenuItem=-1; if(m_nActivateNextItem==-1 && !m_bStaySurfing) { // send WM_EXITMENULOOP message m_pFrameWnd->SendMessage(WM_EXITMENULOOP,(WPARAM)FALSE); } if(m_bStaySurfing) { SetSurfingMode(TRUE,nSavedActiveMenuItem); // reset forbidden item m_nForbiddenItem=-1; } m_bStaySurfing=FALSE; } } int COXMenuBar::CalcButtonRects() { m_rectCloseBtn.SetRectEmpty(); m_rectRestoreBtn.SetRectEmpty(); m_rectMinimizeBtn.SetRectEmpty(); // total width of buttons int nButtonsWidth=0; if(GetIcon()!=NULL) { ASSERT(m_pFrameWnd!=NULL); ASSERT(::IsWindow(m_pFrameWnd->m_hWnd)); ASSERT_KINDOF(CMDIFrameWnd,m_pFrameWnd); BOOL bMaximize=FALSE; CMDIChildWnd* pChild=((CMDIFrameWnd*)m_pFrameWnd)-> MDIGetActive(&bMaximize); if(pChild==NULL || !bMaximize) return nButtonsWidth; nButtonsWidth=2; DWORD dwStyle=pChild->GetStyle(); // buttons metrics int cxIcon=18; int cyIcon=18; BOOL bHorz=(m_dwStyle&CBRS_ORIENT_HORZ); CRect rectToDrawIn; GetWindowRect(rectToDrawIn); rectToDrawIn-=rectToDrawIn.TopLeft(); // center the button images depending on orientation int nOffset=0; if(bHorz) { if(rectToDrawIn.Height()DrawMenuButtons(&dc, this); } int COXMenuBar::HitTest(const CPoint& ptTest, HITTESTORIGIN Origin/*=OX_MNU_ZEROBASED*/) const { CPoint point=ptTest; CRect rect; // update the test point depending on origin switch(Origin) { case OX_MNU_ZEROBASED: break; case OX_MNU_CLIENT: GetWindowRect(rect); ScreenToClient(rect); point-=rect.TopLeft(); break; case OX_MNU_SCREEN: GetWindowRect(rect); point-=rect.TopLeft(); break; } int hitTest; if(m_iconRect.PtInRect(point)) hitTest=OX_MNU_ICON; else if(m_rectCloseBtn.PtInRect(point)) hitTest=OX_MNU_CLOSEBTN; else if(m_rectRestoreBtn.PtInRect(point)) hitTest=OX_MNU_RESTOREBTN; else if(m_rectMinimizeBtn.PtInRect(point)) hitTest=OX_MNU_MINIMIZEBTN; else { // find corresponding menu item // hitTest=OX_MNU_NONE; CRect rectClient; GetClientRect(rectClient); if(rectClient.PtInRect(point)) { GetWindowRect(rect); ScreenToClient(rect); point+=rect.TopLeft(); CToolBarCtrl& tool=GetToolBarCtrl(); for(int nIndex=0; nIndexSendMessage(WM_KEYDOWN,nChar,1)) return TRUE; ASSERT(::IsWindow(m_hWnd)); BOOL bHandled=FALSE; if(nChar==0) { // ALT key was pressed ASSERT(!IsInDisplayingMode()); int nHotItem=PtrToInt(SendMessage(TB_GETHOTITEM)); nHotItem=nHotItem==-1 ? 0 : nHotItem; // set the menu bar in surfing mode when user presses ALT key SetSurfingMode(!IsInSurfingMode(),nHotItem); if(!IsInSurfingMode()) { // send WM_EXITMENULOOP message m_pFrameWnd->SendMessage(WM_EXITMENULOOP,(WPARAM)FALSE); } bHandled=TRUE; } else if(nChar==VK_ESCAPE && IsInSurfingMode()) { // Esc key was pressed in surfing mode int nHotItem=PtrToInt(SendMessage(TB_GETHOTITEM)); nHotItem=nHotItem==-1 ? 0 : nHotItem; SetSurfingMode(FALSE,nHotItem); // send WM_EXITMENULOOP message m_pFrameWnd->SendMessage(WM_EXITMENULOOP,(WPARAM)FALSE); bHandled=TRUE; } else { int nItemCount=GetToolBarCtrl().GetButtonCount(); if(nItemCount==0) return FALSE; // handle keys depending on their values, menu bar // orientation sand the mode it is currently in switch(nChar) { case VK_LEFT: if(m_dwStyle & CBRS_ORIENT_HORZ) { if(IsInSurfingMode()) { // in surfing mode just navigate through menu items int nItem=PtrToInt(SendMessage(TB_GETHOTITEM)); // retrieve the item that preceedes the current hot one nItem=GetPrevMenuItem(nItem); // set it to hot state SendMessage(TB_SETHOTITEM, (nItem>=0 && nItemSendMessage(WM_MENUSELECT, MAKEWPARAM((bSysMenu ? 0 : nItem), ((bSysMenu ? MF_SYSMENU : MF_POPUP|MF_HILITE))), (LPARAM)m_hMenu); bHandled=TRUE; } else if(IsInDisplayingMode()) { // in displaying mode we activate the preceeding menu item int nItem=GetPrevMenuItem(m_nActiveMenuItem); if(nItem!=m_nActiveMenuItem) { if((::GetMenuItemID(m_hMenu,nItem)==-1 || ::GetMenuItemID(m_hMenu,nItem)==0xffff)) { m_nActivateNextItem=nItem; // emulate mouse click // CRect rect; if(GetIcon()!=NULL && nItem==nItemCount) { GetToolBarCtrl().GetItemRect(0,rect); rect.DeflateRect(1,1); rect.OffsetRect(-::GetSystemMetrics(SM_CXSMICON),0); } else { GetToolBarCtrl().GetItemRect(nItem,rect); } CPoint point(rect.left+rect.Width()/2, rect.top+rect.Height()/2); PostMessage(WM_LBUTTONDOWN,MK_LBUTTON, MAKELPARAM(point.x,point.y)); PostMessage(WM_LBUTTONUP,MK_LBUTTON, MAKELPARAM(point.x,point.y)); ////////////////////////////// } bHandled=TRUE; } } } else { if(IsInSurfingMode()) { // in surfing mode activate the currently hot item int nItem=PtrToInt(SendMessage(TB_GETHOTITEM)); nItem=nItem==-1 ? nItemCount : nItem; DisplayPopupMenu(nItem); bHandled=TRUE; } } break; case VK_RIGHT: if(m_dwStyle & CBRS_ORIENT_HORZ) { if(IsInSurfingMode()) { // in surfing mode just navigate through menu items int nItem=PtrToInt(SendMessage(TB_GETHOTITEM)); // retrieve the item that followss the current hot one nItem=GetNextMenuItem(nItem); // set it to hot state SendMessage(TB_SETHOTITEM, (nItem>=0 && nItemSendMessage(WM_MENUSELECT, MAKEWPARAM((bSysMenu ? 0 : nItem), ((bSysMenu ? MF_SYSMENU : MF_POPUP|MF_HILITE))), (LPARAM)m_hMenu); bHandled=TRUE; } else if(IsInDisplayingMode()) { // in displaying mode we activate the following menu item int nItem=GetNextMenuItem(m_nActiveMenuItem); if(nItem!=m_nActiveMenuItem) { if((::GetMenuItemID(m_hMenu,nItem)==-1 || ::GetMenuItemID(m_hMenu,nItem)==0xffff)) { m_nActivateNextItem=nItem; // emulate mouse click // CRect rect; if(GetIcon()!=NULL && nItem==nItemCount) { GetToolBarCtrl().GetItemRect(0,rect); rect.DeflateRect(1,1); rect.OffsetRect(-::GetSystemMetrics(SM_CXSMICON),0); } else { GetToolBarCtrl().GetItemRect(nItem,rect); } CPoint point(rect.left+rect.Width()/2, rect.top+rect.Height()/2); PostMessage(WM_LBUTTONDOWN,MK_LBUTTON, MAKELPARAM(point.x,point.y)); PostMessage(WM_LBUTTONUP,MK_LBUTTON, MAKELPARAM(point.x,point.y)); //////////////////////////// } bHandled=TRUE; } } } else { if(IsInSurfingMode()) { // in surfing mode activate the currently hot item int nItem=PtrToInt(SendMessage(TB_GETHOTITEM)); nItem=nItem==-1 ? nItemCount : nItem; DisplayPopupMenu(nItem); bHandled=TRUE; } } break; case VK_UP: if(m_dwStyle & CBRS_ORIENT_VERT) { if(IsInSurfingMode()) { // in surfing mode just navigate through menu items int nItem=PtrToInt(SendMessage(TB_GETHOTITEM)); nItem=GetPrevMenuItem(nItem); SendMessage(TB_SETHOTITEM, (nItem>=0 && nItemSendMessage(WM_MENUSELECT, MAKEWPARAM((bSysMenu ? 0 : nItem), ((bSysMenu ? MF_SYSMENU : MF_POPUP|MF_HILITE))), (LPARAM)m_hMenu); bHandled=TRUE; } } else { if(IsInSurfingMode()) { // in surfing mode activate the currently hot item int nItem=PtrToInt(SendMessage(TB_GETHOTITEM)); nItem=nItem==-1 ? nItemCount : nItem; DisplayPopupMenu(nItem); bHandled=TRUE; } } break; case VK_DOWN: if(m_dwStyle & CBRS_ORIENT_VERT) { if(IsInSurfingMode()) { // in surfing mode just navigate through menu items int nItem=PtrToInt(SendMessage(TB_GETHOTITEM)); nItem=GetNextMenuItem(nItem); SendMessage(TB_SETHOTITEM, (nItem>=0 && nItem=0) { // try to find the matching key in accelerator table int nMenuItem=-1; TCHAR sHotKey=(TCHAR)nChar; // the key strokes passed in to the OnKeyDown handlers are always as // capital letters, there is no need to convert characters to capitals again // this will only cause problems with extended keyboard keys (ie num-pad) //_tcsupr(&sHotKey); if(m_accelTable.Lookup(sHotKey,nMenuItem)) { ASSERT(nMenuItem>=0 && nMenuItemrectClient.right) nItem=GetIcon()!=NULL ? nItemCount : 0; } return nItem; } int COXMenuBar::GetNextMenuItem(int nItem, BOOL bEnsureVisible/*=TRUE*/) { int nItemCount=GetToolBarCtrl().GetButtonCount(); nItem=nItem==-1 ? ((GetIcon()!=NULL) ? nItemCount : 0) : nItem; if(GetIcon()!=NULL) nItem=nItem==nItemCount ? 0 : nItem+1; else nItem=nItem==nItemCount-1 ? 0 : nItem+1; if(bEnsureVisible && nItem!=nItemCount) { // make sure the button rectangle is within menubar client area // CRect rectClient; GetClientRect(rectClient); CRect rectItem; GetItemRect(nItem,rectItem); if(rectItem.left>rectClient.right) nItem=GetIcon()!=NULL ? nItemCount : 0; } return nItem; } void COXMenuBar::UpdateMenuMetrics(BOOL bRedraw/*=TRUE*/) { ASSERT(::IsWindow(GetSafeHwnd())); if((HFONT)m_fontMenu!=NULL) m_fontMenu.DeleteObject(); // Menu font, height and color NONCLIENTMETRICS ncm={ sizeof(ncm) }; SystemParametersInfo(SPI_GETNONCLIENTMETRICS,sizeof(ncm),&ncm,0); VERIFY(m_fontMenu.CreateFontIndirect(&ncm.lfMenuFont)); SetFont(&m_fontMenu,TRUE); if(GetToolBarCtrl().GetButtonCount()>0) { GetToolBarCtrl().AutoSize(); CRect rect; GetToolBarCtrl().GetItemRect(0,&rect); #if _MFC_VER<=0x0421 SetHeight(rect.Height()+6); #else SetHeight(rect.Height()+3); #endif GetToolBarCtrl().SetButtonSize(rect.Size()); } SetDefaultTextColor(::GetSysColor(COLOR_MENUTEXT)); if(bRedraw) { // redraw the toolbar if specified RedrawToolBar(); } } BOOL COXMenuBar::SaveBarState(LPCTSTR lpszSubKey, LPCTSTR lpszValueName, BOOL bProperties) { UNREFERENCED_PARAMETER(lpszSubKey); UNREFERENCED_PARAMETER(lpszValueName); UNREFERENCED_PARAMETER(bProperties); #ifndef _MAC if(IsCustomizable(TRUE)) { POSITION pos=m_mapChangedMenus.GetStartPosition(); while(pos!=NULL) { HMENU hMenu=NULL; int nIndex=-1; m_mapChangedMenus.GetNextAssoc(pos,hMenu,nIndex); ASSERT(hMenu!=NULL); CDocTemplate* pDocTemplate=NULL; VERIFY(m_mapCustomizableMenus.Lookup(hMenu,pDocTemplate)); CDocument* pDocument=NULL; if(pDocTemplate!=NULL) { POSITION pos=pDocTemplate->GetFirstDocPosition(); ASSERT(pos!=NULL); pDocument=pDocTemplate->GetNextDoc(pos); ASSERT(pDocument!=NULL); } #ifndef _UNICODE VERIFY(SaveMenuState(hMenu,(pDocument==NULL ? NULL : pDocument->GetRuntimeClass()->m_lpszClassName))); #else if(pDocument!=NULL) { LPCSTR lpszUniqueName=pDocument->GetRuntimeClass()->m_lpszClassName; int nLength=sizeof(lpszUniqueName)/sizeof(lpszUniqueName[0])+1; LPTSTR lpszUnicodeUniqueName=new TCHAR[nLength]; memset(lpszUnicodeUniqueName,0,nLength*sizeof(TCHAR)); _mbstowcsz(lpszUnicodeUniqueName,lpszUniqueName,nLength); VERIFY(SaveMenuState(hMenu,lpszUnicodeUniqueName)); delete[] lpszUnicodeUniqueName; } else { VERIFY(SaveMenuState(hMenu,NULL)); } #endif m_mapChangedMenus.RemoveKey(hMenu); } } return TRUE; #else return FALSE; #endif } // Load from registry state of menus BOOL COXMenuBar::LoadBarState(LPCTSTR lpszSubKey, LPCTSTR lpszValueName, BOOL bProperties) { UNREFERENCED_PARAMETER(lpszSubKey); UNREFERENCED_PARAMETER(lpszValueName); UNREFERENCED_PARAMETER(bProperties); #ifndef _MAC return TRUE; #else return FALSE; #endif } BOOL COXMenuBar::SaveMenuState(HMENU hMenu, LPCTSTR lpszSubKey) { #ifndef _MAC ASSERT(hMenu!=NULL); ASSERT(::IsMenu(hMenu)!=NULL); if(!IsCustomizable(TRUE)) return FALSE; CWinApp* pApp=AfxGetApp(); CString sProfileName=lpszSubKey; if(sProfileName.IsEmpty()) sProfileName=_T("Menu_Default~!@#$#$%^"); else sProfileName=_T("Menu_")+sProfileName; CString sValueName=_T("MenuItems"); CMemFile memFile; CArchive ar(&memFile,CArchive::store); VERIFY(SaveMenuContents(hMenu,ar)); ar.Close(); int nBufferLength=(int)memFile.GetLength(); ASSERT(nBufferLength>0); BYTE* pBuffer=memFile.Detach(); pApp->WriteProfileBinary(sProfileName,sValueName,pBuffer,nBufferLength); ::free((void*)pBuffer); sValueName=_T("MenuDataSize"); pApp->WriteProfileInt(sProfileName,sValueName,nBufferLength); if(m_pFrameWnd!=NULL) { // notify parent that the state of menu is being saved. Parent window // might save any additional info m_pFrameWnd->SendMessage(WM_OX_SAVEMENUSTATE,(WPARAM)hMenu, (LPARAM)(LPCTSTR)sProfileName); } return TRUE; #else return FALSE; #endif } BOOL COXMenuBar::LoadMenuState(HMENU hMenu, LPCTSTR lpszSubKey) { #ifndef _MAC ASSERT(hMenu!=NULL); ASSERT(::IsMenu(hMenu)!=NULL); if(!IsCustomizable(TRUE)) return FALSE; CWinApp* pApp=AfxGetApp(); CString sProfileName=lpszSubKey; if(sProfileName.IsEmpty()) sProfileName=_T("Menu_Default~!@#$#$%^"); else sProfileName=_T("Menu_")+sProfileName; CString sValueName=_T("MenuDataSize"); int nSavedBufferLength= pApp->GetProfileInt(sProfileName,sValueName,-1); sValueName=_T("MenuItems"); if(nSavedBufferLength!=-1) { ASSERT(nSavedBufferLength>0); UINT nBufferLength=0; BYTE* pBuffer=NULL; if(pApp->GetProfileBinary(sProfileName,sValueName,&pBuffer,&nBufferLength)) { m_hMDIWindowMenu=NULL; ASSERT(nBufferLength>0); ASSERT(pBuffer!=NULL); CMemFile memFile(pBuffer,nBufferLength); CArchive ar(&memFile,CArchive::load); VERIFY(LoadMenuContents(hMenu,ar)); ar.Close(); memFile.Detach(); delete[] pBuffer; } } if(m_pFrameWnd!=NULL) { // notify parent that the state of menu is being restored from registry. // Parent window might apply any saved info m_pFrameWnd->SendMessage(WM_OX_LOADMENUSTATE,(WPARAM)hMenu, (LPARAM)(LPCTSTR)sProfileName); } return TRUE; #else return FALSE; #endif } BOOL COXMenuBar::SaveMenuContents(HMENU hMenu, CArchive& ar) { ASSERT(hMenu!=NULL); ASSERT(::IsMenu(hMenu)!=NULL); int nItemCount=::GetMenuItemCount(hMenu); ar<>dwItemCount; for(int nIndex=0; nIndex<(int)dwItemCount; nIndex++) { MENUITEMINFO menuItemInfo={ sizeof(MENUITEMINFO) }; menuItemInfo.fMask=MIIM_ID|MIIM_SUBMENU|MIIM_TYPE; ar>>menuItemInfo.fType; BOOL bPopupMenu=FALSE; ar>>bPopupMenu; ar>>menuItemInfo.wID; CString sText; ar>>sText; menuItemInfo.hSubMenu=NULL; if(bPopupMenu) { menuItemInfo.wID=(UINT)-1; // create new popup menu menuItemInfo.hSubMenu=::CreatePopupMenu(); ASSERT(menuItemInfo.hSubMenu!=NULL); m_arrCreatedPopupMenus.Add(menuItemInfo.hSubMenu); VERIFY(LoadMenuContents(menuItemInfo.hSubMenu,ar)); } // if this item is first MDIChild then we have to remove the separator // that we put before if(menuItemInfo.wID==AFX_IDM_FIRST_MDICHILD) { CWnd* pWnd=AfxGetMainWnd(); CMDIFrameWnd* pMDIFrameWnd=DYNAMIC_DOWNCAST(CMDIFrameWnd,pWnd); if(pMDIFrameWnd!=NULL) { // check if the previous item is separator MENUITEMINFO menuItemInfo={ sizeof(MENUITEMINFO) }; menuItemInfo.fMask=MIIM_TYPE; VERIFY(::GetMenuItemInfo(hMenu,::GetMenuItemCount(hMenu)-1, TRUE,&menuItemInfo)); if((menuItemInfo.fType&MFT_SEPARATOR)!=0) { VERIFY(::DeleteMenu(hMenu,::GetMenuItemCount(hMenu)-1, MF_BYPOSITION)); } m_hMDIWindowMenu=hMenu; } } // don't add MDIChild windows menu items if(bPopupMenu || menuItemInfo.wID=0 && nButtonIndexIsKindOf(RUNTIME_CLASS(COXMenuBar))) return DYNAMIC_DOWNCAST(COXMenuBar,pStartWnd); CWnd* pWnd=pStartWnd->GetWindow(GW_CHILD); while(pWnd!=NULL) { COXMenuBar* pMenuBar=COXMenuBar::FindMenuBar(pWnd); if(pMenuBar!=NULL) return pMenuBar; pWnd=pWnd->GetWindow(GW_HWNDNEXT); } return NULL; } BOOL COXMenuBar::SaveCustomizedMenu() { if(!IsCustomizable(TRUE)) return TRUE; BOOL bRes = TRUE; int nIndex=-1; if(m_mapChangedMenus.Lookup(m_hMenu,nIndex)) { CDocTemplate* pDocTemplate=NULL; VERIFY(m_mapCustomizableMenus.Lookup(m_hMenu,pDocTemplate)); CDocument* pDocument=NULL; if(pDocTemplate!=NULL) { POSITION pos=pDocTemplate->GetFirstDocPosition(); ASSERT(pos!=NULL); pDocument=pDocTemplate->GetNextDoc(pos); ASSERT(pDocument!=NULL); } #ifndef _UNICODE bRes = SaveMenuState(m_hMenu,(pDocument==NULL ? NULL : pDocument->GetRuntimeClass()->m_lpszClassName)); #else if(pDocument!=NULL) { LPCSTR lpszUniqueName=pDocument->GetRuntimeClass()->m_lpszClassName; int nLength=sizeof(lpszUniqueName)/sizeof(lpszUniqueName[0])+1; LPTSTR lpszUnicodeUniqueName=new TCHAR[nLength]; memset(lpszUnicodeUniqueName,0,nLength*sizeof(TCHAR)); _mbstowcsz(lpszUnicodeUniqueName,lpszUniqueName,nLength); bRes = SaveMenuState(m_hMenu,lpszUnicodeUniqueName); delete[] lpszUnicodeUniqueName; } else { VERIFY(SaveMenuState(m_hMenu,NULL)); } #endif m_mapChangedMenus.RemoveKey(m_hMenu); } return bRes; } /////////////////////////////////////////////////////////////////////////// #endif // _MFC_VER>=0x0420 CString COXMenuBar::GetItemText(int iIndex) { CMenu menu; menu.Attach(m_hMenu); CString strText; menu.GetMenuString(iIndex, strText, MF_BYPOSITION); menu.Detach(); return strText; } int COXMenuBar::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (COXCoolToolBar::OnCreate(lpCreateStruct) == -1) return -1; // Hook the mouse if (m_hMouseHook == NULL) m_hMouseHook = ::SetWindowsHookEx(WH_MOUSE, MouseProc, 0, AfxGetApp()->m_nThreadID); return 0; } void COXMenuBar::OnDestroy() { // Unhook the mouse if (m_hMouseHook) { ::UnhookWindowsHookEx(m_hMouseHook); m_hMouseHook = NULL; } COXCoolToolBar::OnDestroy(); } // Update the buttons of the mini frame window when the mouse leaves LRESULT CALLBACK COXMenuBar::MouseProc(int nCode, WPARAM wParam, LPARAM lParam) { if (nCode < 0) return ::CallNextHookEx(m_hMouseHook, nCode, wParam, lParam); if (nCode == HC_ACTION && (wParam == WM_MOUSEMOVE || wParam == WM_NCMOUSEMOVE)) { MOUSEHOOKSTRUCT* pMH = (MOUSEHOOKSTRUCT*) lParam; // If the previous message was for COXSizableMiniDockFrameWnd and the current is not // we need to update the caption buttons COXMenuBar* pPrev = DYNAMIC_DOWNCAST(COXMenuBar, CWnd::FromHandlePermanent(m_hwndPrevMouseMoveWnd)); COXMenuBar* pCurrent = DYNAMIC_DOWNCAST(COXMenuBar, CWnd::FromHandlePermanent(pMH->hwnd)); if (pPrev != NULL && pCurrent != pPrev) { if (pPrev->m_pFrameWnd->IsKindOf(RUNTIME_CLASS(CMDIFrameWnd))) { // The mouse just left the mini frame window CWindowDC dc(pPrev); pPrev->GetToolbarSkin()->DrawMenuButtons(&dc, pPrev); } } m_hwndPrevMouseMoveWnd = pMH->hwnd; } return CallNextHookEx(m_hMouseHook, nCode, wParam, lParam); } void COXMenuBar::OnNcMouseMove(UINT nHitTest, CPoint point) { CWindowDC dc(this); GetToolbarSkin()->DrawMenuButtons(&dc, this); COXCoolToolBar::OnNcMouseMove(nHitTest, point); } COXMenuSkin* COXMenuBar::GetMenuSkin() { // Check if the app is derived from COXSkinnedApp COXSkinnedApp* pSkinnedApp = DYNAMIC_DOWNCAST(COXSkinnedApp, AfxGetApp()); if (pSkinnedApp != NULL && pSkinnedApp->GetCurrentSkin() != NULL) return pSkinnedApp->GetCurrentSkin()->GetMenuSkin(); else { // Create a classic skin for this class if not created already if (m_pMenuSkin == NULL) m_pMenuSkin = new COXMenuSkinClassic(); return m_pMenuSkin; } } void COXMenuBar::RecalculateItemWidths() { // Go though all the buttons and determine their widths CToolBarCtrl& ctrl = GetToolBarCtrl(); int iCount = ctrl.GetButtonCount(); int iMaxTextLength = 0; int i = 0; for (i = 0; i < iCount; i++) { CString strText = GetItemText(i); if (strText.IsEmpty()) continue; // Determine the length of the text CDC* pDC = GetDC(); CRect rectText(0, 0, 0, 0); CFont* pOldFont = pDC->SelectObject(GetFont()); pDC->DrawText(strText, rectText, DT_CALCRECT); pDC->SelectObject(pOldFont); ReleaseDC(pDC); if (rectText.right + 8 > iMaxTextLength) iMaxTextLength = rectText.right + 8; if (m_dwStyle & CBRS_ORIENT_HORZ) { // Horizontal TBBUTTONINFO tbi; tbi.cbSize = sizeof(TBBUTTONINFO); tbi.dwMask = TBIF_SIZE; tbi.cx = (BYTE) (rectText.right + GetMenuSkin()->GetDimentionConstants().m_nGapMenuItems); ctrl.SetButtonInfo(GetItemID(i), &tbi); } } // If we have a vertical menubar make the items as wide as the widest item if ((m_dwStyle & CBRS_ORIENT_HORZ) == 0) { for (i = 0; i < iCount; i++) { TBBUTTONINFO tbi; tbi.cbSize = sizeof(TBBUTTONINFO); tbi.dwMask = TBIF_SIZE; tbi.cx = (WORD) iMaxTextLength; ctrl.SetButtonInfo(GetItemID(i), &tbi); } } } void COXShadowedItemWnd::OnPaint() { COXBitmapMenu::GetMenuSkin()->OnPaintShadowedItemWnd(this); } void COXMenuBar::GetItemRect(int nIndex, LPRECT lpRect) { // Handle the system menu case, otherwise call the default implementation bool bSysMenu = (nIndex == (int) ::GetMenuItemCount(m_hMenu)); if (bSysMenu) { CRect rectWindow; GetWindowRect(rectWindow); ScreenToClient(&rectWindow); CRect rectClient; GetClientRect(rectClient); lpRect->left = m_iconRect.left; lpRect->top = m_iconRect.top; lpRect->right = m_iconRect.right; lpRect->bottom = m_iconRect.bottom; // Offset the rectangle lpRect->left += rectWindow.left - rectClient.left; lpRect->right += rectWindow.left - rectClient.left; lpRect->top += rectWindow.top - rectClient.top; lpRect->bottom += rectWindow.top - rectClient.top; } else COXCoolToolBar::GetItemRect(nIndex, lpRect); } CSize COXMenuBar::CalcSize(TBBUTTON *pData, int nCount) { CSize size = COXCoolToolBar::CalcSize(pData, nCount); // If the menu bar if horizontally docked make it as wide as the frame, so that it would // wrap and become multiline if (!IsFloating()) { CFrameWnd* pDockingFrame = GetDockingFrame(); CRect rectClient; pDockingFrame->GetClientRect(rectClient); int iFrameWidth; if (m_rectCloseBtn.IsRectEmpty()) iFrameWidth = rectClient.right; else iFrameWidth = rectClient.right - m_rectCloseBtn.Width() - m_rectMinimizeBtn.Width() - m_rectRestoreBtn.Width() - m_iconRect.Width() - 14; if (iFrameWidth < size.cx) size.cx = iFrameWidth; } return size; } void COXMenuBar::OnSize(UINT nType, int cx, int cy) { COXCoolToolBar::OnSize(nType, cx, cy); if (!IsFloating() && IsWindowVisible()) { m_bDelayedButtonLayout = TRUE; Layout(); } }