#ifndef _MENUBAND_H_ #define _MENUBAND_H_ #include "bands.h" #include "mnbase.h" #include "legacy.h" // Flags for MBANDCID_POPUPITEM #define MBPUI_SETITEM 0x00001 #define MBPUI_INITIALSELECT 0x00002 #define MBPUI_ITEMBYPOS 0x00004 #ifdef STARTMENUSPLIT // Flags for constructor #define MENUBAND_HORIZ 0x00000001 #define MENUBAND_TOPLEVEL 0x00000002 #endif // Special indices for MBANDCID_SELECTITEM #define MBSI_FIRSTITEM 0 #define MBSI_NONE -1 #define MBSI_LASTITEM -2 // This arrow is used when we are in Right-To-Left Mirror mode #define CH_MENUARROWRTLA '3' // Forward declare struct CMBMsgFilter; // Define this to get Shell Expando menu style // Undefine to get "Office IntelliMenu" style //#define DRAWEDGE // The CMenuBand class handles all menu behavior for bands. class CMenuBandMetrics : public IUnknown { public: // *** IUnknown methods *** STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj); HFONT _CalcFont(HWND hwnd, LPCTSTR pszFont, DWORD dwCharSet, TCHAR ch, int* pcx, int* pcy, int* pcxMargin, int iOrientation, int iWeight); void _SetMenuFont(); // (Called for TopLevMBand only) Sets: _hFontMenu void _SetArrowFont(HWND hwnd); // (Called for TopLevMBand only) Sets: _hFontArrow, _cyArrow void _SetChevronFont(HWND hwnd); void _SetTextBrush(HWND hwnd); #ifndef DRAWEDGE void _SetPaintMetrics(HWND hwnd); #endif void _SetColors(); int _cyArrow; // Height of cascade arrow int _cxArrow; // Width of cascade arrow int _cxMargin; // Margin b/t text and arrow int _cyChevron; int _cxChevron; int _cxChevronMargin; HCURSOR _hCursorOld; // Cursor that was in use prior to entering menu mode HFONT _hFontMenu; // Font for menu text HFONT _hFontArrow; // Correct sized Marlett font for cascade arrow HFONT _hFontChevron; HBRUSH _hbrText; #ifndef DRAWEDGE HPEN _hPenHighlight; // Pen for BTNHIGHLIGHT HPEN _hPenShadow; // Pen for BTNSHADOW #endif COLORREF _clrBackground; COLORREF _clrDemoted; COLORREF _clrMenuText; COLORREF _clrMenuGrad; BOOL _fHighContrastMode; // Accessibility BOOL _fFlatMenuMode; BOOL _fInit; CMenuBandMetrics(); void Init(HWND hwnd); private: ~CMenuBandMetrics(); ULONG _cRef; }; class CMenuBandState { // Global State Variables BYTE _fsUEMState; BOOL _fKeyboardCue; IFadeTask* _ptFader; IShellTaskScheduler* _pScheduler; HWND _hwndSubclassed; HWND _hwndToolTip; HWND _hwndWorker; void* _pvContext; // Bits BITBOOL _fExpand: 1; BITBOOL _fContainsDrag: 1; BITBOOL _fTipShown: 1; BITBOOL _fBalloonStyle: 1; int _cChangeNotify; // This will, in the future, contain the menuband stack public: CMenuBandState(); virtual ~CMenuBandState(); // Set/Get the expand state for new popups. BOOL GetExpand() { return (BOOL)_fExpand; }; void SetExpand(BOOL fExpand) { _fExpand = BOOLIFY(fExpand);}; BYTE GetUEMState() { return _fsUEMState; }; void SetUEMState(BYTE bState) { _fsUEMState = bState; }; BOOL GetKeyboardCue(); void SetKeyboardCue(int iKC); BOOL HasDrag() { return _fContainsDrag; }; void HasDrag(BOOL fHasDrag) { _fContainsDrag = BOOLIFY(fHasDrag); }; void SetSubclassedHWND(HWND hwndSubclassed) { _hwndSubclassed = hwndSubclassed; }; HWND GetSubclassedHWND() { return _hwndSubclassed; }; HWND GetWorkerWindow(HWND hwndParent); void PushChangeNotify() { ++_cChangeNotify; }; void PopChangeNotify() { --_cChangeNotify; }; BOOL IsProcessingChangeNotify() { return _cChangeNotify != 0; }; // Context Stuff // a menuband context is used for the global message filter. Since we may have // more than one menu present in the system, there is a race condition that can occur // where the menu in one thread tries to pop off it's menus, when a menuband in another thread // tries to push them on. Through the use of a context, we can know when this is happening and // make sure that we pop all of the menus of one context before pushing from another. // - lamadio 9.15.98 void SetContext(void* pvContext) {_pvContext = pvContext;}; void* GetContext() { return _pvContext;}; // Fade Stuff HRESULT FadeRect(LPCRECT prc); void CreateFader(); IShellTaskScheduler* GetScheduler(); // Chevron Tip Stuff void CenterOnButton(HWND hwndTB, BOOL fBalloon, int idCmd, LPTSTR pszTitle, LPTSTR szTip); void HideTooltip(BOOL fAllowBalloonCollapse); void PutTipOnTop(); }; interface IShellMenuAcc: public IUnknown { // *** IShellMenuAcc methods *** STDMETHOD(GetTop)(THIS_ CMenuToolbarBase** ppmtbTop) PURE; STDMETHOD(GetBottom)(THIS_ CMenuToolbarBase** ppmtbBottom) PURE; STDMETHOD(GetTracked)(THIS_ CMenuToolbarBase** ppmtbTracked) PURE; STDMETHOD(GetParentSite)(THIS_ REFIID riid, void** ppvObj) PURE; STDMETHOD(GetState)(THIS_ BOOL* pfVertical, BOOL* pfOpen) PURE; STDMETHOD(DoDefaultAction)(THIS_ VARIANT* pvarChild) PURE; STDMETHOD(GetSubMenu)(THIS_ VARIANT* pvarChild, REFIID riid, void** ppvObj) PURE; STDMETHOD(IsEmpty)() PURE; }; // {FAF6FE96-CE5E-11d1-8371-00C04FD918D0} DEFINE_GUID(IID_IShellMenuAcc, 0xfaf6fe96, 0xce5e, 0x11d1, 0x83, 0x71, 0x0, 0xc0, 0x4f, 0xd9, 0x18, 0xd0); class CMenuBand : public CToolBand, public IMenuPopup, public IMenuBand, public IShellMenu2, public IWinEventHandler, public IShellMenuAcc { // REVIEW (lamadio): I don't like this. Should I make these nested classes? friend class CMenuToolbarBase; friend class CMenuSFToolbar; friend class CMenuStaticToolbar; friend class CToolbarMenu; friend struct CMBMsgFilter; public: // *** IUnknown *** virtual STDMETHODIMP_(ULONG) AddRef(void) { return CToolBand::AddRef(); }; virtual STDMETHODIMP_(ULONG) Release(void) { return CToolBand::Release(); }; virtual STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj); // *** IDockingWindow methods (override) *** virtual STDMETHODIMP ShowDW(BOOL fShow); virtual STDMETHODIMP CloseDW(DWORD dw); // *** IInputObject methods (override) *** virtual STDMETHODIMP TranslateAcceleratorIO(LPMSG lpMsg); virtual STDMETHODIMP HasFocusIO(); virtual STDMETHODIMP UIActivateIO(BOOL fActivate, LPMSG lpMsg); // *** IOleWindow methods *** virtual STDMETHODIMP GetWindow(HWND * phwnd); virtual STDMETHODIMP ContextSensitiveHelp(BOOL bEnterMode); // *** IServiceProvider methods *** virtual STDMETHODIMP QueryService(REFGUID guidService, REFIID riid, LPVOID* ppvObj); // *** IDeskBar methods *** virtual STDMETHODIMP SetClient(IUnknown* punk) { return E_NOTIMPL; }; virtual STDMETHODIMP GetClient(IUnknown** ppunkClient) { return E_NOTIMPL; }; virtual STDMETHODIMP OnPosRectChangeDB (LPRECT prc); // *** IDeskBand methods *** virtual STDMETHODIMP GetBandInfo(DWORD dwBandID, DWORD fViewMode, DESKBANDINFO* pdbi); // *** IMenuPopup methods *** virtual STDMETHODIMP OnSelect(DWORD dwSelectType); virtual STDMETHODIMP SetSubMenu(IMenuPopup* pmp, BOOL fSet); virtual STDMETHODIMP Popup(POINTL *ppt, RECTL *prcExclude, DWORD dwFlags) { return E_NOTIMPL; }; // *** IMenuBand methods *** virtual STDMETHODIMP IsMenuMessage(MSG * pmsg); virtual STDMETHODIMP TranslateMenuMessage(MSG * pmsg, LRESULT * plRet); // *** IShellMenu methods *** virtual STDMETHODIMP Initialize(IShellMenuCallback* psmc, UINT uId, UINT uIdAncestor, DWORD dwFlags); virtual STDMETHODIMP GetMenuInfo(IShellMenuCallback** ppsmc, UINT* puId, UINT* puIdAncestor, DWORD* pdwFlags); virtual STDMETHODIMP SetShellFolder(IShellFolder* psf, LPCITEMIDLIST pidlFolder, HKEY hkey, DWORD dwFlags); virtual STDMETHODIMP GetShellFolder(DWORD* pdwFlags, LPITEMIDLIST* ppidl, REFIID riid, void** ppvObj); virtual STDMETHODIMP SetMenu(HMENU hmenu, HWND hwnd, DWORD dwFlags); virtual STDMETHODIMP GetMenu(HMENU* phmenu, HWND* phwnd, DWORD* pdwFlags); virtual STDMETHODIMP InvalidateItem(LPSMDATA psmd, DWORD dwFlags); virtual STDMETHODIMP GetState(LPSMDATA psmd); virtual STDMETHODIMP SetMenuToolbar(IUnknown* punk, DWORD dwFlags); // *** IShellMenu2 methods *** virtual STDMETHODIMP GetSubMenu(UINT idCmd, REFIID riid, LPVOID *ppvObj); virtual STDMETHODIMP SetToolbar(HWND hwnd, DWORD dwFlags); virtual STDMETHODIMP SetMinWidth(int cxMenu); virtual STDMETHODIMP SetNoBorder(BOOL fNoBorder); virtual STDMETHODIMP SetTheme(LPCWSTR pszTheme); // ** IPersist *** virtual STDMETHODIMP GetClassID(CLSID*) { return E_NOTIMPL; }; virtual STDMETHODIMP Load(IStream*) { return E_NOTIMPL; }; virtual STDMETHODIMP Save(IStream*, BOOL) { return E_NOTIMPL; }; // ** IWinEventHandler *** virtual STDMETHODIMP IsWindowOwner(HWND hwnd); virtual STDMETHODIMP OnWinEvent(HWND hwnd, UINT dwMsg, WPARAM wParam, LPARAM lParam, LRESULT* plres); // *** IObjectWithSite methods *** virtual STDMETHODIMP SetSite(IUnknown* punkSite); // *** IOleCommandTarget *** virtual STDMETHODIMP Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut); // *** IShellMenuAcc *** virtual STDMETHODIMP GetTop(CMenuToolbarBase** ppmtbTop); virtual STDMETHODIMP GetBottom(CMenuToolbarBase** ppmtbBottom); virtual STDMETHODIMP GetTracked(CMenuToolbarBase** ppmtbTracked); virtual STDMETHODIMP GetParentSite(REFIID riid, void** ppvObj); virtual STDMETHODIMP GetState(BOOL* pfVertical, BOOL* pfOpen); virtual STDMETHODIMP DoDefaultAction(VARIANT* pvarChild); virtual STDMETHODIMP GetSubMenu(VARIANT* pvarChild, REFIID riid, void** ppvObj); virtual STDMETHODIMP IsEmpty(); // Other methods LRESULT GetMsgFilterCB(MSG * pmsg, BOOL bRemove); inline BOOL IsInSubMenu(void) { return _fInSubMenu; }; inline DWORD GetFlags() {return _dwFlags; }; // Other public methods void ResizeMenuBar(); // Make our parent menubar resize void SetTrackMenuPopup(IUnknown* punk); HRESULT ForwardChangeNotify(LONG lEvent, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2); // Change notify Forwarder. CMenuBand(); BOOL SetTracked(CMenuToolbarBase* pmtb); private: friend HRESULT CMenuBand_CreateInstance(IUnknown * punkOuter, REFIID riid, void **ppv); friend VOID CALLBACK CMenuBand_TimerProc( HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime ); friend CMenuBand * CMenuBand_Create(IShellFolder* psf, LPCITEMIDLIST pidl, BOOL bHorizontal); virtual ~CMenuBand(); HRESULT _Initialize(DWORD dwFlags);// Flags are MENUBAND_* HRESULT _EnterMenuMode(void); void _ExitMenuMode(void); void _GetFontMetrics(); // (Called for non-TopLevelMBands) Uses IUnk_QS to set // _hFontMenu, _hFontArrow, _cyArrow based on TopLevel's values void _CancelMode(DWORD dwType); HRESULT _AddToolbar(CMenuToolbarBase* pmtb, DWORD dwFlags); HRESULT _SiteOnSelect(DWORD dwType); HRESULT _SubMenuOnSelect(DWORD dwType); HRESULT _OnSysChar(MSG * pmsg, BOOL bFirstDibs); HRESULT _HandleAccelerators(MSG * pmsg); HRESULT _SiteSetSubMenu(IMenuPopup * pmp, BOOL bSet); void _OnSelectArrow(int iDir); void _UpdateButtons(); HRESULT _CallCB(DWORD dwMsg, WPARAM wParam = 0, LPARAM lParam = 0); HRESULT _ProcessMenuPaneMessages(MSG* pmsg); // Member variables int _nItemCur; // Current item selected int _nItemNew; // New item to be selected/expanded int _nItemTimer; // the timer id for popping up cascading menus int _nItemMove; // Current item being moved int _nItemSubMenu; // item that's cascaded HWND _hwndFocusPrev; HWND _hwndParent; BOOL _fNoBorder; WCHAR* _pszTheme; CMenuToolbarBase* _pmtbMenu; // The static menu toolbar // (may be pmtbTop or pmtbBottom) CMenuToolbarBase* _pmtbShellFolder; // Non-menu toolbar (shellfolder or other) // (may be pmtbTop or pmtbBottom) CMenuToolbarBase* _pmtbTop; // The top toolbar CMenuToolbarBase* _pmtbBottom; // The bottom toolbar (may be == pmtbTop) CMenuToolbarBase* _pmtbTracked; // This is transient, may be pmtbTop or pmtbBottom IAugmentedShellFolder2* _pasf2; UINT _uId; // Id of this band (Derived from the item that poped it up) UINT _uIdAncestor; // Id of the top most menu item. HMENU _hmenu; HWND _hwndMenuOwner; DWORD _dwMenuFlags; CMenuBandState* _pmbState; // Menu Band global state CMenuBandMetrics* _pmbm; IShellMenuCallback* _psmcb; // Callback Mechanism HCURSOR _hCursorOld; DWORD _dwFlags; UINT _uIconSize; IMenuPopup* _pmpSubMenu; // Cached submenu IMenuPopup* _pmpTrackPopup; // Find a way to use only menubands. void* _pvUserData; // User associated data. BITBOOL _fTopLevel: 1; // TRUE: this is the toplevel parent menu // (may be vertical for context menus) BITBOOL _fMenuMode: 1; // TRUE: we are in menu mode BITBOOL _fPopupNewMenu: 1; // TRUE: popup a new menu (_nItemNew) // once done with current menu BITBOOL _fInitialSelect: 1; // TRUE: select first item when popping up submenu BITBOOL _fInSubMenu: 1; // TRUE: currently in a submenu BITBOOL _fAltSpace: 1; // TRUE: Alt-space was hit BITBOOL _fMenuFontCreated: 1; // TRUE: This instance created the font and should delete it BITBOOL _fArrowFontCreated: 1; // TRUE: This instance created the font and should delete it BITBOOL _fEmpty: 1; // TRUE: Menu is empty BITBOOL _fParentIsNotASite: 1; BITBOOL _fKeyboardSelected: 1; BITBOOL _fInvokedByDrag: 1; // TRUE: the menu cascaded open b/c of drag/drop BITBOOL _fDragEntered : 1; BITBOOL _fSysCharHandled: 1; // TRUE: WM_SYSCHAR was already handled BITBOOL _fHasSubMenu:1; BITBOOL _fAppActive:1; // TRUE: The Menus should be drawn using Memphis' grey menu. BITBOOL _fVertical: 1; BITBOOL _fShow : 1; BITBOOL _fClosing: 1; // TRUE: When CloseDW is called. BITBOOL _fForceButtonUpdate: 1; // TRUE: Force a v_UpdateButtons. BITBOOL _fProcessingDup: 1; // TRUE: when the contained classes are processing Dup chars. BITBOOL _fExpanded: 1; // TRUE: This band is expanded BITBOOL _fCascadeAnimate: 1; BITBOOL _fPopupNewItemOnShow: 1; // Causes _nItemNew to be displayed at ShowDW time. BITBOOL _fParentIsHorizontal: 1; #ifdef DEBUG BITBOOL _fInitialized: 1; #endif DEBUG_CODE( int _nMenuLevel; ) }; HRESULT IUnknown_BandChildSetKey(IUnknown* punk, HKEY hKey); // The message filter redirects messages to the menuband // that is at the top of the stack. Each additional cascade // pushes the new menuband onto the stack, and a cancel-level // pops one off. typedef struct tagMBELEM { CMenuBand * pmb; HWND hwndTB; HWND hwndBar; RECT rc; // rect of hwndBar BITBOOL bInitRect: 1; // TRUE: rc is initialized } MBELEM; #define CMBELEM_INIT 10 #define CMBELEM_GROW 10 struct CMBMsgFilter { public: HHOOK _hhookMsg; HWND _hwndCapture; FDSA _fdsa; // Stack MBELEM _rgmbelem[CMBELEM_INIT]; BITBOOL _fPreventCapture : 1; BITBOOL _fInitialized: 1; BITBOOL _fSetAtPush: 1; BITBOOL _fDontIgnoreSysChar: 1; BITBOOL _fEngaged: 1; BITBOOL _fModal: 1; BITBOOL _fAllocated: 1; POINT _ptLastMove; CMenuBand* _pmb; int _iSysCharStack; void* _pvContext; HCURSOR _hcurArrow; int _cRef; DEBUG_CODE( int _nMenuLevel; ) void AddRef(); void Release(); void ForceModalCollapse(); void SetModal(BOOL fModal); // This is so that // a modal message band (Links) // sets activation correctly. void* GetContext() { return _pvContext; }; void SetContext(void* pvContext, BOOL fSet); void Push(void* pvContext, CMenuBand * pmb, IUnknown * punkSite); int Pop(void* pvContext); void RetakeCapture(void); void AcquireMouseLocation() { GetCursorPos(&_ptLastMove); }; void ReEngage(void* pvContext); void DisEngage(void* pvContext); BOOL IsEngaged() { return _fEngaged;}; CMenuBand * _GetBottomMostSelected(void); CMenuBand * _GetTopPtr(void); CMenuBand * _GetWindowOwnerPtr(HWND hwnd); CMenuBand * _HitTest(POINT pt, HWND * phwnd = NULL); LRESULT _HandleMouseMsgs(MSG * pmsg, BOOL bRemove); HRESULT _TopFilterMouseMessage(MSG *pmsg, BOOL bRemove, CMenuBand *pmbTarget); void PreventCapture(BOOL bSet) { _fPreventCapture = BOOLIFY(bSet); } CMenuBand * GetTopMostPtr(void) { return _pmb; }; void SetTopMost(CMenuBand* pmb) {_pmb = pmb; }; void SetHook(BOOL fSet, BOOL fIgnoreSysChar); static LRESULT CALLBACK GetMsgHook(int nCode, WPARAM wParam, LPARAM lParam); //private: }; CMBMsgFilter* GetMessageFilter(); extern CMBMsgFilter g_msgfilter; extern UINT g_nMBPopupOpen; extern UINT g_nMBFullCancel; extern UINT g_nMBDragCancel; extern UINT g_nMBAutomation; extern UINT g_nMBExecute; extern UINT g_nMBOpenChevronMenu; #define MBTIMER_POPOUT 0x00008001 // event ID for popout menu timer #define MBTIMER_DRAGOVER 0x00008002 // event ID for popout menu timer #define MBTIMER_EXPAND 0x00008003 #define MBTIMER_TIMEOUT (GetDoubleClickTime() * 4 / 5) // same formula that USER uses #define MBTIMER_ENDEDIT 0x00008004 #define MBTIMER_ENDEDITTIME 1000 #define MBTIMER_CLOSE 0x00008005 #define MBTIMER_CLOSETIME 2000 #define MBTIMER_CLICKUNHANDLE 0x00008006 // Flashing Support #define MBTIMER_FLASH 0x00008007 #define MBTIMER_FLASHTIME 100 #define COUNT_ENDFLASH 8 // UEM Profiling. #define MBTIMER_UEMTIMEOUT 0x00008008 #define MBTIMER_DRAGPOPDOWN 0x00008009 #define MBTIMER_DRAGPOPDOWNTIMEOUT (2 * GetDoubleClickTime()) //ASSERT(MBTIMER_DRAGPOPDOWNTIMEOUT > // MBTIMER_TIMEOUR) #define MBTIMER_CHEVRONTIP 0x0000800A #define MBTIMER_INFOTIP 0x0000800B #define CH_RETURN 0xd #define szfnMarlett TEXT("MARLETT") #endif // _MENUBAND_H_