// ==========================================================================
// Class Specification :
// COXMenuBar & COXMenuDockBar & COXMenuBarFrame
// ==========================================================================
// 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.
// //////////////////////////////////////////////////////////////////////////
/*
Many products (Misrosoft Office, Visual Studio IDE to name just a few)
use special replacement for standard menu bar in their frame window.
It looks like common dockable flat toolbar while implements all the
functionality found in standard menu bar (accelerators, mouse and
keyboard navigation).
Due to similarity to standard toolbar control we thought it would be natural
to try to use this control in order to implement the menubar.
But we have to note that only using toolbar control that is available
in comctl32.dll v4.71 and higher would allow us to implement the
functionality of menubar to full extent (primarily, because new button
style TBSTYLE_AUTOSIZE, which allows to use buttons of different width
in the toolbar, was introduced only in v4.71). As long as comctl32.dll
was freely redistributable we felt like it wasn't a big deal.
Then, we already had the COXCoolToolBar class in our library that could be
good base class for menubar implementation.
So we developed new class that is called COXMenuBar and is based on
COXCoolToolBar. If you try to use it with old version of comctl32.dll
we will throw unsupported exception.
The problem with replacing standard window menu with dockable menubar
had to be resolved in tight cooperation between frame window and
menubar control. The solution should have worked with any CFrameWnd
derived window (CFrameWnd had to be used because it is support
docking functionality). The problem turned out to be more complicated
due to the fact that we had to provide our own CDockBar derived class
(COXMenuDockBar) in order to implement menu bar (it has to do with docking
functionality). CDockBar is undocumented MFC class that is used
internaly to provide docking functionality for any CControlBar derived
class within CFrameWnd derived framework window.
Moreover, implementation for SDI and MDI main frame window was a little
bit different in both cases. And anyway it was highly possible to assume
that programmers could use their own CFrameWnd derivates in their
applications (e.g. they could have used our COXMDIFrameWndSizeDock class
in order to provide docking windows functionality).
So, we had major problem: implementation that will work with any
CFrameWnd derived class.
And we came up with the following solution.
We designed template class COXMenuBarFrame that defined as follows:
template<class PARENTFRAME, class PARENTDOCKBAR>
class COXMenuBarFrame : public PARENTFRAME
{
. . . . . . . . . . . . . .
};
where PARENTFRAME is the name of the parent frame class (e.g. CFrameWnd)
PARENTDOCKBAR is the name of parent dock bar class (e.g. CDockBar)
Using this approach you can define your mainframe window as:
class CMainFrame : public COXMenuBarFrame<CMDIFrameWnd,CDockBar>
in order to implement standard MDI application with automatic menu bar.
That's all what you have to do in order to include in your application
support for menubar. We would like to note that in standard macros
like IMPLEMENT_DYNAMIC or BEGIN_MESSAGE_MAP you have to eplicitly use
the name of the parent frame class:
BEGIN_MESSAGE_MAP(CMainFrame,CMDIFrameWnd)
Although, COXMenuBarFrame, COXMenuDockBar and COXMenuBar classes define
a number of public functions you wouldn't normally use them because
the functionality that we provide is self sufficient and doesn't provide
any additional customization functionality.
*/
#ifndef _MENUBAR_H
#define _MENUBAR_H
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
#include "OXDllExt.h"
#include "OXMainRes.h"
#include <afxole.h>
#include <afxtempl.h>
#include <afxpriv.h>
#include "UTB64Bit.h"
#ifndef __OX_OLEIMPL2_H__
#ifdef MAP_LOGHIM_TO_PIX
#undef MAP_LOGHIM_TO_PIX
#endif
#ifdef MAP_PIX_TO_LOGHIM
#undef MAP_PIX_TO_LOGHIM
#endif
#if _MFC_VER < 0x0700
#include "..\src\oleimpl2.h"
#else
#include "..\src\mfc\oleimpl2.h"
#endif
#define __OX_OLEIMPL2_H__
#endif
#if _MFC_VER>=0x0420
#include "OXCoolToolBar.h"
// default ID for menubar
#define AFX_IDW_MENUBAR 0xE810
// base id for menubar buttons that correspond to the index
#define ID_CMDBASE 1
// the gap between close, restore and minimize buttons and menu items
#define ID_BUTTONSGAP 6
typedef struct _tagOXCUSTOMIZEPOPUPMENUINFO
{
HMENU hMenu;
UINT nFlags;
POINT ptStart;
} OXCUSTOMIZEPOPUPMENUINFO;
// hit test values
typedef enum _tagMENUBARHITTEST
{
OX_MNU_ICON=-5,
OX_MNU_CLOSEBTN=-4,
OX_MNU_RESTOREBTN=-3,
OX_MNU_MINIMIZEBTN=-2,
OX_MNU_NONE=-1
} MENUBARHITTEST;
//////////////////////
// test point origin
typedef enum _tagHITTESTORIGIN
{
OX_MNU_CLIENT,
OX_MNU_SCREEN,
OX_MNU_ZEROBASED
} HITTESTORIGIN;
/////////////////////////
// ID of the expansion item
#ifndef ID_OX_SHOWALLITEMS
#define ID_OX_SHOWALLITEMS 0x0000ff56
#endif // ID_OX_SHOWALLITEMS
// Define the WM_QUERYSNAPPING user message used to query a frame window whether or not
// the snaping and tear-off behavior is enabled
#ifndef WM_QUERYSNAPPING
#define WM_QUERYSNAPPING (WM_USER + 92)
#endif
/////////////////////////////////////////////////////////////////////////////
// COXMenuBar window
class COXMenuSkin;
class COXBitmapMenu;
class OX_CLASS_DECL COXMenuBar : public COXCoolToolBar
{
friend class COXToolbarSkinClassic;
friend class COXToolbarSkinXP;
friend class COXToolbarSkin2003;
DECLARE_DYNAMIC(COXMenuBar)
// Construction
public:
// --- In :
// --- Out :
// --- Returns:
// --- Effect : Constructs the object
COXMenuBar();
public:
// handle to the submenu that will contain the MRU MDIChild windows
HMENU m_hMDIWindowMenu;
// static function that will search for menubar
static COXMenuBar* FindMenuBar(CWnd* pStartWnd=NULL);
// Attributes
public:
// handle to the menu that is currently displayed in the menu bar
HMENU m_hMenu;
// zero-based index of the menu item that is currently displayed
// in the dropdown state (the corresponding popup menu is active)
int m_nActiveMenuItem;
// zero-based index of the menu item that will be activated (the
// corresponding popup menu will be active) after the currently
// active popup menu is deactivated
int m_nActivateNextItem;
// zero-based index of the menu item that cannot be set as
// m_nActivateNextItem
int m_nForbiddenItem;
// v9.3 update 01 modification manfred for DisplayPopupMenu code
int m_nActivateNextItemShowAll;
// flag that specifies that menu should take entire row
// while displayed
BOOL m_bForceEntireRow;
// flag that specifies that menu bar should state
// in surfing mode after Esc key was pressed when
// top level popup menu was active
BOOL m_bStaySurfing;
protected:
// flag that specifies that menu bar will take the entire row or column
// while docked. At the moment this flag is always TRUE
BOOL m_bTakeEntireRow;
// pointer to the parent frame window
CWnd* m_pFrameWnd;
// accelerator table for menu items
CMap<TCHAR,TCHAR,int,int> m_accelTable;
// rectangles for close, restore and minimize buttons on the bar
CRect m_rectCloseBtn;
CRect m_rectRestoreBtn;
CRect m_rectMinimizeBtn;
////////////////////////////////////////////////////////////////
// currently pressed button (close, restore or minimize)
MENUBARHITTEST m_pressedBtn;
// flag that specifies that menu bar is in surfing mode when user can
// use keyboard to navigate through menu items.
BOOL m_bIsInSurfingMode;
// font used to draw the menu bar
CFont m_fontMenu;
// flag that specifies that current menu display settings has been
// retrieved and they are up-to-date
BOOL m_bIsMenuMetricInitialized;
// map of all menus associated with all document templates defined
// in application. Only this menus are customizable
CMap<HMENU,HMENU,CDocTemplate*,CDocTemplate*> m_mapCustomizableMenus;
// map of all menus that has been customized but hasn't been saved yet
CMap<HMENU,HMENU,int,int> m_mapChangedMenus;
// array of created popup menus that should be destroyed at the end
CArray<HMENU,HMENU> m_arrCreatedPopupMenus;
// timer for drag'n'drop event
UINT_PTR m_nCheckForDragDropEventTimerID;
// item that will be dragged
int m_nWouldBeDraggedItem;
private:
static LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam);
static HHOOK m_hMouseHook;
static HWND m_hwndPrevMouseMoveWnd;
COXMenuSkin* GetMenuSkin();
COXMenuSkin* m_pMenuSkin;
void RecalculateItemWidths();
// Operations
public:
// --- In : pParentWnd - Pointer to the window that is the
// menubar's parent
// dwStyle - The menubar style. Refer to decription
// of CToolBar::Create() function for details
// nID - The toolbar's child-window ID.
// --- Out :
// --- Returns: TRUE if menubar was successfully created,
// or FALSE otherwise
// --- Effect : Creates the menubar
BOOL Create(CWnd* pParentWnd,
DWORD dwStyle=WS_CHILD|WS_VISIBLE|CBRS_TOP|CBRS_SIZE_DYNAMIC,
UINT nID=AFX_IDW_MENUBAR);
// --- In :
// --- Out :
// --- Returns: Handle to the menu that is used in the menu bar
// --- Effect : Retrieves handle to the menubar menu
HMENU GetMenu() const {
ASSERT(::IsWindow(GetSafeHwnd()));
return m_hMenu;
}
// --- In : hMenu - handle to the valid menu that will be
// displayed in the menubar
// --- Out :
// --- Returns: TRUE if the menu was successfully set,
// or FALSE otherwise
// --- Effect : Sets menu to be displayed in the menubar
BOOL SetMenu(HMENU hMenu);
// --- In : bTakeEntireRow - flag that specifies whether the
// menubar will take the entire
// row/column
// bRedraw - flag that specifies whethern the
// menubar will be redrawn or not
// --- Out :
// --- Returns:
// --- Effect : Sets the flag that specifies whether the menubar
// will take the entire row/column
inline void SetTakeEntireRow(BOOL bTakeEntireRow, BOOL bRedraw=TRUE)
{
m_bTakeEntireRow=bTakeEntireRow;
if(bRedraw)
{
RedrawToolBar();
}
}
// --- In :
// --- Out :
// --- Returns:
// --- Effect : Retrieves the flag that specifies whether the menubar
// will take the entire row/column
inline BOOL GetTakeEntireRow() const { return m_bTakeEntireRow; }
// --- In : bHorz - TRUE if the size of row is retrieved,
// FALSE if the size of column is retrieved
// --- Out :
// --- Returns: Size of row/column to display the menu bar in
// --- Effect : Retrieves the size of row/column to display the menu bar in
CSize GetEntireRow(BOOL bHorz) const;
// --- In : bIsInSurfingMode - flag that specifies whether the
// surfing mode is set/removed.
// nItem - if bIsInSurfingMode is TRUE then
// this variable specifies the index
// of the item that has to be
// initially displayed as hot in the
// surfing mode.
// --- Out :
// --- Returns: TRUE if surfing mode was successfully set/removed
// --- Effect : Sets/removes the surfing mode. If menu bar is in surfing
// mode then user can use keyboard to navigate through menu
// items
BOOL SetSurfingMode(BOOL bIsInSurfingMode=TRUE, int nItem=0);
// --- In :
// --- Out :
// --- Returns: TRUE if menubar is in surfing mode, or FALSE otherwise
// --- Effect : Retrives the flag that specifies whether the menubar is
// in the surfing mode or not. If menu bar is in surfing
// mode then user can use keyboard to navigate through
// menu items
inline BOOL IsInSurfingMode() const
{
ASSERT(::IsWindow(m_hWnd));
return m_bIsInSurfingMode;
}
// --- In :
// --- Out :
// --- Returns: TRUE if menubar is in displaying mode, or FALSE otherwise.
// --- Effect : Retrives the flag that specifies whether the menubar is
// in the displaying mode or not. If menu bar is in
// displaying mode then one of the popup menus is displayed
inline BOOL IsInDisplayingMode() const
{
ASSERT(::IsWindow(m_hWnd));
return (m_nActiveMenuItem>=0 &&
m_nActiveMenuItem<=GetToolBarCtrl().GetButtonCount());
}
// returns TRUE if menu content can be dynamically changed in Customize Manger
virtual BOOL IsCustomizable(BOOL bAdvanced=TRUE) const;
// Save to and load from registry state of application menus.
// We use default registry key assigned to your application by MFC as
// a storage. We distinguish
//
////////////////////////
virtual BOOL SaveBarState(LPCTSTR lpszSubKey, LPCTSTR lpszValueName,
BOOL bProperties=TRUE);
virtual BOOL LoadBarState(LPCTSTR lpszSubKey, LPCTSTR lpszValueName,
BOOL bProperties=TRUE);
// saves/restores the state of menu in/from registry
BOOL SaveMenuState(HMENU hMenu, LPCTSTR lpszSubKey);
BOOL LoadMenuState(HMENU hMenu, LPCTSTR lpszSubKey);
virtual BOOL DisplayCustomizeButtonContextMenu(int nButtonIndex, CPoint point);
// mark the menu as the changed one
inline void MarkAsChanged()
{
// mark this menu as a changed one
if(!IsMarkedAsChanged())
{
m_mapChangedMenus.SetAt(GetMenu(),PtrToInt(m_mapChangedMenus.GetCount()));
}
}
// check if menu is marked as the changed one
inline BOOL IsMarkedAsChanged()
{
int nIndex=-1;
HMENU hMenu=GetMenu();
return (m_mapChangedMenus.Lookup(hMenu,nIndex));
}
// --- In :
// --- Out :
// --- Returns:
// --- Effect : This member function fills the RECT structure whose address is
// contained in lpRect with the coordinates of the button or separator
// specified by nIndex. Coordinates are in pixels relative to the
// upper-left corner of the toolbar.
virtual void GetItemRect(int nIndex, LPRECT lpRect);
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMainFrame)
//}}AFX_VIRTUAL
protected:
// repiopulate the menu bar
BOOL RecreateMenuBar(BOOL bRedraw=TRUE);
// refresh the menubar icon if any is displayed
void UpdateIcon(BOOL bRedraw=TRUE);
// sets the specified menu item to pressed state and
// displays the corresponding popup menu
void DisplayPopupMenu(int nMenuItem);
// restores the state of the previously ative menu item
void RestoreMenuButton();
// calculates the size of rectangles for close, restore
// and minimize buttons
int CalcButtonRects();
// draws close, restore and minimize buttons
virtual void DrawButtons(CDC& dc);
// function that is called when the size of the menu bar
// is requested by dock bar or dock context
virtual CSize CalcLayout(DWORD nMode, int nLength=-1);
// returns the index of the previous (only visible if specified)
// item in the menu bar
int GetPrevMenuItem(int nItem, BOOL bEnsureVisile=TRUE);
// returns the index of the next (only visible if specified)
// item in the menu bar
int GetNextMenuItem(int nItem, BOOL bEnsureVisible=TRUE);
// Implementation
public:
virtual CSize CalcSize(TBBUTTON* pData, int nCount);
// --- In :
// --- Out :
// --- Returns:
// --- Effect : Destructs the object
virtual ~COXMenuBar();
// --- In : ptTest - point to test
// Origin - origin of the point. Can be one of the
// following:
//
// OX_MNU_CLIENT - ptTest is in client coordinates
// OX_MNU_SCREEN - ptTest is in screen coordinates
// OX_MNU_ZEROBASED - ptTest is in coordinates where
// TopLeft point of menubar window
// is the origin point.
// --- Out :
// --- Returns: the index of the corresponding menu item or one of the
// following values:
//
// OX_MNU_ICON - ptTest is over the icon rectangle
// OX_MNU_CLOSEBTN - ptTest is over the close button rectangle
// OX_MNU_RESTOREBTN - ptTest is over the restore button rectangle
// OX_MNU_MINIMIZEBTN - ptTest is over the minimize button rectangle
// OX_MNU_NONE - ptTest is in void space
//
// --- Effect : Retrieves the item that is under the specified point
int HitTest(const CPoint& ptTest, HITTESTORIGIN Origin=OX_MNU_ZEROBASED) const;
// --- In :
// --- Out :
// --- Returns:
// --- Effect : Redraws the menu bar. If a menu bar is changed after
// Windows has created the window, call this function to
// draw the changed menu bar.
inline void DrawMenuBar()
{
if(::IsWindow(GetSafeHwnd()))
{
RecreateMenuBar(TRUE);
}
}
// --- In : nChar - Specifies the virtual-key code of the given key.
// --- Out :
// --- Returns: TRUE if key was handled, or FALSE otherwise
// --- Effect : Handles key pressed by user (accelerator key or
// navigate keys)
BOOL HandleMenuKey(UINT nChar);
protected:
// virtual function for designating some space. We book space for
// close, restore and minimize buttons.
virtual void BookSpace(CRect& rectBookedSpace, DWORD dwMode);
// Draw in Booked space
virtual void DrawInBookedSpace(CDC& dc, CRect& rectToDrawIn);
// function called all the time when menubar changes its state from
// docking to floating and vise versa
virtual void OnFloatingDocking(BOOL bFloating);
void UpdateMenuMetrics(BOOL bRedraw=TRUE);
// function called everytime when toolbar changes its docking side
virtual void OnChangeDockSide(DWORD dwDockSide);
// saves/restores the contents of a menu in/from registry
BOOL SaveMenuContents(HMENU hMenu, CArchive& ar);
BOOL LoadMenuContents(HMENU hMenu, CArchive& ar);
// Saves the customized menu in case it has been modified
BOOL SaveCustomizedMenu();
// Generated message map functions
protected:
CString GetItemText(int iIndex);
// overwrite standard handlers to overcome some problems with MFC
// standard painting routine
//{{AFX_MSG(COXMenuBar)
afx_msg void OnNcLButtonDown(UINT nHitTest, CPoint point);
#if _MSC_VER >= 1400
afx_msg LRESULT OnNcHitTest(CPoint point);
#else
afx_msg UINT OnNcHitTest(CPoint point);
#endif
afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg void OnRButtonDown(UINT nFlags, CPoint point);
afx_msg void OnRButtonDblClk(UINT nFlags, CPoint point);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnNcLButtonDblClk(UINT nHitTest, CPoint point);
afx_msg void OnKillFocus(CWnd* pNewWnd);
afx_msg void OnSettingChange(UINT uFlags, LPCTSTR lpszSection);
afx_msg void OnTimer(UINT nIDEvent);
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnDestroy();
afx_msg void OnNcMouseMove(UINT nHitTest, CPoint point);
afx_msg void OnSize(UINT nType, int cx, int cy);
//}}AFX_MSG
afx_msg LONG OnIdleUpdateCmdUI(WPARAM wParam, LPARAM lParam);
afx_msg void OnUpdateMenuItem(CCmdUI* pCmd);
afx_msg BOOL OnMenuDropDown(NMHDR* pNotifyStruct, LRESULT* result);
afx_msg LONG OnDisplayPopupMenu(WPARAM wParam, LPARAM lParam);
// v9.3 update 01 modification (added) Manfred Drasch
afx_msg LONG OnDisplayPopupMenuAllItems(WPARAM wParam, LPARAM lParam);
afx_msg void OnCustTBDelete();
// reflect the messages to let the MenuBar provide
// customization functionality
afx_msg BOOL OnTBNBeginDrag(NMHDR* pNMHDR, LRESULT* pResult);
DECLARE_MESSAGE_MAP()
// drag and drop support
virtual LONG OnDragOver(WPARAM wParam, LPARAM lParam);
virtual LONG OnDrop(WPARAM wParam, LPARAM lParam);
// handler that is called when button is to be removed due to to
// drag'n'drop operation
virtual void OnRemoveDraggedButton(int nButtonIndex);
virtual void RetrieveDragDropMenuItem(BYTE*& lpData, HMENU hMenu,
int nButtonIndex);
};
/////////////////////////////////////////////////////////////////////////
template<class PARENTWND>
class COXMenuBarHost : public PARENTWND
{
public:
// --- In :
// --- Out :
// --- Returns:
// --- Effect : Constructs the object
COXMenuBarHost();
// Operations
protected:
// --- In : hMenu - valid handle of the menu that will be set
// to menu bar
// pWnd - Pointer to the window that is the
// menubar's parent.
// dwStyle - The menubar style. Refer to decription
// of CToolBar::Create() function for details
// nID - The toolbar's child-window ID.
// --- Out :
// --- Returns: TRUE if menubar was successfully created,
// or FALSE otherwise
// --- Effect : Creates the menubar
virtual BOOL OnCreateMenuBar(HMENU hMenu, CWnd* pWnd,
DWORD dwStyle, UINT nID);
// Attributes
public:
// global map of all menu bar frame windows
static CMap<HWND,HWND,void*,void*> g_arrMenuBarFrames;
// handle of the old mouse hook procedure
static HHOOK g_pfnOldMouseHookProc;
// handle of the old keyboard hook procedure
static HHOOK g_pfnOldKeyboardHookProc;
/////////////////
protected:
// flag that specifies that the window is CFrameWnd derived
BOOL m_bIsFrame;
// flag that specifies that the window is MDIFrame
BOOL m_bIsMDI;
// menubar object
COXMenuBar m_menuBar;
// default menu of MDIFrame window
HMENU m_hDefaultMenu;
// flag that specifies that currently selected item in popup menu is
// popup item
BOOL m_bIsPopupMenuItem;
// array of currently displayed popup menus
CArray<HMENU,HMENU> m_arrPopupMenu;
public:
// --- In :
// --- Out :
// --- Returns:
// --- Effect : Destructs the object
virtual ~COXMenuBarHost();
// --- In : nCode - Specifies a code the hook procedure uses
// to determine how to process the mouse message.
// If nCode is less than zero, the rocedure must
// pass the message to the CallNextHookEx function
// without further processing and should return
// the value returned by CallNextHookEx.
// wParam - Specifies the identifier of the mouse message.
// lParam - Pointer to a MOUSEHOOKSTRUCT structure.
// --- Out :
// --- Returns: TRUE if the message has been handled, or FALSE otherwise
// --- Effect : Handles all mouse messages in the current thread
virtual BOOL HandleMouseMsg(int nCode, WPARAM wParam, LPARAM lParam);
// --- In : nCode - Specifies a code the hook procedure uses
// to determine how to process the mouse message.
// If nCode is less than zero, the rocedure must
// pass the message to the CallNextHookEx function
// without further processing and should return
// the value returned by CallNextHookEx.
// wParam - Specifies the virtual-key code of the key that
// generated the keystroke message
// lParam - Specifies the repeat count, scan code,
// extended-key flag, context code, previous
// key-state flag, and transition-state flag
// --- Out :
// --- Returns: TRUE if the message has been handled, or FALSE otherwise
// --- Effect : Handles all keyboard messages in the current thread
virtual BOOL HandleKeyboardMsg(int nCode, WPARAM wParam, LPARAM lParam);
// --- In :
// --- Out :
// --- Returns: reference to COXMenuBar object used to represent
// the menu bar
// --- Effect : Retrieves menu bar object
virtual COXMenuBar& GetMenuBar();
// --- In :
// --- Out :
// --- Returns:
// --- Effect : Redraws menu bar
virtual void DrawMenuBar();
// --- In :
// --- Out :
// --- Returns: pointer to the window menu
// --- Effect : Retrieves window's menu
virtual CMenu* GetMenu();
// --- In : pMenu - pointer to the new window menu
// --- Out :
// --- Returns: TRUE id succeeded or FALSE otherwise
// --- Effect : Sets window's menu
virtual BOOL SetMenu(CMenu* pMenu);
// --- In : nHiliteItemIndex - Specifies the menu item to be highlighted
// bHilite - Specifies whether the menu item is
// highlighted or the highlight is removed.
// --- Out :
// --- Returns: TRUE if succeed; FALSE otherwise
// --- Effect : Highlights or removes the highlight from a top-level
// (menu-bar) menu item
BOOL HiliteMenuItem(int nHiliteItemIndex, BOOL bHilite);
// mark the menu as the changed one
void MarkMenuAsChanged();
protected:
// --- In : msg - message ID
// wp - WPARAM
// lp - LPARAM
// --- Out :
// --- Returns: result of message handling. Different for different messages.
// --- Effect : Handle all messages that go to the window
virtual LRESULT WindowProc(UINT msg, WPARAM wp, LPARAM lp);
// helper function to add the object to global list of existing
// COXMenuBarHost objects
void AddToGlobalList();
// helper function to remove the object from the global list of existing
// COXMenuBarHost objects
void RemoveFromGlobalList();
// hook procedure for mouse messages
static LRESULT CALLBACK MenuMouseHookProc(int nCode, WPARAM wParam,
LPARAM lParam);
// hook procedure for keyboard messages
static LRESULT CALLBACK MenuKeyboardHookProc(int nCode, WPARAM wParam,
LPARAM lParam);
};
// global map of all menu bar frame windows
template<class PARENTWND>
CMap<HWND,HWND,void*,void*> COXMenuBarHost<PARENTWND>::g_arrMenuBarFrames;
// handle of the old mouse hook procedure
template<class PARENTWND>
HHOOK COXMenuBarHost<PARENTWND>::g_pfnOldMouseHookProc=NULL;
// handle of the old keyboard hook procedure
template<class PARENTWND>
HHOOK COXMenuBarHost<PARENTWND>::g_pfnOldKeyboardHookProc=NULL;
///////////////////////////////////////////
template<class PARENTWND>
COXMenuBarHost<PARENTWND>::COXMenuBarHost()
{
// has to be derived from CWnd or its derivates
if(!IsKindOf(RUNTIME_CLASS(CWnd)))
{
TRACE(_T("COXMenuBarHost has to be derived from CFrameWnd or its derivates\n"));
AfxThrowNotSupportedException();
}
// is it CFrameWnd derived
m_bIsFrame=IsKindOf(RUNTIME_CLASS(CFrameWnd));
// is it MDI
m_bIsMDI=IsKindOf(RUNTIME_CLASS(CMDIFrameWnd));
m_hDefaultMenu=NULL;
m_bIsPopupMenuItem=FALSE;
}
template<class PARENTWND>
COXMenuBarHost<PARENTWND>::~COXMenuBarHost()
{
if(::IsWindow(GetSafeHwnd()))
{
DestroyWindow();
}
ASSERT(g_arrMenuBarFrames.GetCount()>0 || g_pfnOldMouseHookProc==NULL);
ASSERT(g_arrMenuBarFrames.GetCount()>0 || g_pfnOldKeyboardHookProc==NULL);
}
template<class PARENTWND>
BOOL COXMenuBarHost<PARENTWND>::OnCreateMenuBar(HMENU hMenu, CWnd* pWnd,
DWORD dwStyle, UINT nID)
{
ASSERT(pWnd!=NULL);
ASSERT(::IsWindow(pWnd->m_hWnd));
if(hMenu==NULL)
dwStyle&=~WS_VISIBLE;
if(!GetMenuBar().Create(pWnd,dwStyle,nID))
{
TRACE(_T("COXMenuBarHost<PARENTWND>::OnCreateMenuBar: failed to create menu bar\n"));
return FALSE;
}
if(!GetMenuBar().SetMenu(hMenu))
{
TRACE(_T("COXMenuBarHost<PARENTWND>::OnCreateMenuBar: failed to set menu to menu bar\n"));
return FALSE;
}
if(m_bIsFrame)
{
((CFrameWnd*)this)->m_hMenuDefault=hMenu;
}
return TRUE;
}
template<class PARENTWND>
LRESULT COXMenuBarHost<PARENTWND>::WindowProc(UINT msg, WPARAM wp, LPARAM lp)
{
#if defined (_WINDLL)
#if defined (_AFXDLL)
AFX_MANAGE_STATE(AfxGetAppModuleState());
#else
AFX_MANAGE_STATE(AfxGetStaticModuleState());
#endif
#endif
ASSERT(::IsWindow(m_hWnd));
switch(msg)
{
// handle the creation of the frame
case WM_CREATE:
{
// call parent implementation
LRESULT lResult=PARENTWND::WindowProc(msg,wp,lp);
if(lResult!=-1)
{
// there shouldn't be any menu bar created at the moment
ASSERT(!::IsWindow(GetMenuBar().GetSafeHwnd()));
AddToGlobalList();
if(::IsWindow(GetMenuBar().GetSafeHwnd()))
{
GetMenuBar().DestroyWindow();
}
// retrieve default menu
HMENU hMenu=::GetMenu(m_hWnd);
if(hMenu==NULL || !::IsMenu(hMenu))
{
if(m_bIsMDI)
{
TRACE(_T("COXMenuBarHost<PARENTWND>::WindowProc: There is no menu associated with frame window\n"));
}
m_hDefaultMenu=NULL;
}
else
{
// save default menu
m_hDefaultMenu=hMenu;
// remove menu from window
SetMenu(NULL);
}
// for SDI frame window it's important to set application
// main window right now
if(AfxGetApp()->m_pMainWnd==NULL && !m_bIsMDI && m_bIsFrame &&
(GetStyle() & WS_CHILD)!=WS_CHILD)
{
AfxGetApp()->m_pMainWnd=this;
}
// create menu bar and set the menu
if(!OnCreateMenuBar(m_hDefaultMenu,this,
WS_CHILD|WS_VISIBLE|CBRS_TOP|CBRS_SIZE_DYNAMIC|CBRS_GRIPPER,AFX_IDW_MENUBAR))
{
TRACE(_T("COXMenuBarHost<PARENTWND>::WindowProc: failed to initialize COXMenuBar object\n"));
return lResult;
}
// setup hooks for mouse and keyboard messages
if(g_pfnOldMouseHookProc==NULL)
{
g_pfnOldMouseHookProc=::SetWindowsHookEx(
WH_MOUSE,MenuMouseHookProc,NULL,::GetCurrentThreadId());
}
if(g_pfnOldKeyboardHookProc==NULL)
{
g_pfnOldKeyboardHookProc=::SetWindowsHookEx(
WH_KEYBOARD,MenuKeyboardHookProc,NULL,::GetCurrentThreadId());
}
//////////////////////////////////////////////
}
return lResult;
}
case WM_DESTROY:
{
RemoveFromGlobalList();
// reset the menu customized mode
if(::IsWindow(GetMenuBar().GetSafeHwnd()))
{
GetMenuBar().SetAdvancedCustomizationMode(FALSE);
}
// destroy menu bar
if(::IsWindow(GetMenuBar().GetSafeHwnd()))
{
GetMenuBar().DestroyWindow();
}
if(g_arrMenuBarFrames.GetCount()==0)
{
// unhook mouse messages
if(g_pfnOldMouseHookProc!=NULL)
{
VERIFY(::UnhookWindowsHookEx(g_pfnOldMouseHookProc));
g_pfnOldMouseHookProc=NULL;
}
// unhook keyboard messages
if(g_pfnOldKeyboardHookProc!=NULL)
{
VERIFY(::UnhookWindowsHookEx(g_pfnOldKeyboardHookProc));
g_pfnOldKeyboardHookProc=NULL;
}
}
break;
}
case WM_INITMENUPOPUP:
{
m_bIsPopupMenuItem=FALSE;
m_arrPopupMenu.Add((HMENU)wp);
WORD hiWord=HIWORD(lp);
WORD loWord=LOWORD(lp);
if(hiWord==0)
{
if(::IsWindow(GetMenuBar().GetSafeHwnd()))
{
loWord=(WORD)GetMenuBar().m_nActiveMenuItem;
}
}
lp=MAKELPARAM(loWord,hiWord);
#if _MFC_VER>0x0421
#ifndef _AFX_NO_OLE_SUPPORT
if(m_bIsFrame)
{
CFrameWnd* pFrameWnd=DYNAMIC_DOWNCAST(CFrameWnd,this);
ASSERT(pFrameWnd!=NULL);
if(pFrameWnd->m_pNotifyHook!=NULL)
{
if(pFrameWnd->m_pNotifyHook->OnInitMenuPopup(
CMenu::FromHandle((HMENU)wp),LOWORD(lp),HIWORD(lp)))
{
return 0;
}
if(pFrameWnd->m_pNotifyHook->m_pActiveItem!=NULL)
{
CWnd* pWnd=pFrameWnd->m_pNotifyHook->
m_pActiveItem->GetInPlaceWindow();
ASSERT(pWnd!=NULL);
pWnd->SendMessage(msg,wp,lp);
return 0;
}
}
}
#endif // _AFX_NO_OLE_SUPPORT
#endif // _MFC_VER>0x0421
break;
}
case WM_MENUSELECT:
{
UINT nFlags=HIWORD(wp);
m_bIsPopupMenuItem=((nFlags&MF_POPUP)!=0 &&
!(nFlags==0xFFFF && lp==NULL) ? TRUE : FALSE);
#if _MFC_VER>0x0421
#ifndef _AFX_NO_OLE_SUPPORT
if(m_bIsFrame)
{
CFrameWnd* pFrameWnd=DYNAMIC_DOWNCAST(CFrameWnd,this);
ASSERT(pFrameWnd!=NULL);
if(pFrameWnd->m_pNotifyHook!=NULL)
{
if(pFrameWnd->m_pNotifyHook->m_pActiveItem!=NULL)
{
CWnd* pWnd=pFrameWnd->m_pNotifyHook->
m_pActiveItem->GetInPlaceWindow();
ASSERT(pWnd!=NULL);
pWnd->SendMessage(msg,wp,lp);
}
}
}
#endif // _AFX_NO_OLE_SUPPORT
#endif // _MFC_VER>0x0421
if((nFlags&MF_HILITE)!=0)
{
while(m_arrPopupMenu.GetSize()>0 &&
m_arrPopupMenu[m_arrPopupMenu.GetSize()-1]!=(HMENU)lp)
{
m_arrPopupMenu.RemoveAt(m_arrPopupMenu.GetSize()-1);
}
}
break;
}
case WM_EXITMENULOOP:
{
if(wp==0)
{
m_arrPopupMenu.RemoveAll();
}
break;
}
case WM_COMMAND:
{
if(HIWORD(wp)==0)
{
int nCmdID=LOWORD(wp);
if(nCmdID==ID_OX_SHOWALLITEMS)
{
// v9.3 update 01 modification (replaced) Manfred Drasch
// GetMenuBar().m_nActivateNextItem=GetMenuBar().m_nActiveMenuItem;
GetMenuBar().PostMessage(WM_DISPLAYPOPUPMENU_ALLITEMS);
}
}
break;
}
case WM_OX_MENUCHANGED:
{
MarkMenuAsChanged();
break;
}
}
// I don't handle it: pass along
return PARENTWND::WindowProc(msg,wp,lp);
}
template<class PARENTWND>
void COXMenuBarHost<PARENTWND>::MarkMenuAsChanged()
{
// mark the current menu as a changed one
GetMenuBar().MarkAsChanged();
}
template<class PARENTWND>
void COXMenuBarHost<PARENTWND>::AddToGlobalList()
{
ASSERT(::IsWindow(GetSafeHwnd()));
g_arrMenuBarFrames.SetAt(GetSafeHwnd(),(void*)this);
}
template<class PARENTWND>
void COXMenuBarHost<PARENTWND>::RemoveFromGlobalList()
{
ASSERT(::IsWindow(GetSafeHwnd()));
g_arrMenuBarFrames.RemoveKey(GetSafeHwnd());
}
// last mouse cursor position when hew menubar item was activated
static CPoint g_ptLast(-1,-1);
template<class PARENTWND>
BOOL COXMenuBarHost<PARENTWND>::HandleMouseMsg(int nCode,
WPARAM wParam,
LPARAM lParam)
{
if(!::IsWindow(m_hWnd) || GetMenuBar().IsInAdvancedCustomizationMode())
{
return FALSE;
}
if(nCode==HC_ACTION && ::IsWindow(GetMenuBar().GetSafeHwnd()))
{
MOUSEHOOKSTRUCT* pMHS=(MOUSEHOOKSTRUCT*)lParam;
// there should be an active menu bar at the moment
if(GetMenuBar().IsInDisplayingMode() &&
pMHS->hwnd!=GetMenuBar().GetSafeHwnd())
{
CRect rect;
GetMenuBar().GetWindowRect(rect);
// handle WM_MOUSEMOVE and WM_LBUTTONDOWN messages
if((wParam==WM_MOUSEMOVE || wParam==WM_LBUTTONDOWN) &&
rect.PtInRect(pMHS->pt) &&
::WindowFromPoint(pMHS->pt)==GetMenuBar().GetSafeHwnd())
{
CPoint point=pMHS->pt;
GetMenuBar().ScreenToClient(&point);
// test the mouse cursor point
int hitTest=GetMenuBar().HitTest(point,OX_MNU_CLIENT);
if(wParam==WM_MOUSEMOVE && g_ptLast!=point &&
hitTest!=GetMenuBar().m_nActiveMenuItem &&
(hitTest>=0 || hitTest==OX_MNU_ICON) &&
!(GetMenuBar().m_nActiveMenuItem==
::GetMenuItemCount(GetMenuBar().m_hMenu) &&
hitTest==OX_MNU_ICON))
{
// set the menu item that will be activated next
GetMenuBar().m_nActivateNextItem=(hitTest!=OX_MNU_ICON) ? hitTest :
::GetMenuItemCount(GetMenuBar().m_hMenu);
// emulate mouse pressing
::PostMessage(pMHS->hwnd,WM_LBUTTONDOWN,MK_LBUTTON,
MAKELPARAM(point.x,point.y));
::PostMessage(pMHS->hwnd,WM_LBUTTONUP,MK_LBUTTON,
MAKELPARAM(point.x,point.y));
return TRUE;
}
else if(wParam==WM_LBUTTONDOWN && (hitTest>=0 || hitTest==OX_MNU_ICON))
{
// set the forbidden item
GetMenuBar().m_nForbiddenItem=(hitTest!=OX_MNU_ICON) ? hitTest :
::GetMenuItemCount(GetMenuBar().m_hMenu);
}
g_ptLast=point;
}
}
}
return FALSE;
}
// flag that ALT was pressed down
static BOOL g_altDownNoOtherKey=FALSE;
template<class PARENTWND>
BOOL COXMenuBarHost<PARENTWND>::
HandleKeyboardMsg(int nCode, WPARAM wParam, LPARAM lParam)
{
ASSERT(::IsWindow(m_hWnd));
if(nCode==HC_ACTION && ::IsWindow(GetMenuBar().GetSafeHwnd()) &&
IsWindowEnabled() && ::GetActiveWindow()==GetSafeHwnd())
{
// handle differently keyboard messages when menubar is in
// displaying mode
if(!GetMenuBar().IsInDisplayingMode())
{
if(wParam==VK_MENU)
{
if(lParam>=0)
{
if(!(lParam&(1<<30)))
{
g_altDownNoOtherKey=TRUE;
return TRUE;
}
}
else if(g_altDownNoOtherKey)
{
// ALT key was pressed
GetMenuBar().HandleMenuKey(0);
g_altDownNoOtherKey=FALSE;
return TRUE;
}
}
if(wParam!=VK_MENU && (::GetAsyncKeyState(VK_MENU)<0 ||
GetMenuBar().IsInSurfingMode()))
{
g_altDownNoOtherKey=FALSE;
if((lParam&0x80000000)==0 && int(lParam)>=0 &&
::GetAsyncKeyState(VK_F4)>=0)
{
// handle the key
if(GetMenuBar().HandleMenuKey(PtrToUint(wParam)))
return TRUE;
}
}
}
else
{
// handle only VK_LEFT, VK_RIGHT and VK_ESCAPE in the specific way
// while in displaying mode
if(int(lParam)>=0 && ((wParam==VK_LEFT && m_arrPopupMenu.GetSize()<=1) ||
(wParam==VK_RIGHT && !m_bIsPopupMenuItem) ||
(wParam==VK_ESCAPE && m_arrPopupMenu.GetSize()==1)))
{
// handle the key
if(GetMenuBar().HandleMenuKey(PtrToUint(wParam)))
return TRUE;
}
}
}
return FALSE;
}
template<class PARENTWND>
COXMenuBar& COXMenuBarHost<PARENTWND>::GetMenuBar()
{
return m_menuBar;
}
template<class PARENTWND>
void COXMenuBarHost<PARENTWND>::DrawMenuBar()
{
if(::IsWindow(GetMenuBar().GetSafeHwnd()))
GetMenuBar().DrawMenuBar();
else
PARENTWND::DrawMenuBar();
}
template<class PARENTWND>
CMenu* COXMenuBarHost<PARENTWND>::GetMenu()
{
if(::IsWindow(GetMenuBar().GetSafeHwnd()))
return CMenu::FromHandle(GetMenuBar().GetMenu());
else
return PARENTWND::GetMenu();
}
template<class PARENTWND>
BOOL COXMenuBarHost<PARENTWND>::SetMenu(CMenu* pMenu)
{
if(::IsWindow(GetMenuBar().GetSafeHwnd()))
return GetMenuBar().SetMenu(pMenu==NULL ? NULL : pMenu->GetSafeHmenu());
else
return PARENTWND::SetMenu(pMenu);
}
template<class PARENTWND>
BOOL COXMenuBarHost<PARENTWND>::HiliteMenuItem(int nHiliteItemIndex, BOOL bHilite)
{
if(GetMenuBar().IsInDisplayingMode())
{
return FALSE;
}
return GetMenuBar().SetSurfingMode(bHilite,nHiliteItemIndex);
}
template<class PARENTWND>
LRESULT CALLBACK COXMenuBarHost<PARENTWND>::
MenuMouseHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
#if defined (_WINDLL)
#if defined (_AFXDLL)
AFX_MANAGE_STATE(AfxGetAppModuleState());
#else
AFX_MANAGE_STATE(AfxGetStaticModuleState());
#endif
#endif
ASSERT(g_pfnOldMouseHookProc!=NULL);
if(nCode<0)
{
// have to call the default implementation
return ::CallNextHookEx(g_pfnOldMouseHookProc,nCode,wParam,lParam);
}
DWORD dwMessagePos=::GetMessagePos();
POINTS points=MAKEPOINTS(dwMessagePos);
CPoint ptLast(points.x,points.y);
CWnd* pWnd=WindowFromPoint(ptLast);
ASSERT(pWnd!=NULL);
CWnd* pTopLevelWnd=pWnd->GetTopLevelParent();
ASSERT(pTopLevelWnd!=NULL);
ASSERT(g_arrMenuBarFrames.GetCount()>0);
POSITION pos=g_arrMenuBarFrames.GetStartPosition();
while(pos!=NULL)
{
HWND hWnd=NULL;
void* pMenuBarFrame=NULL;
g_arrMenuBarFrames.GetNextAssoc(pos,hWnd,pMenuBarFrame);
ASSERT(pMenuBarFrame!=NULL);
// call COXMenuBarHost implementation
if(::IsWindow(((COXMenuBarHost<PARENTWND>*)pMenuBarFrame)->m_hWnd) &&
(pMenuBarFrame==pTopLevelWnd))
{
if(((COXMenuBarHost<PARENTWND>*)pMenuBarFrame)->
HandleMouseMsg(nCode,wParam,lParam))
{
return 0;
}
}
}
return ::CallNextHookEx(g_pfnOldMouseHookProc,nCode,wParam,lParam);
}
template<class PARENTWND>
LRESULT CALLBACK COXMenuBarHost<PARENTWND>::
MenuKeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
#if defined (_WINDLL)
#if defined (_AFXDLL)
AFX_MANAGE_STATE(AfxGetAppModuleState());
#else
AFX_MANAGE_STATE(AfxGetStaticModuleState());
#endif
#endif
ASSERT(g_pfnOldKeyboardHookProc!=NULL);
if(nCode<0)
{
// have to call the default implementation
return ::CallNextHookEx(g_pfnOldKeyboardHookProc,nCode,wParam,lParam);
}
CWnd* pTopLevelWnd=NULL;
CWnd* pWnd=GetFocus();
if(pWnd!=NULL)
{
pTopLevelWnd=pWnd->GetTopLevelParent();
}
else
{
pTopLevelWnd=CWnd::GetDesktopWindow();
}
ASSERT(pTopLevelWnd!=NULL);
ASSERT(g_arrMenuBarFrames.GetCount()>0);
POSITION pos=g_arrMenuBarFrames.GetStartPosition();
while(pos!=NULL)
{
HWND hWnd=NULL;
void* pMenuBarFrame=NULL;
g_arrMenuBarFrames.GetNextAssoc(pos,hWnd,pMenuBarFrame);
ASSERT(pMenuBarFrame!=NULL);
// call COXMenuBarHost implementation
if(::IsWindow(((COXMenuBarHost<PARENTWND>*)pMenuBarFrame)->m_hWnd) &&
pMenuBarFrame==pTopLevelWnd)
{
if(((COXMenuBarHost<PARENTWND>*)pMenuBarFrame)->
HandleKeyboardMsg(nCode,wParam,lParam))
{
return 1;
}
}
}
return ::CallNextHookEx(g_pfnOldKeyboardHookProc,nCode,wParam,lParam);
}
/////////////////////////////////////////////////////////////////////////
template<class PARENTDOCKBAR>
class COXMenuDockBar : public PARENTDOCKBAR
{
public:
// --- In :
// --- Out :
// --- Returns:
// --- Effect : Constructs the object
COXMenuDockBar();
// Operations
// --- In : bStretch - Indicates whether the bar should be
// stretched to the size of the frame.
// bHorz - Indicates that the bar is horizontally
// or vertically oriented. The bHorz parameter
// is nonzero if the bar is horizontally
// oriented and is 0 if it is vertically
// oriented.
// --- Out :
// --- Returns: The dock bar size, in pixels, of a CSize object
// --- Effect : Calculates size of the dock bar
virtual CSize CalcFixedLayout(BOOL bStretch, BOOL bHorz);
public:
// --- In :
// --- Out :
// --- Returns:
// --- Effect : Destructs the object
virtual ~COXMenuDockBar();
};
// constructor
template<class PARENTDOCKBAR>
COXMenuDockBar<PARENTDOCKBAR>::COXMenuDockBar()
{
// has to be derived from CDockBar or its derivates
if(!IsKindOf(RUNTIME_CLASS(CDockBar)))
{
TRACE(_T("COXMenuDockBar has to be derived from CDockBar or its derivations\n"));
AfxThrowNotSupportedException();
}
}
// destructor
template<class PARENTDOCKBAR>
COXMenuDockBar<PARENTDOCKBAR>::~COXMenuDockBar()
{
}
// mostly MFC code
template<class PARENTDOCKBAR>
CSize COXMenuDockBar<PARENTDOCKBAR>::CalcFixedLayout(BOOL bStretch, BOOL bHorz)
{
// scan all the control bars
int nPos=0;
for (nPos=0; nPos < m_arrBars.GetSize(); nPos++)
{
CControlBar* pBar=GetDockedControlBar(nPos);
if(pBar!=NULL && ::IsWindow(pBar->m_hWnd) && pBar->IsVisible() &&
pBar->IsKindOf(RUNTIME_CLASS(COXMenuBar)) &&
((COXMenuBar*)pBar)->GetTakeEntireRow())
{
((COXMenuBar*)pBar)->m_bForceEntireRow=TRUE;
}
}
// call the parent implementation
CSize sizeFixed=PARENTDOCKBAR::CalcFixedLayout(bStretch,bHorz);
CPoint pt(-afxData.cxBorder2, -afxData.cyBorder2);
// get max size
CSize sizeMax;
if(!m_rectLayout.IsRectEmpty())
{
sizeMax=m_rectLayout.Size();
}
else
{
CRect rectFrame;
CFrameWnd* pFrame=GetParentFrame();
ASSERT(pFrame!=NULL);
pFrame->GetClientRect(rectFrame);
pFrame->ClientToScreen(rectFrame);
for(int nID=AFX_IDW_CONTROLBAR_FIRST; nID<=AFX_IDW_CONTROLBAR_LAST; nID++)
{
CControlBar* pBar=m_pDockSite->GetControlBar(nID);
if(pBar!=NULL && pBar->IsDockBar() &&
pBar->IsVisible() && !pBar->IsFloating())
{
CRect rectBar;
pBar->GetWindowRect(rectBar);
if(pBar->GetStyle() & CBRS_TOP)
{
rectFrame.top=__max(rectFrame.top,rectBar.bottom);
}
else if(pBar->GetStyle() & CBRS_BOTTOM)
{
rectFrame.bottom=__min(rectFrame.bottom,rectBar.top);
}
}
}
sizeMax=rectFrame.Size();
}
// prepare for layout
AFX_SIZEPARENTPARAMS layout;
layout.hDWP=m_bLayoutQuery ? NULL :
::BeginDeferWindowPos(PtrToInt(m_arrBars.GetSize()));
BOOL bAdjustBars=FALSE;
CSize sizeOffset(0,0);
// scan all the control bars
for (nPos=0; nPos < m_arrBars.GetSize(); nPos++)
{
CControlBar* pBar=GetDockedControlBar(nPos);
if(pBar!=NULL && ::IsWindow(pBar->m_hWnd) && pBar->IsVisible() &&
pBar->IsKindOf(RUNTIME_CLASS(COXMenuBar)) &&
((COXMenuBar*)pBar)->GetTakeEntireRow())
{
// get ideal rect for bar
DWORD dwMode=0;
if((pBar->m_dwStyle & CBRS_SIZE_DYNAMIC) &&
(pBar->m_dwStyle & CBRS_FLOATING))
dwMode |= LM_HORZ | LM_MRUWIDTH;
else if(pBar->m_dwStyle & CBRS_ORIENT_HORZ)
dwMode |= LM_HORZ | LM_HORZDOCK;
else
dwMode |= LM_VERTDOCK;
if((dwMode&LM_HORZDOCK) || (dwMode&LM_VERTDOCK))
{
// get current rect for bar
CRect rectBar;
pBar->GetWindowRect(&rectBar);
ScreenToClient(&rectBar);
CSize sizeBar(rectBar.Width(),rectBar.Height());
CRect rect(pt,sizeBar);
if(bHorz)
{
rect.right=sizeMax.cx+afxData.cxBorder2;
rect.OffsetRect(0,rectBar.top-rect.top);
// check if menubar was droped on the same row with other
// control bar(s)
if(rectBar.left>rect.left)
{
ASSERT(nPos>0);
int nPrevPos=nPos-1;
CControlBar* pPrevBar=NULL;
while(TRUE)
{
ASSERT(nPrevPos>=0);
pPrevBar=GetDockedControlBar(nPrevPos);
if(pPrevBar==NULL ||
!::IsWindow(pPrevBar->GetSafeHwnd()) ||
pPrevBar->IsVisible())
{
break;
}
nPrevPos--;
}
if(pPrevBar!=NULL)
{
CRect rectPrevBar;
pPrevBar->GetWindowRect(&rectPrevBar);
rect.OffsetRect(0,rectPrevBar.Height()-
afxData.cyBorder2);
sizeOffset.cy+=__min(rectBar.Height(),
rectPrevBar.Height())-afxData.cyBorder2;
m_arrBars.InsertAt(nPos, (CObject*)NULL);
nPos++;
}
}
// mark the end of the row
CControlBar* pNextBar=NULL;
int nNextPos=nPos+1;
while(nNextPos<m_arrBars.GetSize())
{
pNextBar=GetDockedControlBar(nNextPos);
if(pNextBar==NULL || !::IsWindow(pNextBar->GetSafeHwnd()) ||
pNextBar->IsVisible())
break;
nNextPos++;
}
if(pNextBar!=NULL)
{
m_arrBars.InsertAt(nPos+1, (CObject*)NULL);
CRect rectNextBar;
pNextBar->GetWindowRect(&rectNextBar);
sizeOffset.cy+=rectNextBar.Height()-afxData.cyBorder2;
}
}
else
{
rect.bottom=sizeMax.cy;
rect.OffsetRect(rectBar.left-rect.left,0);
// check if menubar was droped on the same row with other
// control bar(s)
if(rectBar.top>rect.top)
{
ASSERT(nPos>0);
int nPrevPos=nPos-1;
CControlBar* pPrevBar=NULL;
while(TRUE)
{
ASSERT(nPrevPos>=0);
pPrevBar=GetDockedControlBar(nPrevPos);
if(pPrevBar==NULL ||
!::IsWindow(pPrevBar->GetSafeHwnd()) ||
pPrevBar->IsVisible())
break;
nPrevPos--;
}
if(pPrevBar!=NULL)
{
CRect rectPrevBar;
pPrevBar->GetWindowRect(&rectPrevBar);
rect.OffsetRect(rectPrevBar.Width()-afxData.cxBorder2,0);
sizeOffset.cx+=__min(rectBar.Width(),
rectPrevBar.Width())-afxData.cxBorder2;
m_arrBars.InsertAt(nPrevPos+1, (CObject*)NULL);
nPos++;
}
}
// mark the end of row
CControlBar* pNextBar=NULL;
int nNextPos=nPos+1;
while(nNextPos<m_arrBars.GetSize())
{
CControlBar* pNextBar=GetDockedControlBar(nNextPos);
if(pNextBar==NULL || !::IsWindow(pNextBar->GetSafeHwnd()) ||
pNextBar->IsVisible())
break;
nNextPos++;
}
if(pNextBar!=NULL)
{
m_arrBars.InsertAt(nPos+1, (CObject*)NULL);
}
}
if(sizeOffset.cx!=0 || sizeOffset.cy!=0)
{
bAdjustBars=TRUE;
}
if((bHorz && rectBar.Width()!=rect.Width() &&
!(rectBar.Width()>rect.Width())) ||
(!bHorz && rectBar.Height()!=rect.Height() &&
!(rectBar.Height()>rect.Height())))
{
AfxRepositionWindow(&layout, pBar->m_hWnd, &rect);
}
}
}
else if(pBar!=NULL && bAdjustBars)
{
// get current rect for bar
CRect rectBar;
pBar->GetWindowRect(&rectBar);
ScreenToClient(&rectBar);
rectBar+=sizeOffset;
AfxRepositionWindow(&layout, pBar->m_hWnd, &rectBar);
}
}
if(!m_bLayoutQuery)
{
if(layout.hDWP==NULL || !::EndDeferWindowPos(layout.hDWP))
{
TRACE(_T("Warning: DeferWindowPos failed - low system resources\n"));
}
}
if(bAdjustBars)
{
sizeFixed+=sizeOffset;
}
// scan all the control bars
for (nPos=0; nPos < m_arrBars.GetSize(); nPos++)
{
CControlBar* pBar=GetDockedControlBar(nPos);
if(pBar!=NULL && ::IsWindow(pBar->m_hWnd) && pBar->IsVisible() &&
pBar->IsKindOf(RUNTIME_CLASS(COXMenuBar)) &&
((COXMenuBar*)pBar)->GetTakeEntireRow())
{
((COXMenuBar*)pBar)->m_bForceEntireRow=FALSE;
}
}
return sizeFixed;
}
template<class PARENTFRAME, class PARENTDOCKBAR>
class COXMenuBarFrame : public COXMenuBarHost<PARENTFRAME>
{
public:
// dock bar control used internally
typedef COXMenuDockBar<PARENTDOCKBAR> CInternalDockBar;
// --- In : dwDockStyle - The desired styles for the control bar.
// menu bar style must be CBRS_ALIGN_XXX
// or 0 only. Refer to the description of
// CControlBar::SetBarStyle function
// for details.
// --- Out :
// --- Returns:
// --- Effect : Constructs the object
COXMenuBarFrame(DWORD dwDockStyle=CBRS_ALIGN_ANY,
CRuntimeClass* pFloatingFrameClass=RUNTIME_CLASS(CMiniDockFrameWnd));
// Operations
// --- In : dwDockStyle - Specifies which sides of the frame
// window can serve as docking sites for
// control bars. Refer to the description
// of CFrameWnd::EnableDocking function
// for details.
// --- Out :
// --- Returns:
// --- Effect : Call this function to enable dockable control bars in a
// frame window. By default, control bars will be docked to a
// side of the frame window in the following order:
// top, bottom, left, right.
virtual void EnableDocking(DWORD dwDockStyle);
virtual void RecalcLayout(BOOL bNotify=TRUE);
virtual BOOL LoadFrame(UINT nIDResource,
DWORD dwDefaultStyle=WS_OVERLAPPEDWINDOW|FWS_ADDTOTITLE,
CWnd* pParentWnd=NULL, CCreateContext* pContext=NULL);
virtual void OnUpdateFrameMenu(HMENU hMenuAlt);
// --- In : bEnable - Specifies whether then snapping behaviour
// should be turned on or off
// --- Out :
// --- Returns:
// --- Effect : Call this function to turn on the snaping and tear-off behaviour
// of toolbars, menubars and docking windows
void EnableSnapping(BOOL bEnable = TRUE);
protected:
// --- In : lpcs - A pointer to a Windows CREATESTRUCT
// structure.
// pContext - A pointer to a CCreateContext structure
// --- Out :
// --- Returns: Nonzero if successful; otherwise 0
// --- Effect :
virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext);
// Attributes
public:
protected:
// Specifies whether the snaping and tear-off behaviour of toolbars,
// menubars and docking windows is enabled
BOOL m_bEnableSnapping;
// Specifies which sides of the frame window can serve as docking
// sites for menu bar.
DWORD m_dwDockStyle;
// address of the window procedure, or a handle representing the address
// of the window procedure of MDIClient window
WNDPROC m_pfnOldMDIClientProc;
// flag that specifies that MDIClient window is subclassed
BOOL m_bIsMDISubclassed;
public:
// --- In :
// --- Out :
// --- Returns:
// --- Effect : Destructs the object
virtual ~COXMenuBarFrame();
// --- In : hWnd - Handle to the window to receive the message.
// msg - Specifies the message.
// wp - Specifies additional message-specific
// information. The contents of this parameter
// depend on the value of the msg parameter.
// lp - Specifies additional message-specific
// information. The contents of this parameter
// depend on the value of the Msg parameter.
// --- Out :
// --- Returns: the result of handling of message that was sent to
// MDIClient window
// --- Effect : Handles all messages that go to MDIClient window
virtual LRESULT HandleMDIClientMsg(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp);
protected:
// --- In : msg - message ID
// wp - WPARAM
// lp - LPARAM
// --- Out :
// --- Returns: result of message handling. Different for different messages.
// --- Effect : Handle all messages that go to the window
virtual LRESULT WindowProc(UINT msg, WPARAM wp, LPARAM lp);
// helper for resizing the menubar
BOOL CheckMenuBarSize(BOOL bNotify=TRUE);
// helper function to subclass MDIClient window
void SubclassMDIClient();
// handles context help
afx_msg void OnContextHelp();
// handles all messages in context help mode
BOOL ProcessHelpMsg(MSG& msg, DWORD* pContext);
// subclass window procedure for MDIClient window
static LRESULT CALLBACK MDISubclassProc(HWND hWnd, UINT msg,
WPARAM wp, LPARAM lp);
};
// analogue of CFrameWnd::dwDockBarMap
static const DWORD g_dwDockBarMap[4][2] =
{
{ AFX_IDW_DOCKBAR_TOP, CBRS_TOP },
{ AFX_IDW_DOCKBAR_BOTTOM, CBRS_BOTTOM },
{ AFX_IDW_DOCKBAR_LEFT, CBRS_LEFT },
{ AFX_IDW_DOCKBAR_RIGHT, CBRS_RIGHT },
};
template<class PARENTFRAME, class PARENTDOCKBAR>
COXMenuBarFrame<PARENTFRAME,PARENTDOCKBAR>::
COXMenuBarFrame(DWORD dwDockStyle/*=CBRS_ALIGN_ANY*/,
CRuntimeClass* pFloatingFrameClass/*=RUNTIME_CLASS(CMiniDockFrameWnd)*/)
{
// has to be derived from CframeWnd or its derivates
if(!IsKindOf(RUNTIME_CLASS(CFrameWnd)))
{
TRACE(_T("COXMenuBarFrame has to be derived from CFrameWnd or its derivates\n"));
AfxThrowNotSupportedException();
}
// menu bar style must be CBRS_ALIGN_XXX or 0 only
ASSERT(dwDockStyle==0 || (dwDockStyle & ~CBRS_ALIGN_ANY)==0);
m_dwDockStyle=dwDockStyle;
m_pfnOldMDIClientProc=NULL;
m_bIsMDISubclassed=FALSE;
m_pFloatingFrameClass=pFloatingFrameClass;
m_bEnableSnapping = FALSE;
}
template<class PARENTFRAME, class PARENTDOCKBAR>
COXMenuBarFrame<PARENTFRAME,PARENTDOCKBAR>::~COXMenuBarFrame()
{
}
template<class PARENTFRAME, class PARENTDOCKBAR>
BOOL COXMenuBarFrame<PARENTFRAME,PARENTDOCKBAR>::
OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
BOOL bResult=COXMenuBarHost<PARENTFRAME>::OnCreateClient(lpcs,pContext);
AddToGlobalList();
if(bResult && m_bIsMDI)
SubclassMDIClient();
return bResult;
}
template<class PARENTFRAME, class PARENTDOCKBAR>
void COXMenuBarFrame<PARENTFRAME,PARENTDOCKBAR>::RecalcLayout(BOOL bNotify/*=TRUE*/)
{
COXMenuBarHost<PARENTFRAME>::RecalcLayout(bNotify);
CheckMenuBarSize(bNotify);
}
template<class PARENTFRAME, class PARENTDOCKBAR>
BOOL COXMenuBarFrame<PARENTFRAME,PARENTDOCKBAR>::
LoadFrame(UINT nIDResource,
DWORD dwDefaultStyle/*=WS_OVERLAPPEDWINDOW|FWS_ADDTOTITLE*/,
CWnd* pParentWnd/*=NULL*/,
CCreateContext* pContext/*=NULL*/)
{
if(COXMenuBarHost<PARENTFRAME>::LoadFrame(nIDResource,dwDefaultStyle,
pParentWnd,pContext))
{
if(::IsWindow(GetMenuBar().GetSafeHwnd()))
m_hMenuDefault=GetMenuBar().GetMenu();
return TRUE;
}
return FALSE;
}
template<class PARENTFRAME, class PARENTDOCKBAR>
void COXMenuBarFrame<PARENTFRAME,PARENTDOCKBAR>::OnUpdateFrameMenu(HMENU hMenuAlt)
{
if(!m_bIsMDI)
{
if(hMenuAlt==NULL)
{
// attempt to get default menu from document
CDocument* pDoc=GetActiveDocument();
if(pDoc!=NULL)
hMenuAlt=pDoc->GetDefaultMenu();
// use default menu stored in frame if none from document
if(hMenuAlt==NULL)
hMenuAlt=m_hMenuDefault;
}
// finally, set the menu
SetMenu(CMenu::FromHandle(hMenuAlt));
}
else
{
PARENTFRAME::OnUpdateFrameMenu(hMenuAlt);
}
}
template<class PARENTFRAME, class PARENTDOCKBAR>
void COXMenuBarFrame<PARENTFRAME,PARENTDOCKBAR>::EnableSnapping(BOOL bEnable/*=TRUE*/)
{
m_bEnableSnapping = bEnable;
}
template<class PARENTFRAME, class PARENTDOCKBAR>
LRESULT COXMenuBarFrame<PARENTFRAME,PARENTDOCKBAR>::WindowProc(UINT msg,
WPARAM wp,
LPARAM lp)
{
#if defined (_WINDLL)
#if defined (_AFXDLL)
AFX_MANAGE_STATE(AfxGetAppModuleState());
#else
AFX_MANAGE_STATE(AfxGetStaticModuleState());
#endif
#endif
ASSERT(::IsWindow(((CFrameWnd*)this)->m_hWnd));
switch(msg)
{
// handle the creation of the frame
case WM_CREATE:
{
// call parent implementation
LRESULT lResult=COXMenuBarHost<PARENTFRAME>::WindowProc(msg,wp,lp);
if(lResult!=-1)
{
// menu must be already created at the moment
ASSERT(::IsWindow(GetMenuBar().GetSafeHwnd()));
if(m_bIsMDI)
// in order to subclass MDIClient if it's not done yet
SendMessage(WM_IDLEUPDATECMDUI);
// setup docking environment
GetMenuBar().EnableDocking(m_dwDockStyle);
if(m_dwDockStyle!=0)
{
EnableDocking(m_dwDockStyle);
CRect rect(0,0,0,0);
DockControlBar(&GetMenuBar(),(UINT)0,&rect);
}
//////////////////////////////
}
return lResult;
}
case WM_COMMAND:
{
WORD loWord=LOWORD(wp);
if(loWord==ID_CONTEXT_HELP)
{
OnContextHelp();
return 0;
}
#if _MFC_VER>0x0421
#ifndef _AFX_NO_OLE_SUPPORT
if(m_pNotifyHook!=NULL)
{
if(m_pNotifyHook->m_pActiveItem!=NULL)
{
CWnd* pWnd=m_pNotifyHook->m_pActiveItem->GetInPlaceWindow();
ASSERT(pWnd!=NULL);
if(pWnd->SendMessage(msg,wp,lp))
{
return TRUE;
}
}
}
#endif // _AFX_NO_OLE_SUPPORT
#endif // _MFC_VER>0x0421
break;
}
case WM_IDLEUPDATECMDUI:
if(m_bIsMDI)
{
m_bIsMDISubclassed=FALSE;
::SendMessage(((CMDIFrameWnd*)this)->m_hWndMDIClient,WM_NULL,0,0);
if(!m_bIsMDISubclassed)
{
TRACE(_T("COXMenuBarFrame: menubar has been removed out of the list of objects that subclass MDIClient\n"));
SubclassMDIClient();
if(::GetMenu(m_hWnd)!=NULL)
{
SetMenu(NULL);
}
}
}
break;
case WM_INITMENU:
{
if (GetMenuBar().m_hMenu != NULL)
wp = (WPARAM) GetMenuBar().m_hMenu;
}
break;
case WM_QUERYSNAPPING:
{
return m_bEnableSnapping;
}
break;
}
// I don't handle it: pass along
return COXMenuBarHost<PARENTFRAME>::WindowProc(msg,wp,lp);
}
template<class PARENTFRAME, class PARENTDOCKBAR>
void COXMenuBarFrame<PARENTFRAME,PARENTDOCKBAR>::OnContextHelp()
{
// don't enter twice, and don't enter if initialization fails
if(m_bHelpMode==HELP_ACTIVE || !CanEnterHelpMode())
return;
// don't enter help mode with pending WM_EXITHELPMODE message
MSG msg;
if(PeekMessage(&msg, m_hWnd, WM_EXITHELPMODE, WM_EXITHELPMODE,
PM_REMOVE|PM_NOYIELD))
{
return;
}
BOOL bHelpMode=m_bHelpMode;
ASSERT(m_bHelpMode==HELP_INACTIVE || m_bHelpMode==HELP_ENTERING);
m_bHelpMode=HELP_ACTIVE;
#ifndef _AFX_NO_OLE_SUPPORT
// allow any in-place active servers to go into help mode
if(bHelpMode!=HELP_ENTERING && m_pNotifyHook!=NULL &&
!m_pNotifyHook->OnContextHelp(TRUE))
{
TRACE0("Error: an in-place server failed to enter context help mode.\n");
m_pNotifyHook->OnContextHelp(FALSE); // undo partial help mode
m_bHelpMode=HELP_INACTIVE;
return;
}
#endif
if(bHelpMode==HELP_INACTIVE)
{
// need to delay help startup until later
PostMessage(WM_COMMAND, ID_CONTEXT_HELP);
m_bHelpMode=HELP_ENTERING;
return;
}
ASSERT(m_bHelpMode==HELP_ACTIVE);
// display special help mode message on status bar
UINT nMsgSave=(UINT)SendMessage(WM_SETMESSAGESTRING,
(WPARAM)AFX_IDS_HELPMODEMESSAGE);
if(nMsgSave==0)
{
nMsgSave=AFX_IDS_IDLEMESSAGE;
}
DWORD dwContext=0;
POINT point;
GetCursorPos(&point);
SetHelpCapture(point, NULL);
LONG lIdleCount=0;
CWinApp* pApp=AfxGetApp();
while(m_bHelpMode)
{
if(PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
{
if(!ProcessHelpMsg(msg, &dwContext))
{
break;
}
ASSERT(dwContext==0);
}
else if(!pApp->OnIdle(lIdleCount++))
{
lIdleCount=0;
WaitMessage();
}
}
m_bHelpMode=HELP_INACTIVE;
ReleaseCapture();
// make sure the cursor is set appropriately
SetCapture();
ReleaseCapture();
// restore original status bar text
SendMessage(WM_SETMESSAGESTRING, (WPARAM)nMsgSave);
#ifndef _AFX_NO_OLE_SUPPORT
// tell in-place servers to exit Shift+F1 help mode
if(m_pNotifyHook!=NULL)
{
m_pNotifyHook->OnContextHelp(FALSE);
}
#endif
if(dwContext!=0)
{
if(dwContext==-1)
{
SendMessage(WM_COMMAND, ID_DEFAULT_HELP);
}
else
{
pApp->WinHelp(dwContext);
}
}
PostMessage(WM_KICKIDLE); // trigger idle update
}
template<class PARENTFRAME, class PARENTDOCKBAR>
BOOL COXMenuBarFrame<PARENTFRAME,PARENTDOCKBAR>::ProcessHelpMsg(MSG& msg,
DWORD* pContext)
{
ASSERT(pContext!=NULL);
if(msg.message==WM_EXITHELPMODE ||
(msg.message==WM_KEYDOWN && msg.wParam==VK_ESCAPE))
{
PeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE);
return FALSE;
}
CPoint point;
if((msg.message >= WM_MOUSEFIRST && msg.message <= WM_MOUSELAST) ||
(msg.message >= WM_NCMOUSEFIRST && msg.message <= WM_NCMOUSELAST))
{
BOOL bDescendant;
HWND hWndHit=SetHelpCapture(msg.pt, &bDescendant);
if(hWndHit==NULL)
return TRUE;
BOOL bHitMenuBar=(hWndHit==GetMenuBar().GetSafeHwnd());
if(bDescendant)
{
if(bHitMenuBar)
{
if(msg.message==WM_LBUTTONDOWN || GetMenuBar().IsInDisplayingMode())
{
ASSERT(::GetCapture()==m_hWnd);
ReleaseCapture();
GetMessage(&msg, NULL, msg.message, msg.message);
DispatchMessage(&msg);
GetCursorPos(&point);
SetHelpCapture(point, NULL);
}
else
{
// Hit one of our owned windows -- eat the message.
PeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE);
return TRUE;
}
}
else
{
return COXMenuBarHost<PARENTFRAME>::ProcessHelpMsg(msg,pContext);
}
}
else
{
// Hit one of our apps windows (or desktop) -- dispatch the message.
PeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE);
// Dispatch mouse messages that hit the desktop!
DispatchMessage(&msg);
}
}
else
{
return COXMenuBarHost<PARENTFRAME>::ProcessHelpMsg(msg,pContext);
}
return TRUE;
}
template<class PARENTFRAME, class PARENTDOCKBAR>
BOOL COXMenuBarFrame<PARENTFRAME,PARENTDOCKBAR>::
CheckMenuBarSize(BOOL bNotify/*=TRUE*/)
{
BOOL bLayoutRecalculated=FALSE;
COXMenuBar& menuBar=GetMenuBar();
if(::IsWindow(menuBar.GetSafeHwnd()) && !menuBar.IsFloating())
{
CRect rectMenuBar;
menuBar.GetWindowRect(rectMenuBar);
BOOL bHorz=(menuBar.m_dwStyle & CBRS_ORIENT_HORZ);
CControlBar* pDockBar=NULL;
if(bHorz)
{
pDockBar=GetControlBar(AFX_IDW_DOCKBAR_TOP);
if(pDockBar!=NULL)
pDockBar=GetControlBar(AFX_IDW_DOCKBAR_BOTTOM);
}
else
{
pDockBar=GetControlBar(AFX_IDW_DOCKBAR_LEFT);
if(pDockBar!=NULL)
pDockBar=GetControlBar(AFX_IDW_DOCKBAR_RIGHT);
}
if(pDockBar!=NULL)
{
CRect rectDockBar;
pDockBar->GetWindowRect(rectDockBar);
if((bHorz && rectDockBar.Width()!=rectMenuBar.Width()) ||
(!bHorz && rectDockBar.Height()!=rectMenuBar.Height()))
{
COXMenuBarHost<PARENTFRAME>::RecalcLayout(bNotify);
bLayoutRecalculated=TRUE;
}
}
}
return bLayoutRecalculated;
}
template<class PARENTFRAME, class PARENTDOCKBAR>
void COXMenuBarFrame<PARENTFRAME,PARENTDOCKBAR>::SubclassMDIClient()
{
ASSERT(::IsWindow(m_hWnd));
if(m_bIsMDI)
{
// if MDI application then we have to handle MDIClient messages
WNDPROC pfnOldMDIClientProc=
(WNDPROC)::GetWindowLongPtr(((CMDIFrameWnd*)this)->
m_hWndMDIClient,GWL_WNDPROC);
if(m_pfnOldMDIClientProc!=pfnOldMDIClientProc)
{
m_pfnOldMDIClientProc=pfnOldMDIClientProc;
::SetWindowLongPtr(((CMDIFrameWnd*)this)->m_hWndMDIClient,GWL_WNDPROC,
(LONG_PTR)MDISubclassProc);
m_bIsMDISubclassed=TRUE;
}
}
}
// dock bars will be created in the order specified by g_dwDockBarMap
// this also controls which gets priority during layout
// this order can be changed by calling EnableDocking repetitively
// with the exact order of priority
template<class PARENTFRAME, class PARENTDOCKBAR>
void COXMenuBarFrame<PARENTFRAME,PARENTDOCKBAR>::
EnableDocking(DWORD dwDockStyle)
{
// must be CBRS_ALIGN_XXX or CBRS_FLOAT_MULTI only
ASSERT((dwDockStyle & ~(CBRS_ALIGN_ANY|CBRS_FLOAT_MULTI))==0);
ASSERT(m_pFloatingFrameClass!=NULL);
for (int i=0; i < 4; i++)
{
if(g_dwDockBarMap[i][1] & dwDockStyle & CBRS_ALIGN_ANY)
{
CInternalDockBar* pDock=
(CInternalDockBar*)GetControlBar(g_dwDockBarMap[i][0]);
if(pDock==NULL)
{
// use our internal implementation of the dock bar
pDock=new CInternalDockBar;
if(!pDock->Create(this,
WS_CLIPSIBLINGS|WS_CLIPCHILDREN|WS_CHILD|WS_VISIBLE|
g_dwDockBarMap[i][1], g_dwDockBarMap[i][0]))
{
AfxThrowResourceException();
}
}
}
}
}
template<class PARENTFRAME, class PARENTDOCKBAR>
LRESULT COXMenuBarFrame<PARENTFRAME,PARENTDOCKBAR>::HandleMDIClientMsg(HWND hWnd,
UINT msg,
WPARAM wp,
LPARAM lp)
{
// only in MDIFrame
ASSERT(m_bIsMDI);
ASSERT(::IsWindow(m_hWnd));
switch(msg)
{
case WM_MDISETMENU:
ASSERT(::IsWindow(GetMenuBar().GetSafeHwnd()));
// set new menu to the menubar
if(NULL!=wp && ::IsWindow(GetMenuBar().GetSafeHwnd()) &&
::IsWindow(GetMenuBar().GetToolBarCtrl().GetSafeHwnd()))
{
GetMenuBar().SetMenu((HMENU)wp);
}
wp=NULL;
if(GetMenuBar().m_hMDIWindowMenu!=NULL)
{
lp=(LPARAM)GetMenuBar().m_hMDIWindowMenu;
}
break;
case WM_MDIACTIVATE:
case WM_MDICREATE:
case WM_MDIDESTROY:
// the icon of the MDIChild window could have changed
if(::IsWindow(GetMenuBar().GetSafeHwnd()))
GetMenuBar().PostMessage(WM_IDLEUPDATECMDUI);
break;
case WM_NULL:
m_bIsMDISubclassed=TRUE;
break;
}
// handle other messages
if(m_pfnOldMDIClientProc!=NULL)
return ::CallWindowProc(m_pfnOldMDIClientProc,hWnd,msg,wp,lp);
return 0;
}
template<class PARENTFRAME, class PARENTDOCKBAR>
LRESULT CALLBACK COXMenuBarFrame<PARENTFRAME,PARENTDOCKBAR>::
MDISubclassProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
#if defined (_WINDLL)
#if defined (_AFXDLL)
AFX_MANAGE_STATE(AfxGetAppModuleState());
#else
AFX_MANAGE_STATE(AfxGetStaticModuleState());
#endif
#endif
HWND hWndParent=::GetParent(hWnd);
ASSERT(hWndParent!=NULL);
void* pMenuBarFrame=NULL;
if(!g_arrMenuBarFrames.Lookup(hWndParent,pMenuBarFrame))
return 0;
ASSERT(pMenuBarFrame!=NULL);
// call COXMenuBarFrame implementation
if(::IsWindow(((COXMenuBarFrame<PARENTFRAME,PARENTDOCKBAR>*)
pMenuBarFrame)->m_hWnd))
{
return ((COXMenuBarFrame<PARENTFRAME,PARENTDOCKBAR>*)pMenuBarFrame)->
HandleMDIClientMsg(hWnd,msg,wp,lp);
}
return 0;
}
#endif // _MFC_VER>=0x0420
#endif // _MENUBAR_H