//========= 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(ButtonCode_t 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(ButtonCode_t 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 *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