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.

355 lines
8.0 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "vgui_controls/KeyBindingHelpDialog.h"
  7. #include "vgui_controls/ListPanel.h"
  8. #include "vgui/ISurface.h"
  9. #include "vgui/IVGui.h"
  10. #include "vgui/ILocalize.h"
  11. #include "vgui/IInput.h"
  12. #include "vgui/ISystem.h"
  13. #include "KeyValues.h"
  14. #include "vgui/Cursor.h"
  15. #include "tier1/utldict.h"
  16. #include "vgui_controls/KeyBoardEditorDialog.h"
  17. // NOTE: This has to be the last file included!
  18. #include "tier0/memdbgon.h"
  19. using namespace vgui;
  20. // If the user holds the key bound to help down for this long, then the dialog will stay on automatically
  21. #define KB_HELP_CONTINUE_SHOWING_TIME 1.0
  22. static bool BindingLessFunc( KeyValues * const & lhs, KeyValues * const &rhs )
  23. {
  24. KeyValues *p1, *p2;
  25. p1 = const_cast< KeyValues * >( lhs );
  26. p2 = const_cast< KeyValues * >( rhs );
  27. return ( Q_stricmp( p1->GetString( "Action" ), p2->GetString( "Action" ) ) < 0 ) ? true : false;
  28. }
  29. CKeyBindingHelpDialog::CKeyBindingHelpDialog( Panel *parent, Panel *panelToView, KeyBindingContextHandle_t handle, KeyCode code, int modifiers )
  30. : BaseClass( parent, "KeyBindingHelpDialog" ),
  31. m_Handle( handle ),
  32. m_KeyCode( code ),
  33. m_Modifiers( modifiers ),
  34. m_bPermanent( false )
  35. {
  36. Assert( panelToView );
  37. m_hPanel = panelToView;
  38. m_pList = new ListPanel( this, "KeyBindings" );
  39. m_pList->SetIgnoreDoubleClick( true );
  40. m_pList->AddColumnHeader(0, "Action", "#KBEditorBindingName", 175, 0);
  41. m_pList->AddColumnHeader(1, "Binding", "#KBEditorBinding", 175, 0);
  42. m_pList->AddColumnHeader(2, "Description", "#KBEditorDescription", 300, 0);
  43. LoadControlSettings( "resource/KeyBindingHelpDialog.res" );
  44. if ( panelToView && panelToView->GetName() && panelToView->GetName()[0] )
  45. {
  46. SetTitle( panelToView->GetName(), true );
  47. }
  48. else
  49. {
  50. SetTitle( "#KBHelpDialogTitle", true );
  51. }
  52. SetSmallCaption( true );
  53. SetMinimumSize( 400, 400 );
  54. SetMinimizeButtonVisible( false );
  55. SetMaximizeButtonVisible( false );
  56. SetSizeable( true );
  57. SetMoveable( true );
  58. SetMenuButtonVisible( false );
  59. SetVisible( true );
  60. MoveToCenterOfScreen();
  61. PopulateList();
  62. m_flShowTime = system()->GetCurrentTime();
  63. ivgui()->AddTickSignal( GetVPanel(), 0 );
  64. input()->SetAppModalSurface( GetVPanel() );
  65. }
  66. CKeyBindingHelpDialog::~CKeyBindingHelpDialog()
  67. {
  68. if ( input()->GetAppModalSurface() == GetVPanel() )
  69. {
  70. input()->SetAppModalSurface( 0 );
  71. }
  72. }
  73. void CKeyBindingHelpDialog::OnTick()
  74. {
  75. BaseClass::OnTick();
  76. bool keyStillDown = IsHelpKeyStillBeingHeld();
  77. double curtime = system()->GetCurrentTime();
  78. double elapsed = curtime - m_flShowTime;
  79. // After a second of holding the key, releasing the key will close the dialog
  80. if ( elapsed > KB_HELP_CONTINUE_SHOWING_TIME )
  81. {
  82. if ( !keyStillDown )
  83. {
  84. MarkForDeletion();
  85. return;
  86. }
  87. }
  88. // Otherwise, if they tapped the key within a second and now have released...
  89. else if ( !keyStillDown )
  90. {
  91. // Continue showing dialog indefinitely
  92. ivgui()->RemoveTickSignal( GetVPanel() );
  93. m_bPermanent = true;
  94. }
  95. }
  96. // The key originally bound to help was pressed
  97. void CKeyBindingHelpDialog::HelpKeyPressed()
  98. {
  99. // Don't kill while editor is being shown...
  100. if ( m_hKeyBindingsEditor.Get() )
  101. return;
  102. if ( m_bPermanent )
  103. {
  104. MarkForDeletion();
  105. }
  106. }
  107. bool CKeyBindingHelpDialog::IsHelpKeyStillBeingHeld()
  108. {
  109. bool keyDown = input()->IsKeyDown( m_KeyCode );
  110. if ( !keyDown )
  111. return false;
  112. bool shift = (input()->IsKeyDown(KEY_LSHIFT) || input()->IsKeyDown(KEY_RSHIFT));
  113. bool ctrl = (input()->IsKeyDown(KEY_LCONTROL) || input()->IsKeyDown(KEY_RCONTROL));
  114. bool alt = (input()->IsKeyDown(KEY_LALT) || input()->IsKeyDown(KEY_RALT));
  115. int modifiers = 0;
  116. if ( shift )
  117. {
  118. modifiers |= MODIFIER_SHIFT;
  119. }
  120. if ( ctrl )
  121. {
  122. modifiers |= MODIFIER_CONTROL;
  123. }
  124. if ( alt )
  125. {
  126. modifiers |= MODIFIER_ALT;
  127. }
  128. if ( modifiers != m_Modifiers )
  129. {
  130. return false;
  131. }
  132. return true;
  133. }
  134. void CKeyBindingHelpDialog::OnCommand( char const *cmd )
  135. {
  136. if ( !Q_stricmp( cmd, "OK" ) ||
  137. !Q_stricmp( cmd, "cancel" ) ||
  138. !Q_stricmp( cmd, "Close" ) )
  139. {
  140. MarkForDeletion();
  141. }
  142. else if ( !Q_stricmp( cmd, "edit" ) )
  143. {
  144. // Show the keybindings edit dialog
  145. if ( m_hKeyBindingsEditor.Get() )
  146. {
  147. delete m_hKeyBindingsEditor.Get();
  148. }
  149. // Don't delete panel if H key is released...
  150. m_hKeyBindingsEditor = new CKeyBoardEditorDialog( this, m_hPanel, m_Handle );
  151. m_hKeyBindingsEditor->DoModal();
  152. ivgui()->RemoveTickSignal( GetVPanel() );
  153. m_bPermanent = true;
  154. }
  155. else
  156. {
  157. BaseClass::OnCommand( cmd );
  158. }
  159. }
  160. void CKeyBindingHelpDialog::OnKeyCodeTyped(vgui::KeyCode code)
  161. {
  162. BaseClass::OnKeyCodeTyped( code );
  163. }
  164. void CKeyBindingHelpDialog::GetMappingList( Panel *panel, CUtlVector< PanelKeyBindingMap * >& maps )
  165. {
  166. PanelKeyBindingMap *map = panel->GetKBMap();
  167. while ( map )
  168. {
  169. maps.AddToTail( map );
  170. map = map->baseMap;
  171. }
  172. }
  173. void CKeyBindingHelpDialog::AnsiText( char const *token, char *out, size_t buflen )
  174. {
  175. out[ 0 ] = 0;
  176. wchar_t *str = g_pVGuiLocalize->Find( token );
  177. if ( !str )
  178. {
  179. Q_strncpy( out, token, buflen );
  180. }
  181. else
  182. {
  183. g_pVGuiLocalize->ConvertUnicodeToANSI( str, out, buflen );
  184. }
  185. }
  186. struct ListInfo_t
  187. {
  188. PanelKeyBindingMap *m_pMap;
  189. Panel *m_pPanel;
  190. };
  191. void CKeyBindingHelpDialog::PopulateList()
  192. {
  193. m_pList->DeleteAllItems();
  194. int i, j;
  195. CUtlVector< ListInfo_t > maps;
  196. vgui::Panel *pPanel = m_hPanel;
  197. while ( pPanel->IsKeyBindingChainToParentAllowed() )
  198. {
  199. PanelKeyBindingMap *map = pPanel->GetKBMap();
  200. while ( map )
  201. {
  202. int k;
  203. int c = maps.Count();
  204. for ( k = 0; k < c; ++k )
  205. {
  206. if ( maps[k].m_pMap == map )
  207. break;
  208. }
  209. if ( k == c )
  210. {
  211. int iMap = maps.AddToTail( );
  212. maps[iMap].m_pMap = map;
  213. maps[iMap].m_pPanel = pPanel;
  214. }
  215. map = map->baseMap;
  216. }
  217. pPanel = pPanel->GetParent();
  218. if ( !pPanel )
  219. break;
  220. }
  221. CUtlRBTree< KeyValues *, int > sorted( 0, 0, BindingLessFunc );
  222. // add header item
  223. int c = maps.Count();
  224. for ( i = 0; i < c; ++i )
  225. {
  226. PanelKeyBindingMap *m = maps[ i ].m_pMap;
  227. pPanel = maps[i].m_pPanel;
  228. Assert( m );
  229. int bindings = m->boundkeys.Count();
  230. for ( j = 0; j < bindings; ++j )
  231. {
  232. BoundKey_t *kbMap = &m->boundkeys[ j ];
  233. Assert( kbMap );
  234. // Create a new: blank item
  235. KeyValues *item = new KeyValues( "Item" );
  236. // Fill in data
  237. char loc[ 128 ];
  238. Q_snprintf( loc, sizeof( loc ), "#%s", kbMap->bindingname );
  239. char ansi[ 256 ];
  240. AnsiText( loc, ansi, sizeof( ansi ) );
  241. item->SetString( "Action", ansi );
  242. item->SetWString( "Binding", Panel::KeyCodeModifiersToDisplayString( (KeyCode)kbMap->keycode, kbMap->modifiers ) );
  243. // Find the binding
  244. KeyBindingMap_t *bindingMap = pPanel->LookupBinding( kbMap->bindingname );
  245. if ( bindingMap &&
  246. bindingMap->helpstring )
  247. {
  248. AnsiText( bindingMap->helpstring, ansi, sizeof( ansi ) );
  249. item->SetString( "Description", ansi );
  250. }
  251. item->SetPtr( "Item", kbMap );
  252. sorted.Insert( item );
  253. }
  254. // Now try and find any "unbound" keys...
  255. int mappings = m->entries.Count();
  256. for ( j = 0; j < mappings; ++j )
  257. {
  258. KeyBindingMap_t *kbMap = &m->entries[ j ];
  259. // See if it's bound
  260. CUtlVector< BoundKey_t * > list;
  261. pPanel->LookupBoundKeys( kbMap->bindingname, list );
  262. if ( list.Count() > 0 )
  263. continue;
  264. // Not bound, add a placeholder entry
  265. // Create a new: blank item
  266. KeyValues *item = new KeyValues( "Item" );
  267. // fill in data
  268. char loc[ 128 ];
  269. Q_snprintf( loc, sizeof( loc ), "#%s", kbMap->bindingname );
  270. char ansi[ 256 ];
  271. AnsiText( loc, ansi, sizeof( ansi ) );
  272. item->SetString( "Action", ansi );
  273. item->SetWString( "Binding", L"" );
  274. if ( kbMap->helpstring )
  275. {
  276. AnsiText( kbMap->helpstring, ansi, sizeof( ansi ) );
  277. item->SetString( "Description", ansi );
  278. }
  279. item->SetPtr( "Unbound", kbMap );
  280. sorted.Insert( item );
  281. }
  282. }
  283. for ( j = sorted.FirstInorder() ; j != sorted.InvalidIndex(); j = sorted.NextInorder( j ) )
  284. {
  285. KeyValues *item = sorted[ j ];
  286. // Add to list
  287. m_pList->AddItem( item, 0, false, false );
  288. item->deleteThis();
  289. }
  290. sorted.RemoveAll();
  291. }