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.

360 lines
7.6 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //===========================================================================//
  7. #include "cbase.h"
  8. #include <cdll_client_int.h>
  9. #include <cdll_util.h>
  10. #include <globalvars_base.h>
  11. #include <icvar.h>
  12. #include <filesystem.h>
  13. #include "commandmenu.h"
  14. #include "vgui_controls/MenuItem.h"
  15. // memdbgon must be the last include file in a .cpp file!!!
  16. #include "tier0/memdbgon.h"
  17. CommandMenu::CommandMenu( Panel *parent, const char *panelName, IViewPort * viewport) : Menu( parent, panelName )
  18. {
  19. if ( !viewport )
  20. return;
  21. m_ViewPort = viewport;
  22. SetVisible( false );
  23. m_CurrentMenu = this;
  24. m_MenuKeys = NULL;
  25. }
  26. bool CommandMenu::LoadFromFile( const char * fileName) // load menu from KeyValues
  27. {
  28. KeyValues * kv = new KeyValues(fileName);
  29. if ( !kv->LoadFromFile( g_pFullFileSystem, fileName, "GAME" ) )
  30. return false;
  31. bool ret = LoadFromKeyValues( kv );
  32. kv->deleteThis();
  33. return ret;
  34. }
  35. CommandMenu::~CommandMenu()
  36. {
  37. ClearMenu();
  38. }
  39. void CommandMenu::OnMessage(const KeyValues *params, VPANEL fromPanel)
  40. {
  41. char text[255];
  42. bool bHandled = false;
  43. KeyValues *param1 = const_cast<KeyValues *>(params);
  44. // toggle attached cvar, if any
  45. Q_strncpy( text, param1->GetString("toggle"), sizeof( text ) );
  46. if ( text[0] )
  47. {
  48. ConVarRef convar( text );
  49. if ( convar.IsValid() )
  50. {
  51. // toggle cvar
  52. if ( convar.GetInt() )
  53. {
  54. convar.SetValue( 0 );
  55. }
  56. else
  57. {
  58. convar.SetValue( 1 );
  59. }
  60. UpdateMenu();
  61. }
  62. else
  63. {
  64. Msg("CommandComboBox::OnMessage: cvar %s not found.\n", param1->GetString("typedata") );
  65. }
  66. bHandled = true;
  67. }
  68. // execute attached command, if any
  69. Q_strncpy( text, param1->GetString("command"), sizeof( text ) );
  70. if ( text[0] )
  71. {
  72. engine->ClientCmd( text );
  73. bHandled = true;
  74. }
  75. // fire custom message, if any
  76. Q_strncpy( text, param1->GetString("custom"), sizeof( text ) );
  77. if ( text[0] )
  78. {
  79. OnCustomItem( param1 ); // let derived class decide what to do
  80. bHandled = true;
  81. }
  82. if ( bHandled )
  83. {
  84. PostMessage( GetParent(), new KeyValues("CommandMenuClosed") );
  85. }
  86. BaseClass::OnMessage( params, fromPanel );
  87. }
  88. void CommandMenu::StartNewSubMenu(KeyValues * params)
  89. {
  90. CommandMenuItem menuitem;
  91. menuitem.menu = m_CurrentMenu;
  92. Menu * menu = new Menu( this, params->GetString("name") ); // create new menu
  93. menuitem.itemnr = m_CurrentMenu->AddCascadingMenuItem( params->GetString("label"), this, menu, params ); // add to current menu as item
  94. m_MenuItems.AddToTail( menuitem ); // add to global list
  95. m_pMenuStack.Push( m_CurrentMenu ); // remember current menu
  96. m_CurrentMenu = menu; // continue adding items in new menu
  97. }
  98. void CommandMenu::FinishSubMenu()
  99. {
  100. m_CurrentMenu = m_pMenuStack.Top(); // get menu one level above
  101. m_pMenuStack.Pop(); // remove it from stack
  102. }
  103. void CommandMenu::AddMenuCommandItem(KeyValues * params)
  104. {
  105. CommandMenuItem menuitem; // create new menuItem
  106. menuitem.menu = m_CurrentMenu; // save the current menu context
  107. menuitem.itemnr = m_CurrentMenu->AddMenuItem( params->GetString("label"), params->MakeCopy(), this, params ); // add it
  108. m_MenuItems.AddToTail( menuitem ); // add to global list
  109. }
  110. void CommandMenu::AddMenuToggleItem(KeyValues * params)
  111. {
  112. CommandMenuItem menuitem; // create new menuItem
  113. menuitem.menu = m_CurrentMenu; // save the current menu context
  114. menuitem.itemnr = m_CurrentMenu->AddCheckableMenuItem( params->GetString("label"), params->MakeCopy(), this, params ); // add it
  115. m_MenuItems.AddToTail( menuitem ); // add to global list
  116. }
  117. void CommandMenu::AddMenuCustomItem(KeyValues * params)
  118. {
  119. CommandMenuItem menuitem; // create new menuItem
  120. menuitem.menu = m_CurrentMenu; // save the current menu context
  121. menuitem.itemnr = AddCustomItem( params, m_CurrentMenu );
  122. m_MenuItems.AddToTail( menuitem ); // add to global list
  123. }
  124. void CommandMenu::ClearMenu()
  125. {
  126. SetVisible( false );
  127. m_pMenuStack.Clear();
  128. m_MenuItems.RemoveAll();
  129. // DeleteAllItems();
  130. MarkForDeletion();
  131. if ( m_MenuKeys )
  132. {
  133. m_MenuKeys->deleteThis();
  134. m_MenuKeys = NULL;
  135. }
  136. }
  137. void CommandMenu::RebuildMenu()
  138. {
  139. if ( !m_MenuKeys )
  140. return;
  141. m_pMenuStack.Clear();
  142. m_MenuItems.RemoveAll();
  143. DeleteAllItems();
  144. LoadFromKeyValues( m_MenuKeys ); // and reload respecting new team, mapname etc.
  145. }
  146. void CommandMenu::UpdateMenu()
  147. {
  148. char text[255];
  149. int num = m_MenuItems.Count();
  150. for (int i=0; i < num; i++)
  151. {
  152. CommandMenuItem menuitem = m_MenuItems.Element(i);
  153. KeyValues * keys = menuitem.menu->GetItemUserData( menuitem.itemnr );
  154. if ( !keys )
  155. continue;
  156. // let custom menu items update themself
  157. Q_strncpy( text, keys->GetString("custom"), sizeof(text) );
  158. if ( text[0] )
  159. {
  160. // let derived class modify the menu item
  161. UpdateCustomItem( keys, menuitem.menu->GetMenuItem(menuitem.itemnr) );
  162. continue;
  163. }
  164. // update toggle buttons
  165. Q_strncpy( text, keys->GetString("toggle"), sizeof(text) );
  166. if ( text[0] )
  167. {
  168. // set toggle state equal to cvar state
  169. ConVarRef convar( text );
  170. if ( convar.IsValid() )
  171. {
  172. menuitem.menu->SetMenuItemChecked( menuitem.itemnr, convar.GetBool() );
  173. }
  174. }
  175. }
  176. }
  177. void CommandMenu::SetVisible(bool state)
  178. {
  179. if ( state && !IsVisible() )
  180. {
  181. UpdateMenu();
  182. }
  183. BaseClass::SetVisible( state );
  184. }
  185. bool CommandMenu::CheckRules(const char *rule, const char *ruledata)
  186. {
  187. if ( !rule || !ruledata )
  188. {
  189. return true; // no rule defined, show item
  190. }
  191. if ( Q_strcmp( rule, "team") == 0 )
  192. {
  193. // if team is same as specified in rule, show item
  194. return ( Q_strcmp( m_CurrentTeam, ruledata ) == 0 );
  195. }
  196. else if ( Q_strcmp( rule, "map") == 0 )
  197. {
  198. // if team is same as specified in rule, show item
  199. return ( Q_strcmp( m_CurrentMap, ruledata ) == 0 );
  200. }
  201. return true;
  202. }
  203. KeyValues * CommandMenu::GetKeyValues()
  204. {
  205. return m_MenuKeys;
  206. }
  207. bool CommandMenu::LoadFromKeyValues( KeyValues * params )
  208. {
  209. if ( !params )
  210. return false;
  211. Q_snprintf( m_CurrentTeam, 4, "%i", GetLocalPlayerTeam() );
  212. Q_FileBase( engine->GetLevelName(), m_CurrentMap, sizeof(m_CurrentMap) );
  213. if ( params != m_MenuKeys )
  214. {
  215. if ( m_MenuKeys )
  216. m_MenuKeys->deleteThis();
  217. m_MenuKeys = params->MakeCopy(); // save keyvalues
  218. }
  219. // iterate through all menu items
  220. KeyValues * subkey = m_MenuKeys->GetFirstSubKey();
  221. while ( subkey )
  222. {
  223. if ( subkey->GetDataType() == KeyValues::TYPE_NONE )
  224. {
  225. if ( !LoadFromKeyValuesInternal( subkey, 0 ) ) // recursive call
  226. return false;
  227. }
  228. subkey = subkey->GetNextKey();
  229. }
  230. UpdateMenu();
  231. return true;
  232. }
  233. bool CommandMenu::LoadFromKeyValuesInternal(KeyValues * key, int depth)
  234. {
  235. char text[255];
  236. KeyValues * subkey = NULL;
  237. if ( depth > 100 )
  238. {
  239. Msg("CommandMenu::LoadFromKeyValueInternal: depth > 100.\n");
  240. return false;
  241. }
  242. Q_strncpy( text, key->GetString("custom"), sizeof(text) ); // get type
  243. if ( text[0] )
  244. {
  245. AddMenuCustomItem( key ); // do whatever custom item wants to
  246. return true;
  247. }
  248. if ( !CheckRules( key->GetString("rule"), key->GetString("ruledata") ) )
  249. {
  250. return true;
  251. }
  252. // rules OK add subkey
  253. Q_strncpy( text, key->GetString("toggle"), sizeof(text) ); // get type
  254. if ( text[0] )
  255. {
  256. AddMenuToggleItem( key );
  257. return true;
  258. }
  259. Q_strncpy( text, key->GetString("command"), sizeof(text) ); // get type
  260. if ( text[0] )
  261. {
  262. AddMenuCommandItem( key );
  263. return true;
  264. }
  265. // not a command, nor a toggle. Must be a submenu:
  266. StartNewSubMenu( key ); // create submenu
  267. // iterate through all subkeys
  268. subkey = key->GetFirstSubKey();
  269. while ( subkey )
  270. {
  271. if ( subkey->GetDataType() == KeyValues::TYPE_NONE )
  272. {
  273. LoadFromKeyValuesInternal( subkey, depth+1 ); // recursive call
  274. }
  275. subkey = subkey->GetNextKey();
  276. }
  277. FinishSubMenu(); // go one level back
  278. return true;
  279. }