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
380 lines
15 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
//===========================================================================// |
|
|
|
#ifndef MENU_H |
|
#define MENU_H |
|
|
|
#ifdef _WIN32 |
|
#pragma once |
|
#endif |
|
|
|
#include <vgui_controls/Panel.h> |
|
#include <vgui_controls/Label.h> |
|
#include <utllinkedlist.h> |
|
#include <utlvector.h> |
|
|
|
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_HANDLE( OnCursorEnteredMenuItem, "CursorEnteredMenuItem", menuItem); |
|
MESSAGE_FUNC_HANDLE( OnCursorExitedMenuItem, "CursorExitedMenuItem", menuItem); |
|
|
|
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<MenuItem*, int> m_MenuItems; |
|
|
|
CUtlVector<int> m_VisibleSortedItems; |
|
CUtlVector<int> m_SortedItems; // used for visual |
|
CUtlVector<int> m_Separators; // menu item ids after which separators should be shown |
|
CUtlVector<MenuSeparator *> 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
|
|
|