|
|
#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_
|