Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

380 lines
15 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //===========================================================================//
  7. #ifndef MENU_H
  8. #define MENU_H
  9. #ifdef _WIN32
  10. #pragma once
  11. #endif
  12. #include <vgui_controls/Panel.h>
  13. #include <vgui_controls/Label.h>
  14. #include <utllinkedlist.h>
  15. #include <utlvector.h>
  16. namespace vgui
  17. {
  18. class MenuItem;
  19. class ScrollBar;
  20. class MenuSeparator;
  21. //-----------------------------------------------------------------------------
  22. // Purpose: A menu is a list of items that can be selected with one click, navigated
  23. // with arrow keys and/or hot keys, and have a lit behavior when mouse over.
  24. // It is NOT the button which opens the menu, but only the menu itself.
  25. //
  26. // Behaviour spec:
  27. // Menu navigation can be done in 2 modes, via keyboard keys and via mouse.
  28. // Clicking on menu button opens menu.
  29. // Only one item in a menu is highlighted at a time.
  30. // Only one submenu in a menu is open at a time.
  31. // Disabled menuitems get highlighted via mouse and keys but will not activate.
  32. //
  33. // Mouse:
  34. // Moving mouse into a menuitem highlights it.
  35. // If the menuitem has a cascading menu, the menu opens when the mouse enters
  36. // the menuitem. The cascading menuitem stays highlighted while its menu is open.
  37. // No submenu items are highlighted by default.
  38. // Moving the mouse into another menuitem closes any previously open submenus in the list.
  39. // Clicking once in the menu item activates the menu item and closes all menus.
  40. // Moving the mouse off a menuitem unhighlights it.
  41. // The scroll bar arrows can be used to move up/down the menu one item at a time.
  42. // The clicking and dragging on the scroll bar nob also scrolls the menu items.
  43. // If a highlighed menuitem scrolls off, and the user then begins navigating via keys,
  44. // the menu will snap the scroll bar so the highlighted item is visible.
  45. // If user has been navigating via keys, moving the mouse over a menu item
  46. // highlights it.
  47. // Mousewheel:
  48. // You must have the mouse inside the menu/scroll bar to use the wheel.
  49. // The mouse wheel moves the highlighted menuitem up or down the list.
  50. // If the list has no scroll bar the wheel will cycle from the bottom of the list
  51. // to the top of the list and vice versa.
  52. // If the list has a scrollbar the mouse wheel will stop at the top or bottom
  53. // of the list.
  54. // If the mouse is over the scroll bar no items are highlighted.
  55. // Keyboard:
  56. // When a menu is opened, no items are highlighted.
  57. // If a menuitem has a cascading menu it does not open when the item is highlighted.
  58. // The down arrow selects the next item in the list.
  59. // (first item if none are highlighted and there is a scrollbar).
  60. // The up arrow selects the previous item in the list
  61. // (first item if none are highlighted and there is a scrollbar, last item if none are
  62. // highlighted and there is no scrollbar).
  63. // Selecting a new menuitem closes any previously open submenus in the list.
  64. // The enter key activates the selected item and closes all menus.
  65. // If the selected item has a cascading menu, activating it opens its submenu.
  66. // These may also be activated by pressing the right arrow.
  67. // Pressing the left arrow closes the submenu.
  68. // When the submenu is opened the cascading menuitem stays highlighted.
  69. // No items in the submenu are highlighted when it is opened.
  70. //
  71. // Note: Cascading menuitems in menus with a scrollbar is not supported.
  72. // Its a clunky UI and if we want this we should design a better solution,
  73. // perhaps along the lines of how explorer's bookmarks does it.
  74. // It currently functions, but there are some arm/disarm bugs.
  75. //
  76. //
  77. //-----------------------------------------------------------------------------
  78. class Menu : public Panel
  79. {
  80. DECLARE_CLASS_SIMPLE( Menu, Panel );
  81. friend class MenuItem;
  82. public:
  83. enum MenuDirection_e
  84. {
  85. LEFT,
  86. RIGHT,
  87. UP,
  88. DOWN,
  89. CURSOR, // make the menu appear under the mouse cursor
  90. ALIGN_WITH_PARENT, // make the menu appear under the parent
  91. };
  92. Menu(Panel *parent, const char *panelName);
  93. ~Menu();
  94. static void PlaceContextMenu( Panel *parent, Menu *menu );
  95. static void OnInternalMousePressed( Panel *other, MouseCode code );
  96. virtual void PositionRelativeToPanel( Panel *reference, MenuDirection_e direction, int nAdditionalYOffset = 0, bool showMenu = false );
  97. // the menu. For combo boxes, it's the edit/field, etc. etc.
  98. // Add a simple text item to the menu
  99. virtual int AddMenuItem( const char *itemName, const char *itemText, const char *command, Panel *target, const KeyValues *userData = NULL );
  100. virtual int AddMenuItem( const char *itemName, const wchar_t *wszItemText, const char *command, Panel *target, const KeyValues *userData = NULL );
  101. virtual int AddMenuItem( const char *itemName, const char *itemText, KeyValues *message, Panel *target , const KeyValues *userData = NULL);
  102. virtual int AddMenuItem( const char *itemName, const wchar_t *wszItemText, KeyValues *message, Panel *target , const KeyValues *userData = NULL);
  103. virtual int AddMenuItem( const char *itemText, const char *command, Panel *target , const KeyValues *userData = NULL);
  104. virtual int AddMenuItem( const char *itemText, KeyValues *message, Panel *target, const KeyValues *userData = NULL );
  105. virtual int AddMenuItem( const char *itemText, Panel *target, const KeyValues *userData = NULL );
  106. // Add a checkable item to the menu
  107. virtual int AddCheckableMenuItem( const char *itemName, const char *itemText, const char *command, Panel *target, const KeyValues *userData = NULL );
  108. virtual int AddCheckableMenuItem( const char *itemName, const wchar_t *wszItemText, const char *command, Panel *target, const KeyValues *userData = NULL );
  109. virtual int AddCheckableMenuItem( const char *itemName, const char *itemText, KeyValues *message, Panel *target, const KeyValues *userData = NULL );
  110. virtual int AddCheckableMenuItem( const char *itemName, const wchar_t *wszItemText, KeyValues *message, Panel *target, const KeyValues *userData = NULL );
  111. virtual int AddCheckableMenuItem( const char *itemText, const char *command, Panel *target , const KeyValues *userData = NULL);
  112. virtual int AddCheckableMenuItem( const char *itemText, KeyValues *message, Panel *target, const KeyValues *userData = NULL );
  113. virtual int AddCheckableMenuItem( const char *itemText, Panel *target, const KeyValues *userData = NULL );
  114. // Add a cascading menu item to the menu
  115. virtual int AddCascadingMenuItem( const char *itemName, const char *itemText, const char *command, Panel *target, Menu *cascadeMenu, const KeyValues *userData = NULL );
  116. virtual int AddCascadingMenuItem( const char *itemName, const wchar_t *wszItemText, const char *command, Panel *target, Menu *cascadeMenu, const KeyValues *userData = NULL );
  117. virtual int AddCascadingMenuItem( const char *itemName, const char *itemText, KeyValues *message, Panel *target, Menu *cascadeMenu, const KeyValues *userData = NULL );
  118. virtual int AddCascadingMenuItem( const char *itemName, const wchar_t *wszItemText, KeyValues *message, Panel *target, Menu *cascadeMenu, const KeyValues *userData = NULL );
  119. virtual int AddCascadingMenuItem( const char *itemText, const char *command, Panel *target, Menu *cascadeMenu, const KeyValues *userData = NULL );
  120. virtual int AddCascadingMenuItem( const char *itemText, KeyValues *message, Panel *target, Menu *cascadeMenu, const KeyValues *userData = NULL );
  121. virtual int AddCascadingMenuItem( const char *itemText, Panel *target, Menu *cascadeMenu, const KeyValues *userData = NULL );
  122. // Add a custom panel to the menu
  123. virtual int AddMenuItem( MenuItem *panel );
  124. virtual void AddSeparator();
  125. virtual void AddSeparatorAfterItem( int itemID );
  126. // Sets the values of a menu item at the specified index
  127. virtual void UpdateMenuItem(int itemID, const char *itemText,KeyValues *message, const KeyValues *userData = NULL);
  128. virtual void UpdateMenuItem(int itemID, const wchar_t *wszItemText,KeyValues *message, const KeyValues *userData = NULL);
  129. virtual void MoveMenuItem( int itemID, int moveBeforeThisItemID );
  130. virtual bool IsValidMenuID(int itemID);
  131. virtual int GetInvalidMenuID();
  132. KeyValues *GetItemUserData(int itemID);
  133. void GetItemText(int itemID, wchar_t *text, int bufLenInBytes);
  134. void GetItemText(int itemID, char *text, int bufLenInBytes);
  135. virtual void SetItemEnabled(const char *itemName, bool state);
  136. virtual void SetItemEnabled(int itemID, bool state);
  137. virtual void SetItemVisible(const char *itemName, bool visible);
  138. virtual void SetItemVisible(int itemID, bool visible);
  139. // Remove a single item
  140. void DeleteItem( int itemID );
  141. // Clear the menu, deleting all the menu items within
  142. void DeleteAllItems();
  143. // Override the auto-width setting with a single fixed width
  144. virtual void SetFixedWidth( int width );
  145. // Sets the content alignment of all items in the menu
  146. void SetContentAlignment( Label::Alignment alignment );
  147. // sets the height of each menu item
  148. virtual void SetMenuItemHeight(int itemHeight);
  149. virtual int GetMenuItemHeight() const;
  150. // Set the max number of items visible (scrollbar appears with more)
  151. virtual void SetNumberOfVisibleItems( int numItems );
  152. // Add the menu to the menu manager (see Menu::SetVisible())?
  153. void EnableUseMenuManager( bool bUseMenuManager );
  154. // Set up the menu items layout
  155. virtual void PerformLayout( void );
  156. virtual void SetBorder(class IBorder *border);
  157. virtual void ApplySchemeSettings(IScheme *pScheme);
  158. // Set type ahead behaviour
  159. enum MenuTypeAheadMode
  160. {
  161. COMPAT_MODE = 0,
  162. HOT_KEY_MODE,
  163. TYPE_AHEAD_MODE,
  164. };
  165. virtual void SetTypeAheadMode(MenuTypeAheadMode mode);
  166. virtual int GetTypeAheadMode();
  167. // Hotkey handling
  168. virtual void OnKeyTyped(wchar_t unichar);
  169. // Menu nagivation etc.
  170. virtual void OnKeyCodeTyped( KeyCode code );
  171. // Visibility
  172. virtual void SetVisible(bool state);
  173. // Activates item in the menu list, as if that menu item had been selected by the user
  174. virtual void ActivateItem(int itemID);
  175. virtual void SilentActivateItem(int itemID); // activate item, but don't fire the action signal
  176. virtual void ActivateItemByRow(int row);
  177. virtual int GetActiveItem(); // returns the itemID (not the row) of the active item
  178. // Return the number of items currently in the menu list
  179. virtual int GetItemCount() const;
  180. // return the menuID of the n'th item in the menu list, valid from [0, GetItemCount)
  181. virtual int GetMenuID(int index);
  182. // Return the number of items currently visible in the menu list
  183. int GetCurrentlyVisibleItemsCount();
  184. MenuItem *GetMenuItem(int itemID);
  185. void CloseOtherMenus(MenuItem *item);
  186. virtual void OnKillFocus();
  187. int GetMenuMode();
  188. enum MenuMode
  189. {
  190. MOUSE = 0,
  191. KEYBOARD,
  192. };
  193. void SetCurrentlyHighlightedItem(int itemID);
  194. int GetCurrentlyHighlightedItem();
  195. void ClearCurrentlyHighlightedItem();
  196. // Set the checked state of a checkable menuItem
  197. void SetMenuItemChecked(int itemID, bool state);
  198. bool IsChecked(int index); // check if item is checked.
  199. void SetMinimumWidth(int width);
  200. int GetMinimumWidth();
  201. // baseclass overrides to chain colors through to cascade menus
  202. virtual void SetFgColor( Color newColor );
  203. virtual void SetBgColor( Color newColor );
  204. virtual void SetFont( HFont font );
  205. // Pass in NULL hotkey to remove hotkey
  206. void SetCurrentKeyBinding( int itemID, char const *hotkey );
  207. void ForceCalculateWidth();
  208. void SetUseFallbackFont( bool bState, HFont hFallback );
  209. protected:
  210. // helper functions
  211. int AddMenuItemCharCommand(MenuItem *item, const char *command, Panel *target, const KeyValues *userData);
  212. int AddMenuItemKeyValuesCommand(MenuItem *item, KeyValues *message, Panel *target, const KeyValues *userData);
  213. // vgui result reporting
  214. virtual void OnCommand( const char *command );
  215. MESSAGE_FUNC_PTR( OnMenuItemSelected, "MenuItemSelected", panel );
  216. virtual void AddScrollBar();
  217. virtual void RemoveScrollBar();
  218. MESSAGE_FUNC( OnSliderMoved, "ScrollBarSliderMoved" );
  219. virtual void Paint();
  220. virtual void LayoutMenuBorder();
  221. virtual void MakeItemsVisibleInScrollRange( int maxVisibleItems, int nNumPixelsAvailable );
  222. virtual void OnMouseWheeled(int delta);
  223. // Alternate OnKeyTyped behaviors
  224. virtual void OnHotKey(wchar_t unichar);
  225. virtual void OnTypeAhead(wchar_t unichar);
  226. int CountVisibleItems();
  227. void ComputeWorkspaceSize( int& workWide, int& workTall );
  228. int ComputeFullMenuHeightWithInsets();
  229. void CalculateWidth();
  230. void LayoutScrollBar();
  231. void PositionCascadingMenu();
  232. void SizeMenuItems();
  233. void OnCursorMoved(int x, int y);
  234. void OnKeyCodePressed(KeyCode code);
  235. void OnMenuClose();
  236. MESSAGE_FUNC( OnKeyModeSet, "KeyModeSet" );
  237. void SetCurrentlySelectedItem(MenuItem *item);
  238. void SetCurrentlySelectedItem(int itemID);
  239. MESSAGE_FUNC_INT( OnCursorEnteredMenuItem, "CursorEnteredMenuItem", VPanel);
  240. MESSAGE_FUNC_INT( OnCursorExitedMenuItem, "CursorExitedMenuItem", VPanel);
  241. void MoveAlongMenuItemList(int direction, int loopCount);
  242. enum
  243. {
  244. DEFAULT_MENU_ITEM_HEIGHT = 22, // height of items in the menu
  245. MENU_UP = -1, // used for moving up/down list of menu items in the menu
  246. MENU_DOWN = 1
  247. };
  248. #ifdef DBGFLAG_VALIDATE
  249. virtual void Validate( CValidator &validator, char *pchName );
  250. #endif // DBGFLAG_VALIDATE
  251. private:
  252. MenuItem *GetParentMenuItem();
  253. int m_iMenuItemHeight;
  254. int m_iFixedWidth;
  255. int m_iMinimumWidth; // a minimum width the menu has to be if it is not fixed width
  256. int m_iNumVisibleLines; // number of items in menu before scroll bar adds on
  257. ScrollBar *m_pScroller;
  258. CUtlLinkedList<MenuItem*, int> m_MenuItems;
  259. CUtlVector<int> m_VisibleSortedItems;
  260. CUtlVector<int> m_SortedItems; // used for visual
  261. CUtlVector<int> m_Separators; // menu item ids after which separators should be shown
  262. CUtlVector<MenuSeparator *> m_SeparatorPanels;
  263. bool _sizedForScrollBar: 1 ; // whether menu has been sized for a scrollbar
  264. bool m_bUseFallbackFont : 1;
  265. bool _recalculateWidth : 1;
  266. bool m_bUseMenuManager : 1;
  267. int _menuWide;
  268. int m_iCurrentlySelectedItemID;
  269. int m_iInputMode;
  270. int m_iCheckImageWidth; // the size of the check box spot on a checkable menu.
  271. int m_iProportionalScrollBarSize;
  272. Label::Alignment m_Alignment;
  273. Color _borderDark;
  274. int m_iActivatedItem;
  275. HFont m_hItemFont;
  276. HFont m_hFallbackItemFont;
  277. // for managing type ahead
  278. #define TYPEAHEAD_BUFSIZE 256
  279. MenuTypeAheadMode m_eTypeAheadMode;
  280. wchar_t m_szTypeAheadBuf[TYPEAHEAD_BUFSIZE];
  281. int m_iNumTypeAheadChars;
  282. double m_fLastTypeAheadTime;
  283. };
  284. //-----------------------------------------------------------------------------
  285. // Helper class to create menu
  286. //-----------------------------------------------------------------------------
  287. class MenuBuilder
  288. {
  289. public:
  290. MenuBuilder( Menu *pMenu, Panel *pActionTarget );
  291. MenuItem* AddMenuItem( const char *pszButtonText, const char *pszCommand, const char *pszCategoryName );
  292. MenuItem* AddMenuItem( const char *pszButtonText, KeyValues *kvUserData, const char *pszCategoryName );
  293. MenuItem* AddCascadingMenuItem( const char *pszButtonText, Menu *pSubMenu, const char *pszCategoryName );
  294. private:
  295. void AddSepratorIfNeeded( const char *pszCategoryName );
  296. Menu *m_pMenu;
  297. Panel *m_pActionTarget;
  298. const char *m_pszLastCategory;
  299. };
  300. } // namespace vgui
  301. #endif // MENU_H