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.

598 lines
16 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include "client_pch.h"
  7. #include <vgui/IClientPanel.h>
  8. #include <vgui_controls/TreeView.h>
  9. #include <vgui_controls/EditablePanel.h>
  10. #include <vgui_controls/Frame.h>
  11. #include <vgui_controls/CheckButton.h>
  12. #include <vgui_controls/Button.h>
  13. #include <vgui/IInput.h>
  14. #include "../vgui2/src/VPanel.h"
  15. #include "convar.h"
  16. #include "tier0/vprof.h"
  17. #include "vgui_baseui_interface.h"
  18. #include "vgui_helpers.h"
  19. // memdbgon must be the last include file in a .cpp file!!!
  20. #include "tier0/memdbgon.h"
  21. bool g_bForceRefresh = true;
  22. void ChangeCallback_RefreshDrawTree( IConVar *var, const char *pOldString, float flValue )
  23. {
  24. g_bForceRefresh = true;
  25. }
  26. // Bunch of vgui debugging stuff
  27. static ConVar vgui_drawtree( "vgui_drawtree", "0", FCVAR_CHEAT, "Draws the vgui panel hiearchy to the specified depth level." );
  28. static ConVar vgui_drawtree_visible( "vgui_drawtree_visible", "1", 0, "Draw the visible panels.", ChangeCallback_RefreshDrawTree );
  29. static ConVar vgui_drawtree_hidden( "vgui_drawtree_hidden", "0", 0, "Draw the hidden panels.", ChangeCallback_RefreshDrawTree );
  30. static ConVar vgui_drawtree_popupsonly( "vgui_drawtree_popupsonly", "0", 0, "Draws the vgui popup list in hierarchy(1) or most recently used(2) order.", ChangeCallback_RefreshDrawTree );
  31. static ConVar vgui_drawtree_freeze( "vgui_drawtree_freeze", "0", 0, "Set to 1 to stop updating the vgui_drawtree view.", ChangeCallback_RefreshDrawTree );
  32. static ConVar vgui_drawtree_panelptr( "vgui_drawtree_panelptr", "0", 0, "Show the panel pointer values in the vgui_drawtree view.", ChangeCallback_RefreshDrawTree );
  33. static ConVar vgui_drawtree_panelalpha( "vgui_drawtree_panelalpha", "0", 0, "Show the panel alpha values in the vgui_drawtree view.", ChangeCallback_RefreshDrawTree );
  34. static ConVar vgui_drawtree_render_order( "vgui_drawtree_render_order", "0", 0, "List the vgui_drawtree panels in render order.", ChangeCallback_RefreshDrawTree );
  35. static ConVar vgui_drawtree_bounds( "vgui_drawtree_bounds", "0", 0, "Show panel bounds.", ChangeCallback_RefreshDrawTree );
  36. static ConVar vgui_drawtree_draw_selected( "vgui_drawtree_draw_selected", "0", 0, "Highlight the selected panel", ChangeCallback_RefreshDrawTree );
  37. extern ConVar vgui_drawfocus;
  38. void vgui_drawtree_on_f()
  39. {
  40. vgui_drawtree.SetValue( 1 );
  41. }
  42. void vgui_drawtree_off_f()
  43. {
  44. vgui_drawtree.SetValue( 0 );
  45. }
  46. ConCommand vgui_drawtree_on( "+vgui_drawtree", vgui_drawtree_on_f );
  47. ConCommand vgui_drawtree_off( "-vgui_drawtree", vgui_drawtree_off_f );
  48. extern CUtlVector< vgui::VPANEL > g_FocusPanelList;
  49. extern vgui::VPanelHandle g_DrawTreeSelectedPanel;
  50. class CVGuiTree : public vgui::TreeView
  51. {
  52. public:
  53. typedef vgui::TreeView BaseClass;
  54. CVGuiTree( vgui::Panel *parent, const char *pName ) :
  55. BaseClass( parent, pName )
  56. {
  57. }
  58. virtual void ApplySchemeSettings( vgui::IScheme *pScheme )
  59. {
  60. BaseClass::ApplySchemeSettings( pScheme );
  61. SetFont( pScheme->GetFont( "ConsoleText", false ) );
  62. //SetBgColor( Color( 0, 0, 0, 175 ) );
  63. SetPaintBackgroundEnabled( false );
  64. }
  65. };
  66. class CDrawTreeFrame : public vgui::Frame
  67. {
  68. public:
  69. DECLARE_CLASS_SIMPLE( CDrawTreeFrame, vgui::Frame );
  70. CDrawTreeFrame( vgui::Panel *parent, const char *pName ) :
  71. BaseClass( parent, pName )
  72. {
  73. // Init the frame.
  74. SetTitle( "VGUI Hierarchy", false );
  75. SetMenuButtonVisible( false );
  76. // Create the tree control itself.
  77. m_pTree = vgui::SETUP_PANEL( new CVGuiTree( this, "Tree view" ) );
  78. m_pTree->SetVisible( true );
  79. // Init the buttons.
  80. m_pShowVisible = vgui::SETUP_PANEL( new CConVarCheckButton( this, "show visible", "Show Visible" ) );
  81. m_pShowVisible->SetVisible( true );
  82. m_pShowVisible->SetConVar( &vgui_drawtree_visible );
  83. m_pShowHidden = vgui::SETUP_PANEL( new CConVarCheckButton( this, "show hidden", "Show Hidden" ) );
  84. m_pShowHidden->SetVisible( true );
  85. m_pShowHidden->SetConVar( &vgui_drawtree_hidden );
  86. m_pPopupsOnly = vgui::SETUP_PANEL( new CConVarCheckButton( this, "popups only", "Popups Only" ) );
  87. m_pPopupsOnly->SetVisible( true );
  88. m_pPopupsOnly->SetConVar( &vgui_drawtree_popupsonly );
  89. m_pDrawFocus = vgui::SETUP_PANEL( new CConVarCheckButton( this, "draw focus", "Highlight MouseOver" ) );
  90. m_pDrawFocus->SetVisible( true );
  91. m_pDrawFocus->SetConVar( &vgui_drawfocus );
  92. m_pFreeze = vgui::SETUP_PANEL( new CConVarCheckButton( this, "freeze option", "Freeze" ) );
  93. m_pFreeze->SetVisible( true );
  94. m_pFreeze->SetConVar( &vgui_drawtree_freeze );
  95. m_pShowPanelPtr = vgui::SETUP_PANEL( new CConVarCheckButton( this, "panel ptr option", "Show Addresses" ) );
  96. m_pShowPanelPtr->SetVisible( true );
  97. m_pShowPanelPtr->SetConVar( &vgui_drawtree_panelptr );
  98. m_pShowPanelAlpha = vgui::SETUP_PANEL( new CConVarCheckButton( this, "panel alpha option", "Show Alpha" ) );
  99. m_pShowPanelAlpha->SetVisible( true );
  100. m_pShowPanelAlpha->SetConVar( &vgui_drawtree_panelalpha );
  101. m_pRenderOrder = vgui::SETUP_PANEL( new CConVarCheckButton( this, "render order option", "In Render Order" ) );
  102. m_pRenderOrder->SetVisible( true );
  103. m_pRenderOrder->SetConVar( &vgui_drawtree_render_order );
  104. m_pShowBounds = vgui::SETUP_PANEL( new CConVarCheckButton( this, "show panel bounds", "Show Panel Bounds" ) );
  105. m_pShowBounds->SetVisible( true );
  106. m_pShowBounds->SetConVar( &vgui_drawtree_bounds );
  107. m_pHighlightSelected = vgui::SETUP_PANEL( new CConVarCheckButton( this, "highlight selected", "Highlight Selected" ) );
  108. m_pHighlightSelected->SetVisible( true );
  109. m_pHighlightSelected->SetConVar( &vgui_drawtree_draw_selected );
  110. m_pPerformLayoutBtn = vgui::SETUP_PANEL( new vgui::Button( this, "performlayout", "Perform Layout (Highlighted)", this, "performlayout" ) );
  111. m_pPerformLayoutBtn->SetVisible( true );
  112. m_pReloadSchemeBtn = vgui::SETUP_PANEL( new vgui::Button( this, "reloadscheme", "Reload Scheme (Highlighted)", this, "reloadscheme" ) );
  113. m_pReloadSchemeBtn->SetVisible( true );
  114. int r,g,b,a;
  115. GetBgColor().GetColor( r, g, b, a );
  116. a = 128;
  117. SetBgColor( Color( r, g, b, a ) );
  118. }
  119. virtual void PerformLayout()
  120. {
  121. BaseClass::PerformLayout();
  122. int x, y, w, t;
  123. GetClientArea( x, y, w, t );
  124. int yOffset = y;
  125. // Align the check boxes.
  126. m_pShowVisible->SetPos( x, yOffset );
  127. m_pShowVisible->SetWide( w/2 );
  128. yOffset += m_pShowVisible->GetTall();
  129. m_pShowHidden->SetPos( x, yOffset );
  130. m_pShowHidden->SetWide( w/2 );
  131. yOffset += m_pShowHidden->GetTall();
  132. m_pPopupsOnly->SetPos( x, yOffset );
  133. m_pPopupsOnly->SetWide( w/2 );
  134. yOffset += m_pPopupsOnly->GetTall();
  135. m_pDrawFocus->SetPos( x, yOffset );
  136. m_pDrawFocus->SetWide( w/2 );
  137. yOffset += m_pDrawFocus->GetTall();
  138. m_pShowBounds->SetPos( x, yOffset );
  139. m_pShowBounds->SetWide( w/2 );
  140. yOffset += m_pShowBounds->GetTall();
  141. // Next column..
  142. yOffset = y;
  143. m_pFreeze->SetPos( x + w/2, yOffset );
  144. m_pFreeze->SetWide( w/2 );
  145. yOffset += m_pFreeze->GetTall();
  146. m_pShowPanelPtr->SetPos( x + w/2, yOffset );
  147. m_pShowPanelPtr->SetWide( w/2 );
  148. yOffset += m_pShowPanelPtr->GetTall();
  149. m_pShowPanelAlpha->SetPos( x + w/2, yOffset );
  150. m_pShowPanelAlpha->SetWide( w/2 );
  151. yOffset += m_pShowPanelAlpha->GetTall();
  152. m_pRenderOrder->SetPos( x + w/2, yOffset );
  153. m_pRenderOrder->SetWide( w/2 );
  154. yOffset += m_pRenderOrder->GetTall();
  155. m_pHighlightSelected->SetPos( x + w/2, yOffset );
  156. m_pHighlightSelected->SetWide( w/2 );
  157. yOffset += m_pHighlightSelected->GetTall();
  158. // buttons
  159. m_pPerformLayoutBtn->SetPos( x , yOffset );
  160. m_pPerformLayoutBtn->SizeToContents();
  161. m_pPerformLayoutBtn->SetWide( w );
  162. yOffset += m_pPerformLayoutBtn->GetTall();
  163. m_pReloadSchemeBtn->SetPos( x , yOffset );
  164. m_pReloadSchemeBtn->SizeToContents();
  165. m_pReloadSchemeBtn->SetWide( w );
  166. yOffset += m_pReloadSchemeBtn->GetTall();
  167. // the tree control
  168. m_pTree->SetBounds( x, yOffset, w, t - (yOffset - y) );
  169. }
  170. virtual void OnCommand( const char *command )
  171. {
  172. if ( !Q_stricmp( command, "performlayout" ) )
  173. {
  174. if ( g_DrawTreeSelectedPanel )
  175. {
  176. vgui::ipanel()->SendMessage( g_DrawTreeSelectedPanel, new KeyValues("Command", "command", "performlayout"), GetVPanel() );
  177. }
  178. }
  179. else if ( !Q_stricmp( command, "reloadscheme" ) )
  180. {
  181. if ( g_DrawTreeSelectedPanel )
  182. {
  183. vgui::ipanel()->SendMessage( g_DrawTreeSelectedPanel, new KeyValues("Command", "command", "reloadscheme"), GetVPanel() );
  184. }
  185. }
  186. else
  187. {
  188. BaseClass::OnCommand( command );
  189. }
  190. }
  191. MESSAGE_FUNC( OnItemSelected, "TreeViewItemSelected" )
  192. {
  193. RecalculateSelectedHighlight();
  194. }
  195. void RecalculateSelectedHighlight( void )
  196. {
  197. Assert( m_pTree );
  198. if ( !vgui_drawtree_draw_selected.GetBool() || m_pTree->GetSelectedItemCount() != 1 )
  199. {
  200. // clear the selection
  201. g_DrawTreeSelectedPanel = 0;
  202. }
  203. else
  204. {
  205. CUtlVector< int > list;
  206. m_pTree->GetSelectedItems( list );
  207. Assert( list.Count() == 1 );
  208. KeyValues *data = m_pTree->GetItemData( list.Element(0) );
  209. if ( data )
  210. {
  211. g_DrawTreeSelectedPanel = (data) ? (vgui::VPANEL)data->GetInt( "PanelPtr", 0 ) : 0;
  212. }
  213. else
  214. {
  215. g_DrawTreeSelectedPanel = 0;
  216. }
  217. }
  218. }
  219. virtual void OnClose()
  220. {
  221. vgui_drawtree.SetValue( 0 );
  222. g_DrawTreeSelectedPanel = 0;
  223. // fixme - g_DrawTreeSelectedPanel has a potential crash if you hilight a panel, and then spam hud_reloadscheme
  224. // you will sometimes end up on a different panel or on garbage.
  225. }
  226. virtual void OnThink() OVERRIDE
  227. {
  228. BaseClass::OnThink();
  229. vgui::VPANEL focus = 0;
  230. if ( vgui::input() )
  231. {
  232. focus = vgui::input()->GetFocus();
  233. }
  234. MoveToFront();
  235. if ( vgui::input() && focus )
  236. {
  237. OnRequestFocus(focus, NULL);
  238. }
  239. }
  240. public:
  241. CVGuiTree *m_pTree;
  242. CConVarCheckButton *m_pShowVisible;
  243. CConVarCheckButton *m_pShowHidden;
  244. CConVarCheckButton *m_pPopupsOnly;
  245. CConVarCheckButton *m_pFreeze;
  246. CConVarCheckButton *m_pShowPanelPtr;
  247. CConVarCheckButton *m_pShowPanelAlpha;
  248. CConVarCheckButton *m_pRenderOrder;
  249. CConVarCheckButton *m_pDrawFocus;
  250. CConVarCheckButton *m_pShowBounds;
  251. CConVarCheckButton *m_pHighlightSelected;
  252. vgui::Button *m_pPerformLayoutBtn;
  253. vgui::Button *m_pReloadSchemeBtn;
  254. };
  255. CDrawTreeFrame *g_pDrawTreeFrame = 0;
  256. void VGui_RecursivePrintTree(
  257. vgui::VPANEL current,
  258. KeyValues *pCurrentParent,
  259. int popupDepthCounter )
  260. {
  261. if ( !current )
  262. return;
  263. vgui::IPanel *ipanel = vgui::ipanel();
  264. if ( !vgui_drawtree_visible.GetInt() && ipanel->IsVisible( current ) )
  265. return;
  266. else if ( !vgui_drawtree_hidden.GetInt() && !ipanel->IsVisible( current ) )
  267. return;
  268. else if ( popupDepthCounter <= 0 && ipanel->IsPopup( current ) )
  269. return;
  270. KeyValues *pNewParent = pCurrentParent;
  271. KeyValues *pVal = pCurrentParent->CreateNewKey();
  272. // Bind data to pVal.
  273. char name[1024];
  274. const char *pInputName = ipanel->GetName( current );
  275. if ( pInputName && pInputName[0] != 0 )
  276. Q_snprintf( name, sizeof( name ), "%s", pInputName );
  277. else
  278. Q_snprintf( name, sizeof( name ), "%s", "(no name)" );
  279. if ( ipanel->IsMouseInputEnabled( current ) )
  280. {
  281. Q_strncat( name, ", +m", sizeof( name ), COPY_ALL_CHARACTERS );
  282. }
  283. if ( ipanel->IsKeyBoardInputEnabled( current ) )
  284. {
  285. Q_strncat( name, ", +k", sizeof( name ), COPY_ALL_CHARACTERS );
  286. }
  287. if ( vgui_drawtree_bounds.GetBool() )
  288. {
  289. int x, y, w, h;
  290. vgui::ipanel()->GetPos( current, x, y );
  291. vgui::ipanel()->GetSize( current, w, h );
  292. char b[ 128 ];
  293. Q_snprintf( b, sizeof( b ), "[%-4i %-4i %-4i %-4i]", x, y, w, h );
  294. Q_strncat( name, ", ", sizeof( name ), COPY_ALL_CHARACTERS );
  295. Q_strncat( name, b, sizeof( name ), COPY_ALL_CHARACTERS );
  296. }
  297. char str[1024];
  298. if ( vgui_drawtree_panelptr.GetInt() )
  299. Q_snprintf( str, sizeof( str ), "%s - [0x%x]", name, current );
  300. else if (vgui_drawtree_panelalpha.GetInt() )
  301. {
  302. KeyValues *kv = new KeyValues("alpha");
  303. vgui::ipanel()->RequestInfo(current, kv);
  304. Q_snprintf( str, sizeof( str ), "%s - [%d]", name, kv->GetInt("alpha") );
  305. kv->deleteThis();
  306. }
  307. else
  308. Q_snprintf( str, sizeof( str ), "%s", name );
  309. pVal->SetString( "Text", str );
  310. pVal->SetInt( "PanelPtr", current );
  311. pNewParent = pVal;
  312. // Don't recurse past the tree itself because the tree control uses a panel for each
  313. // panel inside itself, and it'll infinitely create panels.
  314. if ( current == g_pDrawTreeFrame->m_pTree->GetVPanel() )
  315. return;
  316. int count = ipanel->GetChildCount( current );
  317. for ( int i = 0; i < count ; i++ )
  318. {
  319. vgui::VPANEL panel = ipanel->GetChild( current, i );
  320. VGui_RecursivePrintTree( panel, pNewParent, popupDepthCounter-1 );
  321. }
  322. }
  323. bool UpdateItemState(
  324. vgui::TreeView *pTree,
  325. int iChildItemId,
  326. KeyValues *pSub )
  327. {
  328. bool bRet = false;
  329. vgui::IPanel *ipanel = vgui::ipanel();
  330. KeyValues *pItemData = pTree->GetItemData( iChildItemId );
  331. if ( pItemData->GetInt( "PanelPtr" ) != pSub->GetInt( "PanelPtr" ) ||
  332. Q_stricmp( pItemData->GetString( "Text" ), pSub->GetString( "Text" ) ) != 0 )
  333. {
  334. pTree->ModifyItem( iChildItemId, pSub );
  335. bRet = true;
  336. }
  337. // Ok, this is a new panel.
  338. vgui::VPANEL vPanel = pSub->GetInt( "PanelPtr" );
  339. int iBaseColor[3] = { 255, 255, 255 };
  340. if ( ipanel->IsPopup( vPanel ) )
  341. {
  342. iBaseColor[0] = 255; iBaseColor[1] = 255; iBaseColor[2] = 0;
  343. }
  344. if ( g_FocusPanelList.Find( vPanel ) != -1 )
  345. {
  346. iBaseColor[0] = 0; iBaseColor[1] = 255; iBaseColor[2] = 0;
  347. pTree->ExpandItem( iChildItemId, true );
  348. }
  349. if ( !ipanel->IsVisible( vPanel ) )
  350. {
  351. iBaseColor[0] >>= 1; iBaseColor[1] >>= 1; iBaseColor[2] >>= 1;
  352. }
  353. pTree->SetItemFgColor( iChildItemId, Color( iBaseColor[0], iBaseColor[1], iBaseColor[2], 255 ) );
  354. return bRet;
  355. }
  356. void IncrementalUpdateTree(
  357. vgui::TreeView *pTree,
  358. KeyValues *pValues )
  359. {
  360. if ( !g_bForceRefresh && vgui_drawtree_freeze.GetInt() )
  361. return;
  362. g_bForceRefresh = false;
  363. bool bInvalidateLayout = IncrementalUpdateTree( pTree, pValues, UpdateItemState, -1 );
  364. pTree->ExpandItem( pTree->GetRootItemIndex(), true );
  365. if ( g_pDrawTreeFrame )
  366. g_pDrawTreeFrame->RecalculateSelectedHighlight();
  367. if ( bInvalidateLayout )
  368. pTree->InvalidateLayout();
  369. }
  370. bool WillPanelBeVisible( vgui::VPANEL hPanel )
  371. {
  372. while ( hPanel )
  373. {
  374. if ( !vgui::ipanel()->IsVisible( hPanel ) )
  375. return false;
  376. hPanel = vgui::ipanel()->GetParent( hPanel );
  377. }
  378. return true;
  379. }
  380. void VGui_AddPopupsToKeyValues( KeyValues *pCurrentParent )
  381. {
  382. // 'twould be nice if we could get the Panel* from the VPANEL, but we can't.
  383. int count = vgui::surface()->GetPopupCount();
  384. for ( int i=0; i < count; i++ )
  385. {
  386. vgui::VPANEL vPopup = vgui::surface()->GetPopup( i );
  387. if ( vgui_drawtree_hidden.GetInt() || WillPanelBeVisible( vPopup ) )
  388. {
  389. VGui_RecursivePrintTree(
  390. vPopup,
  391. pCurrentParent,
  392. 1 );
  393. }
  394. }
  395. }
  396. void VGui_FillKeyValues( KeyValues *pCurrentParent )
  397. {
  398. if ( !EngineVGui()->IsInitialized() )
  399. return;
  400. // Figure out the root panel to start at.
  401. // If they specified a name for a root panel, then use that one.
  402. vgui::VPANEL hBase = vgui::surface()->GetEmbeddedPanel();
  403. if ( vgui_drawtree_popupsonly.GetInt() )
  404. {
  405. VGui_AddPopupsToKeyValues( pCurrentParent );
  406. }
  407. else if ( vgui_drawtree_render_order.GetInt() )
  408. {
  409. VGui_RecursivePrintTree(
  410. hBase,
  411. pCurrentParent,
  412. 0 );
  413. VGui_AddPopupsToKeyValues( pCurrentParent );
  414. }
  415. else
  416. {
  417. VGui_RecursivePrintTree(
  418. hBase,
  419. pCurrentParent,
  420. 99999 );
  421. }
  422. }
  423. void VGui_DrawHierarchy( void )
  424. {
  425. VPROF( "VGui_DrawHierarchy" );
  426. if ( IsX360() )
  427. return;
  428. if ( vgui_drawtree.GetInt() <= 0 )
  429. {
  430. g_pDrawTreeFrame->SetVisible( false );
  431. return;
  432. }
  433. g_pDrawTreeFrame->SetVisible( true );
  434. // Now reconstruct the tree control.
  435. KeyValues *pRoot = new KeyValues("");
  436. pRoot->SetString( "Text", "<shouldn't see this>" );
  437. VGui_FillKeyValues( pRoot );
  438. // Now incrementally update the tree control so we can preserve which nodes are open.
  439. IncrementalUpdateTree( g_pDrawTreeFrame->m_pTree, pRoot );
  440. // Delete the keyvalues.
  441. pRoot->deleteThis();
  442. }
  443. void VGui_CreateDrawTreePanel( vgui::Panel *parent )
  444. {
  445. int widths = 300;
  446. g_pDrawTreeFrame = vgui::SETUP_PANEL( new CDrawTreeFrame( parent, "DrawTreeFrame" ) );
  447. g_pDrawTreeFrame->SetVisible( false );
  448. g_pDrawTreeFrame->SetBounds( parent->GetWide() - widths, 0, widths, parent->GetTall() - 10 );
  449. g_pDrawTreeFrame->MakePopup( false, false );
  450. g_pDrawTreeFrame->SetKeyBoardInputEnabled( true );
  451. g_pDrawTreeFrame->SetMouseInputEnabled( true );
  452. }
  453. void VGui_MoveDrawTreePanelToFront()
  454. {
  455. if ( g_pDrawTreeFrame )
  456. g_pDrawTreeFrame->MoveToFront();
  457. }
  458. void VGui_UpdateDrawTreePanel()
  459. {
  460. VGui_DrawHierarchy();
  461. }
  462. void vgui_drawtree_clear_f()
  463. {
  464. if ( g_pDrawTreeFrame && g_pDrawTreeFrame->m_pTree )
  465. g_pDrawTreeFrame->m_pTree->RemoveAll();
  466. }
  467. ConCommand vgui_drawtree_clear( "vgui_drawtree_clear", vgui_drawtree_clear_f );