//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //===========================================================================// #ifndef MENU_H #define MENU_H #ifdef _WIN32 #pragma once #endif #include #include #include #include namespace vgui { class MenuItem; class ScrollBar; class MenuSeparator; //----------------------------------------------------------------------------- // Purpose: A menu is a list of items that can be selected with one click, navigated // with arrow keys and/or hot keys, and have a lit behavior when mouse over. // It is NOT the button which opens the menu, but only the menu itself. // // Behaviour spec: // Menu navigation can be done in 2 modes, via keyboard keys and via mouse. // Clicking on menu button opens menu. // Only one item in a menu is highlighted at a time. // Only one submenu in a menu is open at a time. // Disabled menuitems get highlighted via mouse and keys but will not activate. // // Mouse: // Moving mouse into a menuitem highlights it. // If the menuitem has a cascading menu, the menu opens when the mouse enters // the menuitem. The cascading menuitem stays highlighted while its menu is open. // No submenu items are highlighted by default. // Moving the mouse into another menuitem closes any previously open submenus in the list. // Clicking once in the menu item activates the menu item and closes all menus. // Moving the mouse off a menuitem unhighlights it. // The scroll bar arrows can be used to move up/down the menu one item at a time. // The clicking and dragging on the scroll bar nob also scrolls the menu items. // If a highlighed menuitem scrolls off, and the user then begins navigating via keys, // the menu will snap the scroll bar so the highlighted item is visible. // If user has been navigating via keys, moving the mouse over a menu item // highlights it. // Mousewheel: // You must have the mouse inside the menu/scroll bar to use the wheel. // The mouse wheel moves the highlighted menuitem up or down the list. // If the list has no scroll bar the wheel will cycle from the bottom of the list // to the top of the list and vice versa. // If the list has a scrollbar the mouse wheel will stop at the top or bottom // of the list. // If the mouse is over the scroll bar no items are highlighted. // Keyboard: // When a menu is opened, no items are highlighted. // If a menuitem has a cascading menu it does not open when the item is highlighted. // The down arrow selects the next item in the list. // (first item if none are highlighted and there is a scrollbar). // The up arrow selects the previous item in the list // (first item if none are highlighted and there is a scrollbar, last item if none are // highlighted and there is no scrollbar). // Selecting a new menuitem closes any previously open submenus in the list. // The enter key activates the selected item and closes all menus. // If the selected item has a cascading menu, activating it opens its submenu. // These may also be activated by pressing the right arrow. // Pressing the left arrow closes the submenu. // When the submenu is opened the cascading menuitem stays highlighted. // No items in the submenu are highlighted when it is opened. // // Note: Cascading menuitems in menus with a scrollbar is not supported. // Its a clunky UI and if we want this we should design a better solution, // perhaps along the lines of how explorer's bookmarks does it. // It currently functions, but there are some arm/disarm bugs. // // //----------------------------------------------------------------------------- class Menu : public Panel { DECLARE_CLASS_SIMPLE( Menu, Panel ); friend class MenuItem; public: enum MenuDirection_e { LEFT, RIGHT, UP, DOWN, CURSOR, // make the menu appear under the mouse cursor ALIGN_WITH_PARENT, // make the menu appear under the parent }; Menu(Panel *parent, const char *panelName); ~Menu(); static void PlaceContextMenu( Panel *parent, Menu *menu ); static void OnInternalMousePressed( Panel *other, MouseCode code ); virtual void PositionRelativeToPanel( Panel *reference, MenuDirection_e direction, int nAdditionalYOffset = 0, bool showMenu = false ); // the menu. For combo boxes, it's the edit/field, etc. etc. // Add a simple text item to the menu virtual int AddMenuItem( const char *itemName, const char *itemText, const char *command, Panel *target, const KeyValues *userData = NULL ); virtual int AddMenuItem( const char *itemName, const wchar_t *wszItemText, const char *command, Panel *target, const KeyValues *userData = NULL ); virtual int AddMenuItem( const char *itemName, const char *itemText, KeyValues *message, Panel *target , const KeyValues *userData = NULL); virtual int AddMenuItem( const char *itemName, const wchar_t *wszItemText, KeyValues *message, Panel *target , const KeyValues *userData = NULL); virtual int AddMenuItem( const char *itemText, const char *command, Panel *target , const KeyValues *userData = NULL); virtual int AddMenuItem( const char *itemText, KeyValues *message, Panel *target, const KeyValues *userData = NULL ); virtual int AddMenuItem( const char *itemText, Panel *target, const KeyValues *userData = NULL ); // Add a checkable item to the menu virtual int AddCheckableMenuItem( const char *itemName, const char *itemText, const char *command, Panel *target, const KeyValues *userData = NULL ); virtual int AddCheckableMenuItem( const char *itemName, const wchar_t *wszItemText, const char *command, Panel *target, const KeyValues *userData = NULL ); virtual int AddCheckableMenuItem( const char *itemName, const char *itemText, KeyValues *message, Panel *target, const KeyValues *userData = NULL ); virtual int AddCheckableMenuItem( const char *itemName, const wchar_t *wszItemText, KeyValues *message, Panel *target, const KeyValues *userData = NULL ); virtual int AddCheckableMenuItem( const char *itemText, const char *command, Panel *target , const KeyValues *userData = NULL); virtual int AddCheckableMenuItem( const char *itemText, KeyValues *message, Panel *target, const KeyValues *userData = NULL ); virtual int AddCheckableMenuItem( const char *itemText, Panel *target, const KeyValues *userData = NULL ); // Add a cascading menu item to the menu virtual int AddCascadingMenuItem( const char *itemName, const char *itemText, const char *command, Panel *target, Menu *cascadeMenu, const KeyValues *userData = NULL ); virtual int AddCascadingMenuItem( const char *itemName, const wchar_t *wszItemText, const char *command, Panel *target, Menu *cascadeMenu, const KeyValues *userData = NULL ); virtual int AddCascadingMenuItem( const char *itemName, const char *itemText, KeyValues *message, Panel *target, Menu *cascadeMenu, const KeyValues *userData = NULL ); virtual int AddCascadingMenuItem( const char *itemName, const wchar_t *wszItemText, KeyValues *message, Panel *target, Menu *cascadeMenu, const KeyValues *userData = NULL ); virtual int AddCascadingMenuItem( const char *itemText, const char *command, Panel *target, Menu *cascadeMenu, const KeyValues *userData = NULL ); virtual int AddCascadingMenuItem( const char *itemText, KeyValues *message, Panel *target, Menu *cascadeMenu, const KeyValues *userData = NULL ); virtual int AddCascadingMenuItem( const char *itemText, Panel *target, Menu *cascadeMenu, const KeyValues *userData = NULL ); // Add a custom panel to the menu virtual int AddMenuItem( MenuItem *panel ); virtual void AddSeparator(); virtual void AddSeparatorAfterItem( int itemID ); // Sets the values of a menu item at the specified index virtual void UpdateMenuItem(int itemID, const char *itemText,KeyValues *message, const KeyValues *userData = NULL); virtual void UpdateMenuItem(int itemID, const wchar_t *wszItemText,KeyValues *message, const KeyValues *userData = NULL); virtual void MoveMenuItem( int itemID, int moveBeforeThisItemID ); virtual bool IsValidMenuID(int itemID); virtual int GetInvalidMenuID(); KeyValues *GetItemUserData(int itemID); void GetItemText(int itemID, wchar_t *text, int bufLenInBytes); void GetItemText(int itemID, char *text, int bufLenInBytes); virtual void SetItemEnabled(const char *itemName, bool state); virtual void SetItemEnabled(int itemID, bool state); virtual void SetItemVisible(const char *itemName, bool visible); virtual void SetItemVisible(int itemID, bool visible); // Remove a single item void DeleteItem( int itemID ); // Clear the menu, deleting all the menu items within void DeleteAllItems(); // Override the auto-width setting with a single fixed width virtual void SetFixedWidth( int width ); // Sets the content alignment of all items in the menu void SetContentAlignment( Label::Alignment alignment ); // sets the height of each menu item virtual void SetMenuItemHeight(int itemHeight); virtual int GetMenuItemHeight() const; // Set the max number of items visible (scrollbar appears with more) virtual void SetNumberOfVisibleItems( int numItems ); // Add the menu to the menu manager (see Menu::SetVisible())? void EnableUseMenuManager( bool bUseMenuManager ); // Set up the menu items layout virtual void PerformLayout( void ); virtual void SetBorder(class IBorder *border); virtual void ApplySchemeSettings(IScheme *pScheme); // Set type ahead behaviour enum MenuTypeAheadMode { COMPAT_MODE = 0, HOT_KEY_MODE, TYPE_AHEAD_MODE, }; virtual void SetTypeAheadMode(MenuTypeAheadMode mode); virtual int GetTypeAheadMode(); // Hotkey handling virtual void OnKeyTyped(wchar_t unichar); // Menu nagivation etc. virtual void OnKeyCodeTyped( KeyCode code ); // Visibility virtual void SetVisible(bool state); // Activates item in the menu list, as if that menu item had been selected by the user virtual void ActivateItem(int itemID); virtual void SilentActivateItem(int itemID); // activate item, but don't fire the action signal virtual void ActivateItemByRow(int row); virtual int GetActiveItem(); // returns the itemID (not the row) of the active item // Return the number of items currently in the menu list virtual int GetItemCount() const; // return the menuID of the n'th item in the menu list, valid from [0, GetItemCount) virtual int GetMenuID(int index); // Return the number of items currently visible in the menu list int GetCurrentlyVisibleItemsCount(); MenuItem *GetMenuItem(int itemID); void CloseOtherMenus(MenuItem *item); virtual void OnKillFocus(); int GetMenuMode(); enum MenuMode { MOUSE = 0, KEYBOARD, }; void SetCurrentlyHighlightedItem(int itemID); int GetCurrentlyHighlightedItem(); void ClearCurrentlyHighlightedItem(); // Set the checked state of a checkable menuItem void SetMenuItemChecked(int itemID, bool state); bool IsChecked(int index); // check if item is checked. void SetMinimumWidth(int width); int GetMinimumWidth(); // baseclass overrides to chain colors through to cascade menus virtual void SetFgColor( Color newColor ); virtual void SetBgColor( Color newColor ); virtual void SetFont( HFont font ); // Pass in NULL hotkey to remove hotkey void SetCurrentKeyBinding( int itemID, char const *hotkey ); void ForceCalculateWidth(); void SetUseFallbackFont( bool bState, HFont hFallback ); protected: // helper functions int AddMenuItemCharCommand(MenuItem *item, const char *command, Panel *target, const KeyValues *userData); int AddMenuItemKeyValuesCommand(MenuItem *item, KeyValues *message, Panel *target, const KeyValues *userData); // vgui result reporting virtual void OnCommand( const char *command ); MESSAGE_FUNC_PTR( OnMenuItemSelected, "MenuItemSelected", panel ); virtual void AddScrollBar(); virtual void RemoveScrollBar(); MESSAGE_FUNC( OnSliderMoved, "ScrollBarSliderMoved" ); virtual void Paint(); virtual void LayoutMenuBorder(); virtual void MakeItemsVisibleInScrollRange( int maxVisibleItems, int nNumPixelsAvailable ); virtual void OnMouseWheeled(int delta); // Alternate OnKeyTyped behaviors virtual void OnHotKey(wchar_t unichar); virtual void OnTypeAhead(wchar_t unichar); int CountVisibleItems(); void ComputeWorkspaceSize( int& workWide, int& workTall ); int ComputeFullMenuHeightWithInsets(); void CalculateWidth(); void LayoutScrollBar(); void PositionCascadingMenu(); void SizeMenuItems(); void OnCursorMoved(int x, int y); void OnKeyCodePressed(KeyCode code); void OnMenuClose(); MESSAGE_FUNC( OnKeyModeSet, "KeyModeSet" ); void SetCurrentlySelectedItem(MenuItem *item); void SetCurrentlySelectedItem(int itemID); MESSAGE_FUNC_INT( OnCursorEnteredMenuItem, "CursorEnteredMenuItem", VPanel); MESSAGE_FUNC_INT( OnCursorExitedMenuItem, "CursorExitedMenuItem", VPanel); void MoveAlongMenuItemList(int direction, int loopCount); enum { DEFAULT_MENU_ITEM_HEIGHT = 22, // height of items in the menu MENU_UP = -1, // used for moving up/down list of menu items in the menu MENU_DOWN = 1 }; #ifdef DBGFLAG_VALIDATE virtual void Validate( CValidator &validator, char *pchName ); #endif // DBGFLAG_VALIDATE private: MenuItem *GetParentMenuItem(); int m_iMenuItemHeight; int m_iFixedWidth; int m_iMinimumWidth; // a minimum width the menu has to be if it is not fixed width int m_iNumVisibleLines; // number of items in menu before scroll bar adds on ScrollBar *m_pScroller; CUtlLinkedList m_MenuItems; CUtlVector m_VisibleSortedItems; CUtlVector m_SortedItems; // used for visual CUtlVector m_Separators; // menu item ids after which separators should be shown CUtlVector m_SeparatorPanels; bool _sizedForScrollBar: 1 ; // whether menu has been sized for a scrollbar bool m_bUseFallbackFont : 1; bool _recalculateWidth : 1; bool m_bUseMenuManager : 1; int _menuWide; int m_iCurrentlySelectedItemID; int m_iInputMode; int m_iCheckImageWidth; // the size of the check box spot on a checkable menu. int m_iProportionalScrollBarSize; Label::Alignment m_Alignment; Color _borderDark; int m_iActivatedItem; HFont m_hItemFont; HFont m_hFallbackItemFont; // for managing type ahead #define TYPEAHEAD_BUFSIZE 256 MenuTypeAheadMode m_eTypeAheadMode; wchar_t m_szTypeAheadBuf[TYPEAHEAD_BUFSIZE]; int m_iNumTypeAheadChars; double m_fLastTypeAheadTime; }; //----------------------------------------------------------------------------- // Helper class to create menu //----------------------------------------------------------------------------- class MenuBuilder { public: MenuBuilder( Menu *pMenu, Panel *pActionTarget ); MenuItem* AddMenuItem( const char *pszButtonText, const char *pszCommand, const char *pszCategoryName ); MenuItem* AddMenuItem( const char *pszButtonText, KeyValues *kvUserData, const char *pszCategoryName ); MenuItem* AddCascadingMenuItem( const char *pszButtonText, Menu *pSubMenu, const char *pszCategoryName ); private: void AddSepratorIfNeeded( const char *pszCategoryName ); Menu *m_pMenu; Panel *m_pActionTarget; const char *m_pszLastCategory; }; } // namespace vgui #endif // MENU_H