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.

1072 lines
31 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include <vgui/IPanel.h>
  8. #include <vgui/ISurface.h>
  9. #include <vgui/ISystem.h>
  10. #include <vgui/ILocalize.h>
  11. #include <KeyValues.h>
  12. #include "vgui/IVGui.h"
  13. #include <vgui_controls/BuildGroup.h>
  14. #include <vgui_controls/BuildModeDialog.h>
  15. #include <vgui_controls/EditablePanel.h>
  16. // these includes are all for the virtual contruction factory Dialog::CreateControlByName()
  17. #include <vgui_controls/Button.h>
  18. #include <vgui_controls/Label.h>
  19. #include <vgui_controls/CheckButton.h>
  20. #include <vgui_controls/ComboBox.h>
  21. #include <vgui_controls/Menu.h>
  22. #include <vgui_controls/MenuItem.h>
  23. #include <vgui_controls/MessageBox.h>
  24. #include <vgui_controls/ProgressBar.h>
  25. #include <vgui_controls/RadioButton.h>
  26. #include <vgui_controls/ScrollBar.h>
  27. #include <vgui_controls/ToggleButton.h>
  28. #include <vgui_controls/ImagePanel.h>
  29. #include <vgui_controls/AnimatingImagePanel.h>
  30. #include <vgui_controls/Divider.h>
  31. #include <vgui_controls/URLLabel.h>
  32. #include <vgui_controls/RichText.h>
  33. #include <vgui_controls/BitmapImagePanel.h>
  34. #include "filesystem.h"
  35. #include "fmtstr.h"
  36. // memdbgon must be the last include file in a .cpp file!!!
  37. #include <tier0/memdbgon.h>
  38. using namespace vgui;
  39. DECLARE_BUILD_FACTORY( EditablePanel );
  40. //-----------------------------------------------------------------------------
  41. // Purpose: Constructor
  42. //-----------------------------------------------------------------------------
  43. #pragma warning( disable : 4355 )
  44. EditablePanel::EditablePanel(Panel *parent, const char *panelName) : Panel(parent, panelName), m_NavGroup(this)
  45. {
  46. _buildGroup = new BuildGroup(this, this);
  47. m_pszConfigName = NULL;
  48. m_iConfigID = 0;
  49. m_pDialogVariables = NULL;
  50. m_bShouldSkipAutoResize = false;
  51. // add ourselves to the build group
  52. SetBuildGroup(GetBuildGroup());
  53. }
  54. //-----------------------------------------------------------------------------
  55. // Purpose: Constructor
  56. //-----------------------------------------------------------------------------
  57. EditablePanel::EditablePanel(Panel *parent, const char *panelName, HScheme hScheme) : Panel(parent, panelName, hScheme), m_NavGroup(this)
  58. {
  59. _buildGroup = new BuildGroup(this, this);
  60. m_pszConfigName = NULL;
  61. m_iConfigID = 0;
  62. m_pDialogVariables = NULL;
  63. m_bShouldSkipAutoResize = false;
  64. // add ourselves to the build group
  65. SetBuildGroup(GetBuildGroup());
  66. }
  67. #pragma warning( default : 4355 )
  68. //-----------------------------------------------------------------------------
  69. // Purpose: Destructor
  70. //-----------------------------------------------------------------------------
  71. EditablePanel::~EditablePanel()
  72. {
  73. delete [] m_pszConfigName;
  74. delete _buildGroup;
  75. if (m_pDialogVariables)
  76. {
  77. m_pDialogVariables->deleteThis();
  78. }
  79. }
  80. //-----------------------------------------------------------------------------
  81. // Purpose: Called when a child is added to the panel.
  82. //-----------------------------------------------------------------------------
  83. void EditablePanel::OnChildAdded(VPANEL child)
  84. {
  85. BaseClass::OnChildAdded(child);
  86. // add only if we're in the same module
  87. Panel *panel = ipanel()->GetPanel(child, GetModuleName());
  88. if (panel)
  89. {
  90. panel->SetBuildGroup(_buildGroup);
  91. panel->AddActionSignalTarget(this);
  92. }
  93. }
  94. //-----------------------------------------------------------------------------
  95. // Purpose:
  96. //-----------------------------------------------------------------------------
  97. void EditablePanel::OnKeyCodePressed( KeyCode code )
  98. {
  99. static ConVarRef vgui_nav_lock_default_button( "vgui_nav_lock_default_button" );
  100. if ( !vgui_nav_lock_default_button.IsValid() || vgui_nav_lock_default_button.GetInt() == 0 )
  101. {
  102. ButtonCode_t nButtonCode = GetBaseButtonCode( code );
  103. // check for a default button
  104. VPANEL panel = GetFocusNavGroup().GetCurrentDefaultButton();
  105. if ( panel && !IsConsoleStylePanel() )
  106. {
  107. switch ( nButtonCode )
  108. {
  109. case KEY_XBUTTON_UP:
  110. case KEY_XSTICK1_UP:
  111. case KEY_XSTICK2_UP:
  112. case KEY_UP:
  113. case STEAMCONTROLLER_DPAD_UP:
  114. case KEY_XBUTTON_DOWN:
  115. case KEY_XSTICK1_DOWN:
  116. case KEY_XSTICK2_DOWN:
  117. case KEY_DOWN:
  118. case STEAMCONTROLLER_DPAD_DOWN:
  119. case KEY_XBUTTON_LEFT:
  120. case KEY_XSTICK1_LEFT:
  121. case KEY_XSTICK2_LEFT:
  122. case KEY_LEFT:
  123. case KEY_XBUTTON_RIGHT:
  124. case KEY_XSTICK1_RIGHT:
  125. case KEY_XSTICK2_RIGHT:
  126. case KEY_RIGHT:
  127. case KEY_XBUTTON_B:
  128. case STEAMCONTROLLER_B:
  129. // Navigating menus
  130. vgui_nav_lock_default_button.SetValue( 1 );
  131. PostMessage( panel, new KeyValues( "KeyCodePressed", "code", code ) );
  132. return;
  133. case KEY_XBUTTON_A:
  134. case STEAMCONTROLLER_A:
  135. case KEY_ENTER:
  136. if ( ipanel()->IsVisible( panel ) && ipanel()->IsEnabled( panel ) )
  137. {
  138. // Activate the button
  139. PostMessage( panel, new KeyValues( "Hotkey" ) );
  140. return;
  141. }
  142. }
  143. }
  144. }
  145. if ( !m_PassUnhandledInput )
  146. return;
  147. // Nothing to do with the button
  148. BaseClass::OnKeyCodePressed( code );
  149. }
  150. //-----------------------------------------------------------------------------
  151. // Purpose: Callback for when the panel size has been changed
  152. //-----------------------------------------------------------------------------
  153. void EditablePanel::OnSizeChanged(int wide, int tall)
  154. {
  155. BaseClass::OnSizeChanged(wide, tall);
  156. InvalidateLayout();
  157. for (int i = 0; i < GetChildCount(); i++)
  158. {
  159. // perform auto-layout on the child panel
  160. Panel *child = GetChild(i);
  161. if ( !child )
  162. continue;
  163. int x, y, w, h;
  164. child->GetBounds( x, y, w, h );
  165. int px, py;
  166. child->GetPinOffset( px, py );
  167. int ox, oy;
  168. child->GetResizeOffset( ox, oy );
  169. int ex;
  170. int ey;
  171. AutoResize_e resize = child->GetAutoResize();
  172. bool bResizeHoriz = ( resize == AUTORESIZE_RIGHT || resize == AUTORESIZE_DOWNANDRIGHT );
  173. bool bResizeVert = ( resize == AUTORESIZE_DOWN || resize == AUTORESIZE_DOWNANDRIGHT );
  174. // The correct version of this code would say:
  175. // if ( resize != AUTORESIZE_NO )
  176. // but we're very close to shipping and this causes artifacts in other vgui panels that now
  177. // depend on this bug. So, I've added m_bShouldSkipAutoResize, which defaults to false but can
  178. // be set using "skip_autoresize" in a .res file
  179. if ( !m_bShouldSkipAutoResize )
  180. {
  181. PinCorner_e pinCorner = child->GetPinCorner();
  182. if ( pinCorner == PIN_TOPRIGHT || pinCorner == PIN_BOTTOMRIGHT )
  183. {
  184. // move along with the right edge
  185. ex = wide + px;
  186. x = bResizeHoriz ? ox : ex - w;
  187. }
  188. else
  189. {
  190. x = px;
  191. ex = bResizeHoriz ? wide + ox : px + w;
  192. }
  193. if ( pinCorner == PIN_BOTTOMLEFT || pinCorner == PIN_BOTTOMRIGHT )
  194. {
  195. // move along with the right edge
  196. ey = tall + py;
  197. y = bResizeVert ? oy : ey - h;
  198. }
  199. else
  200. {
  201. y = py;
  202. ey = bResizeVert ? tall + oy : py + h;
  203. }
  204. // Clamp..
  205. if ( ex < x )
  206. {
  207. ex = x;
  208. }
  209. if ( ey < y )
  210. {
  211. ey = y;
  212. }
  213. child->SetBounds( x, y, ex - x, ey - y );
  214. child->InvalidateLayout();
  215. }
  216. }
  217. Repaint();
  218. }
  219. //-----------------------------------------------------------------------------
  220. // Purpose:
  221. //-----------------------------------------------------------------------------
  222. void EditablePanel::OnCurrentDefaultButtonSet( VPANEL defaultButton )
  223. {
  224. m_NavGroup.SetCurrentDefaultButton( defaultButton, false );
  225. // forward the message up
  226. if (GetVParent())
  227. {
  228. KeyValues *msg = new KeyValues("CurrentDefaultButtonSet");
  229. msg->SetInt("button", ivgui()->PanelToHandle( defaultButton ) );
  230. PostMessage(GetVParent(), msg);
  231. }
  232. }
  233. //-----------------------------------------------------------------------------
  234. // Purpose:
  235. //-----------------------------------------------------------------------------
  236. void EditablePanel::OnDefaultButtonSet( VPANEL defaultButton )
  237. {
  238. Panel *panel = ipanel()->GetPanel( defaultButton, GetModuleName() );
  239. m_NavGroup.SetDefaultButton(panel);
  240. }
  241. //-----------------------------------------------------------------------------
  242. // Purpose:
  243. //-----------------------------------------------------------------------------
  244. void EditablePanel::OnFindDefaultButton()
  245. {
  246. if (m_NavGroup.GetDefaultButton())
  247. {
  248. m_NavGroup.SetCurrentDefaultButton(m_NavGroup.GetDefaultButton());
  249. }
  250. else
  251. {
  252. if (GetVParent())
  253. {
  254. PostMessage(GetVParent(), new KeyValues("FindDefaultButton"));
  255. }
  256. }
  257. }
  258. struct leaf_t
  259. {
  260. short x, y, wide, tall;
  261. unsigned char split; // 0 no split; 1 x-axis, 2 y-axis
  262. bool filled; // true if this is already filled
  263. short splitpos; // place of split
  264. leaf_t *left;
  265. leaf_t *right;
  266. };
  267. leaf_t g_Leaves[256];
  268. int g_iNextLeaf;
  269. inline leaf_t *AllocLeaf()
  270. {
  271. Assert(g_iNextLeaf < 255);
  272. return &g_Leaves[g_iNextLeaf++];
  273. }
  274. void AddSolidToTree(leaf_t *leaf, int x, int y, int wide, int tall)
  275. {
  276. // clip to this leaf
  277. if (x < leaf->x)
  278. {
  279. wide -= (leaf->x - x);
  280. if (wide < 1)
  281. return;
  282. x = leaf->x;
  283. }
  284. if (y < leaf->y)
  285. {
  286. tall -= (leaf->y - y);
  287. if (tall < 1)
  288. return;
  289. y = leaf->y;
  290. }
  291. if (x + wide > leaf->x + leaf->wide)
  292. {
  293. wide -= ((x + wide) - (leaf->x + leaf->wide));
  294. if (wide < 1)
  295. return;
  296. }
  297. if (y + tall > leaf->y + leaf->tall)
  298. {
  299. tall -= ((y + tall) - (leaf->y + leaf->tall));
  300. if (tall < 1)
  301. return;
  302. }
  303. // the rect should now be completely within the leaf
  304. if (leaf->split == 1)
  305. {
  306. // see if it is to the left or the right of the split
  307. if (x < leaf->splitpos)
  308. {
  309. // it's to the left
  310. AddSolidToTree(leaf->left, x, y, wide, tall);
  311. }
  312. else if (x + wide > leaf->splitpos)
  313. {
  314. // it's to the right
  315. AddSolidToTree(leaf->right, x, y, wide, tall);
  316. }
  317. }
  318. else if (leaf->split == 2)
  319. {
  320. // check y
  321. // see if it is to the left (above) or the right (below) of the split
  322. if (y < leaf->splitpos)
  323. {
  324. // it's above
  325. AddSolidToTree(leaf->left, x, y, wide, tall);
  326. }
  327. else if (y + tall > leaf->splitpos)
  328. {
  329. // it's below
  330. AddSolidToTree(leaf->right, x, y, wide, tall);
  331. }
  332. }
  333. else
  334. {
  335. // this leaf is unsplit, make the first split against the first edge we find
  336. if (x > leaf->x)
  337. {
  338. // split the left side of the rect
  339. leaf->split = 1;
  340. leaf->splitpos = (short)x;
  341. // create 2 new leaves
  342. leaf_t *left = AllocLeaf();
  343. leaf_t *right = AllocLeaf();
  344. memset(left, 0, sizeof(leaf_t));
  345. memset(right, 0, sizeof(leaf_t));
  346. leaf->left = left;
  347. leaf->right = right;
  348. left->x = leaf->x;
  349. left->y = leaf->y;
  350. left->wide = (short)(leaf->splitpos - leaf->x);
  351. left->tall = leaf->tall;
  352. right->x = leaf->splitpos;
  353. right->y = leaf->y;
  354. right->wide = (short)(leaf->wide - left->wide);
  355. right->tall = leaf->tall;
  356. // split the right leaf by the current rect
  357. AddSolidToTree(leaf->right, x, y, wide, tall);
  358. }
  359. else if (y > leaf->y)
  360. {
  361. // split the top edge
  362. leaf->split = 2;
  363. leaf->splitpos = (short)y;
  364. // create 2 new leaves (facing to the east)
  365. leaf_t *left = AllocLeaf();
  366. leaf_t *right = AllocLeaf();
  367. memset(left, 0, sizeof(leaf_t));
  368. memset(right, 0, sizeof(leaf_t));
  369. leaf->left = left;
  370. leaf->right = right;
  371. left->x = leaf->x;
  372. left->y = leaf->y;
  373. left->wide = leaf->wide;
  374. left->tall = (short)(y - leaf->y);
  375. right->x = leaf->x;
  376. right->y = leaf->splitpos;
  377. right->wide = leaf->wide;
  378. right->tall = (short)(leaf->tall + leaf->y - right->y);
  379. // split the right leaf by the current rect
  380. AddSolidToTree(leaf->right, x, y, wide, tall);
  381. }
  382. else if (x + wide < leaf->x + leaf->wide)
  383. {
  384. // split the right edge
  385. leaf->split = 1;
  386. leaf->splitpos = (short)(x + wide);
  387. // create 2 new leaves
  388. leaf_t *left = AllocLeaf();
  389. leaf_t *right = AllocLeaf();
  390. memset(left, 0, sizeof(leaf_t));
  391. memset(right, 0, sizeof(leaf_t));
  392. leaf->left = left;
  393. leaf->right = right;
  394. left->x = leaf->x;
  395. left->y = leaf->y;
  396. left->wide = (short)(leaf->splitpos - leaf->x);
  397. left->tall = leaf->tall;
  398. right->x = leaf->splitpos;
  399. right->y = leaf->y;
  400. right->wide = (short)(leaf->wide - left->wide);
  401. right->tall = leaf->tall;
  402. // split the left leaf by the current rect
  403. AddSolidToTree(leaf->left, x, y, wide, tall);
  404. }
  405. else if (y + tall < leaf->y + leaf->tall)
  406. {
  407. // split the bottom edge
  408. leaf->split = 2;
  409. leaf->splitpos = (short)(y + tall);
  410. // create 2 new leaves (facing to the east)
  411. leaf_t *left = AllocLeaf();
  412. leaf_t *right = AllocLeaf();
  413. memset(left, 0, sizeof(leaf_t));
  414. memset(right, 0, sizeof(leaf_t));
  415. leaf->left = left;
  416. leaf->right = right;
  417. left->x = leaf->x;
  418. left->y = leaf->y;
  419. left->wide = leaf->wide;
  420. left->tall = (short)(leaf->splitpos - leaf->y);
  421. right->x = leaf->x;
  422. right->y = leaf->splitpos;
  423. right->wide = leaf->wide;
  424. right->tall = (short)(leaf->tall - left->tall);
  425. // split the left leaf by the current rect
  426. AddSolidToTree(leaf->left, x, y, wide, tall);
  427. }
  428. else
  429. {
  430. // this is the exact same rect! don't draw this leaf
  431. leaf->filled = true;
  432. return;
  433. }
  434. }
  435. }
  436. //-----------------------------------------------------------------------------
  437. // Purpose: Fills the panel background, clipping if possible
  438. //-----------------------------------------------------------------------------
  439. void EditablePanel::PaintBackground()
  440. {
  441. BaseClass::PaintBackground();
  442. return;
  443. /*
  444. test code, using a screenspace bsp tree to reduce overdraw in vgui
  445. not yet fully functional
  446. // test: fill background with obnoxious color to show holes
  447. // surface()->DrawSetColor(Color(255, 0, 0, 255));
  448. // surface()->DrawFilledRect(0, 0, GetWide(), GetTall());
  449. // return;
  450. // reset the leaf memory
  451. g_iNextLeaf = 0;
  452. leaf_t *headNode = AllocLeaf();
  453. memset(headNode, 0, sizeof(leaf_t));
  454. headNode->wide = (short)GetWide();
  455. headNode->tall = (short)GetTall();
  456. // split the leaf by the first child
  457. for (int i = 0; i < GetChildCount(); i++)
  458. {
  459. Panel *child = GetChild(i);
  460. if (child->IsOpaque())
  461. {
  462. int x, y, wide, tall;
  463. child->GetBounds(x, y, wide, tall);
  464. // ignore small children
  465. if (wide + tall < 100)
  466. continue;
  467. AddSolidToTree(headNode, x, y, wide, tall);
  468. }
  469. }
  470. // walk the built tree, painting the background
  471. Color col = GetBgColor();
  472. surface()->DrawSetColor(col);
  473. for (i = 0; i < g_iNextLeaf; i++)
  474. {
  475. leaf_t *leaf = g_Leaves + i;
  476. if (leaf->splitpos || leaf->filled)
  477. continue;
  478. surface()->DrawFilledRect(leaf->x, leaf->y, leaf->x + leaf->wide, leaf->y + leaf->tall);
  479. }
  480. */
  481. }
  482. //-----------------------------------------------------------------------------
  483. // Purpose: Activates the build mode dialog for editing panels.
  484. //-----------------------------------------------------------------------------
  485. void EditablePanel::ActivateBuildMode()
  486. {
  487. _buildGroup->SetEnabled(true);
  488. }
  489. //-----------------------------------------------------------------------------
  490. // Purpose: Loads panel settings from a resource file.
  491. //-----------------------------------------------------------------------------
  492. void EditablePanel::LoadControlSettings(const char *resourceName, const char *pathID, KeyValues *pKeyValues, KeyValues *pConditions)
  493. {
  494. #if defined( DBGFLAG_ASSERT ) && !defined(OSX) && !defined(LINUX)
  495. // Since nobody wants to fix this assert, I'm making it a Msg instead:
  496. // editablepanel.cpp (535) : Resource file "resource\DebugOptionsPanel.res" not found on disk!
  497. // AssertMsg( g_pFullFileSystem->FileExists( resourceName ), CFmtStr( "Resource file \"%s\" not found on disk!", resourceName ).Access() );
  498. if ( !g_pFullFileSystem->FileExists( resourceName ) )
  499. {
  500. Msg( "Resource file \"%s\" not found on disk!", resourceName );
  501. }
  502. #endif
  503. _buildGroup->LoadControlSettings(resourceName, pathID, pKeyValues, pConditions);
  504. ForceSubPanelsToUpdateWithNewDialogVariables();
  505. InvalidateLayout();
  506. }
  507. //-----------------------------------------------------------------------------
  508. // Purpose: registers a file in the list of control settings, so the vgui dialog can choose between them to edit
  509. //-----------------------------------------------------------------------------
  510. void EditablePanel::RegisterControlSettingsFile(const char *resourceName, const char *pathID)
  511. {
  512. _buildGroup->RegisterControlSettingsFile(resourceName, pathID);
  513. }
  514. //-----------------------------------------------------------------------------
  515. // Purpose: sets the name of this dialog so it can be saved in the user config area
  516. //-----------------------------------------------------------------------------
  517. void EditablePanel::LoadUserConfig(const char *configName, int dialogID)
  518. {
  519. KeyValues *data = system()->GetUserConfigFileData(configName, dialogID);
  520. delete [] m_pszConfigName;
  521. int len = Q_strlen(configName) + 1;
  522. m_pszConfigName = new char[ len ];
  523. Q_strncpy(m_pszConfigName, configName, len );
  524. m_iConfigID = dialogID;
  525. // apply our user config settings (this will recurse through our children)
  526. if (data)
  527. {
  528. ApplyUserConfigSettings(data);
  529. }
  530. }
  531. //-----------------------------------------------------------------------------
  532. // Purpose: saves all the settings to the document
  533. //-----------------------------------------------------------------------------
  534. void EditablePanel::SaveUserConfig()
  535. {
  536. if (m_pszConfigName)
  537. {
  538. KeyValues *data = system()->GetUserConfigFileData(m_pszConfigName, m_iConfigID);
  539. // get our user config settings (this will recurse through our children)
  540. if (data)
  541. {
  542. GetUserConfigSettings(data);
  543. }
  544. }
  545. }
  546. //-----------------------------------------------------------------------------
  547. // Purpose: combines both of the above, LoadControlSettings & LoadUserConfig
  548. //-----------------------------------------------------------------------------
  549. void EditablePanel::LoadControlSettingsAndUserConfig(const char *dialogResourceName, int dialogID)
  550. {
  551. LoadControlSettings(dialogResourceName);
  552. LoadUserConfig(dialogResourceName, dialogID);
  553. }
  554. //-----------------------------------------------------------------------------
  555. // Purpose: applies the user config settings to all the children
  556. //-----------------------------------------------------------------------------
  557. void EditablePanel::ApplyUserConfigSettings(KeyValues *userConfig)
  558. {
  559. for (int i = 0; i < GetChildCount(); i++)
  560. {
  561. Panel *child = GetChild(i);
  562. if (child->HasUserConfigSettings())
  563. {
  564. const char *name = child->GetName();
  565. if (name && *name)
  566. {
  567. child->ApplyUserConfigSettings(userConfig->FindKey(name, true));
  568. }
  569. }
  570. }
  571. }
  572. //-----------------------------------------------------------------------------
  573. // Purpose: gets all the children's user config settings
  574. //-----------------------------------------------------------------------------
  575. void EditablePanel::GetUserConfigSettings(KeyValues *userConfig)
  576. {
  577. for (int i = 0; i < GetChildCount(); i++)
  578. {
  579. Panel *child = GetChild(i);
  580. if (child->HasUserConfigSettings())
  581. {
  582. const char *name = child->GetName();
  583. if (name && *name)
  584. {
  585. child->GetUserConfigSettings(userConfig->FindKey(name, true));
  586. }
  587. }
  588. }
  589. }
  590. //-----------------------------------------------------------------------------
  591. // Purpose: Save user config settings
  592. //-----------------------------------------------------------------------------
  593. void EditablePanel::OnClose()
  594. {
  595. SaveUserConfig();
  596. }
  597. //-----------------------------------------------------------------------------
  598. // Purpose: Handle information requests
  599. //-----------------------------------------------------------------------------
  600. bool EditablePanel::RequestInfo(KeyValues *data)
  601. {
  602. if (!stricmp(data->GetName(), "BuildDialog"))
  603. {
  604. // a build dialog is being requested, give it one
  605. // a bit hacky, but this is a case where vgui.dll needs to reach out
  606. data->SetPtr("PanelPtr", new BuildModeDialog( (BuildGroup *)data->GetPtr("BuildGroupPtr")));
  607. return true;
  608. }
  609. else if (!stricmp(data->GetName(), "ControlFactory"))
  610. {
  611. Panel *newPanel = CreateControlByName(data->GetString("ControlName"));
  612. if (newPanel)
  613. {
  614. data->SetPtr("PanelPtr", newPanel);
  615. return true;
  616. }
  617. }
  618. return BaseClass::RequestInfo(data);
  619. }
  620. //-----------------------------------------------------------------------------
  621. // Purpose: Return the buildgroup that this panel is part of.
  622. // Input :
  623. // Output : BuildGroup
  624. //-----------------------------------------------------------------------------
  625. BuildGroup *EditablePanel::GetBuildGroup()
  626. {
  627. return _buildGroup;
  628. }
  629. //-----------------------------------------------------------------------------
  630. // Purpose: Return a pointer to the nav group
  631. // Output : FocusNavGroup
  632. //-----------------------------------------------------------------------------
  633. FocusNavGroup &EditablePanel::GetFocusNavGroup()
  634. {
  635. return m_NavGroup;
  636. }
  637. //-----------------------------------------------------------------------------
  638. // Purpose:
  639. //-----------------------------------------------------------------------------
  640. bool EditablePanel::RequestFocusNext(VPANEL panel)
  641. {
  642. bool bRet = m_NavGroup.RequestFocusNext(panel);
  643. if ( IsPC() && !bRet && IsConsoleStylePanel() )
  644. {
  645. NavigateDown();
  646. }
  647. return bRet;
  648. }
  649. //-----------------------------------------------------------------------------
  650. // Purpose:
  651. //-----------------------------------------------------------------------------
  652. bool EditablePanel::RequestFocusPrev(VPANEL panel)
  653. {
  654. bool bRet = m_NavGroup.RequestFocusPrev(panel);
  655. if ( IsPC() && !bRet && IsConsoleStylePanel() )
  656. {
  657. NavigateUp();
  658. }
  659. return bRet;
  660. }
  661. //-----------------------------------------------------------------------------
  662. // Purpose: Delegates focus to a sub panel
  663. // Input : direction - the direction in which focus travelled to arrive at this panel; forward = 1, back = -1
  664. //-----------------------------------------------------------------------------
  665. void EditablePanel::RequestFocus(int direction)
  666. {
  667. // we must be a sub panel for this to be called
  668. // delegate focus
  669. if (direction == 1)
  670. {
  671. RequestFocusNext(NULL);
  672. }
  673. else if (direction == -1)
  674. {
  675. RequestFocusPrev(NULL);
  676. }
  677. else
  678. {
  679. BaseClass::RequestFocus();
  680. }
  681. }
  682. //-----------------------------------------------------------------------------
  683. // Purpose: Pass the focus down onto the last used panel
  684. //-----------------------------------------------------------------------------
  685. void EditablePanel::OnSetFocus()
  686. {
  687. Panel *focus = m_NavGroup.GetCurrentFocus();
  688. if (focus && focus != this)
  689. {
  690. focus->RequestFocus();
  691. }
  692. else
  693. {
  694. focus = m_NavGroup.GetDefaultPanel();
  695. if (focus)
  696. {
  697. focus->RequestFocus();
  698. focus->OnSetFocus();
  699. }
  700. }
  701. BaseClass::OnSetFocus();
  702. }
  703. //-----------------------------------------------------------------------------
  704. // Purpose: Called when the resource file is loaded to set up the panel state
  705. // Input : *inResourceData -
  706. //-----------------------------------------------------------------------------
  707. void EditablePanel::ApplySettings(KeyValues *inResourceData)
  708. {
  709. BaseClass::ApplySettings(inResourceData);
  710. _buildGroup->ApplySettings(inResourceData);
  711. m_bShouldSkipAutoResize = inResourceData->GetBool( "skip_autoresize", false );
  712. }
  713. //-----------------------------------------------------------------------------
  714. // Purpose: Update focus info for navigation
  715. //-----------------------------------------------------------------------------
  716. void EditablePanel::OnRequestFocus(VPANEL subFocus, VPANEL defaultPanel)
  717. {
  718. if (!ipanel()->IsPopup(subFocus))
  719. {
  720. defaultPanel = m_NavGroup.SetCurrentFocus(subFocus, defaultPanel);
  721. }
  722. BaseClass::OnRequestFocus(GetVPanel(), defaultPanel);
  723. }
  724. //-----------------------------------------------------------------------------
  725. // Purpose: Get the panel that currently has keyfocus
  726. //-----------------------------------------------------------------------------
  727. VPANEL EditablePanel::GetCurrentKeyFocus()
  728. {
  729. Panel *focus = m_NavGroup.GetCurrentFocus();
  730. if (focus == this)
  731. return NULL;
  732. if (focus)
  733. {
  734. if (focus->IsPopup())
  735. return BaseClass::GetCurrentKeyFocus();
  736. // chain down the editpanel hierarchy
  737. VPANEL subFocus = focus->GetCurrentKeyFocus();
  738. if (subFocus)
  739. return subFocus;
  740. // hit a leaf panel, return that
  741. return focus->GetVPanel();
  742. }
  743. return BaseClass::GetCurrentKeyFocus();
  744. }
  745. //-----------------------------------------------------------------------------
  746. // Purpose: Gets the panel with the specified hotkey
  747. //-----------------------------------------------------------------------------
  748. Panel *EditablePanel::HasHotkey(wchar_t key)
  749. {
  750. if( !IsVisible() || !IsEnabled()) // not visible, so can't respond to a hot key
  751. {
  752. return NULL;
  753. }
  754. for (int i = 0; i < GetChildCount(); i++)
  755. {
  756. Panel *hot = GetChild(i)->HasHotkey(key);
  757. if (hot && hot->IsVisible() && hot->IsEnabled())
  758. {
  759. return hot;
  760. }
  761. }
  762. return NULL;
  763. }
  764. //-----------------------------------------------------------------------------
  765. // Purpose: Shortcut function to setting enabled state of control
  766. //-----------------------------------------------------------------------------
  767. void EditablePanel::SetControlEnabled(const char *controlName, bool enabled)
  768. {
  769. Panel *control = FindChildByName(controlName);
  770. if (control)
  771. {
  772. control->SetEnabled(enabled);
  773. }
  774. }
  775. //-----------------------------------------------------------------------------
  776. // Purpose: Shortcut function to setting visibility state of control
  777. //-----------------------------------------------------------------------------
  778. void EditablePanel::SetControlVisible(const char *controlName, bool visible, bool bRecurseDown /*= false*/ )
  779. {
  780. Panel *control = FindChildByName(controlName, bRecurseDown);
  781. if (control)
  782. {
  783. control->SetVisible(visible);
  784. }
  785. }
  786. //-----------------------------------------------------------------------------
  787. // Purpose: Shortcut function to set data in child controls
  788. //-----------------------------------------------------------------------------
  789. void EditablePanel::SetControlString(const char *controlName, const char *string)
  790. {
  791. Panel *control = FindChildByName(controlName);
  792. if (control)
  793. {
  794. if (string[0] == '#')
  795. {
  796. const wchar_t *wszText = g_pVGuiLocalize->Find(string);
  797. if (wszText)
  798. {
  799. PostMessage(control, new KeyValues("SetText", "text", wszText));
  800. }
  801. }
  802. else
  803. {
  804. PostMessage(control, new KeyValues("SetText", "text", string));
  805. }
  806. }
  807. }
  808. //-----------------------------------------------------------------------------
  809. // Purpose: Shortcut function to set data in child controls
  810. //-----------------------------------------------------------------------------
  811. void EditablePanel::SetControlString(const char *controlName, const wchar_t *string)
  812. {
  813. Panel *control = FindChildByName(controlName);
  814. if (control)
  815. {
  816. PostMessage(control, new KeyValues("SetText", "text", string));
  817. }
  818. }
  819. //-----------------------------------------------------------------------------
  820. // Purpose: Shortcut function to set data in child controls
  821. //-----------------------------------------------------------------------------
  822. void EditablePanel::SetControlInt(const char *controlName, int state)
  823. {
  824. Panel *control = FindChildByName(controlName);
  825. if (control)
  826. {
  827. PostMessage(control, new KeyValues("SetState", "state", state));
  828. }
  829. }
  830. //-----------------------------------------------------------------------------
  831. // Purpose: Shortcut function to get data in child controls
  832. //-----------------------------------------------------------------------------
  833. int EditablePanel::GetControlInt(const char *controlName, int defaultState)
  834. {
  835. Panel *control = FindChildByName(controlName);
  836. if (control)
  837. {
  838. KeyValues *data = new KeyValues("GetState");
  839. if (control->RequestInfo(data))
  840. {
  841. int state = data->GetInt("state", defaultState);
  842. data->deleteThis();
  843. return state;
  844. }
  845. }
  846. return defaultState;
  847. }
  848. //-----------------------------------------------------------------------------
  849. // Purpose: Shortcut function to get data in child controls
  850. //-----------------------------------------------------------------------------
  851. const char *EditablePanel::GetControlString(const char *controlName, const char *defaultString)
  852. {
  853. static char buf[512];
  854. GetControlString(controlName, buf, sizeof(buf) - 1, defaultString);
  855. return buf;
  856. }
  857. //-----------------------------------------------------------------------------
  858. // Purpose: Shortcut function to get data in child controls
  859. //-----------------------------------------------------------------------------
  860. void EditablePanel::GetControlString(const char *controlName, char *buf, int bufSize, const char *defaultString)
  861. {
  862. Panel *control = FindChildByName(controlName);
  863. KeyValues *data = new KeyValues("GetText");
  864. if (control && control->RequestInfo(data))
  865. {
  866. Q_strncpy(buf, data->GetString("text", defaultString), bufSize);
  867. }
  868. else
  869. {
  870. // no value found, copy in default text
  871. Q_strncpy(buf, defaultString, bufSize);
  872. }
  873. // ensure null termination of string
  874. buf[bufSize - 1] = 0;
  875. // free
  876. data->deleteThis();
  877. }
  878. //-----------------------------------------------------------------------------
  879. // Purpose: localization variables (used in constructing UI strings)
  880. //-----------------------------------------------------------------------------
  881. void EditablePanel::SetDialogVariable(const char *varName, const char *value)
  882. {
  883. GetDialogVariables()->SetString(varName, value);
  884. ForceSubPanelsToUpdateWithNewDialogVariables();
  885. }
  886. //-----------------------------------------------------------------------------
  887. // Purpose: localization variables (used in constructing UI strings)
  888. //-----------------------------------------------------------------------------
  889. void EditablePanel::SetDialogVariable(const char *varName, const wchar_t *value)
  890. {
  891. GetDialogVariables()->SetWString(varName, value);
  892. ForceSubPanelsToUpdateWithNewDialogVariables();
  893. }
  894. //-----------------------------------------------------------------------------
  895. // Purpose: localization variables (used in constructing UI strings)
  896. //-----------------------------------------------------------------------------
  897. void EditablePanel::SetDialogVariable(const char *varName, int value)
  898. {
  899. GetDialogVariables()->SetInt(varName, value);
  900. ForceSubPanelsToUpdateWithNewDialogVariables();
  901. }
  902. //-----------------------------------------------------------------------------
  903. // Purpose: localization variables (used in constructing UI strings)
  904. //-----------------------------------------------------------------------------
  905. void EditablePanel::SetDialogVariable(const char *varName, float value)
  906. {
  907. GetDialogVariables()->SetFloat(varName, value);
  908. ForceSubPanelsToUpdateWithNewDialogVariables();
  909. }
  910. //-----------------------------------------------------------------------------
  911. // Purpose: redraws child panels with new localization vars
  912. //-----------------------------------------------------------------------------
  913. void EditablePanel::ForceSubPanelsToUpdateWithNewDialogVariables()
  914. {
  915. if (m_pDialogVariables)
  916. {
  917. ipanel()->SendMessage(GetVPanel(), m_pDialogVariables, GetVPanel());
  918. for (int i = 0; i < ipanel()->GetChildCount(GetVPanel()); i++)
  919. {
  920. ipanel()->SendMessage(ipanel()->GetChild(GetVPanel(), i), m_pDialogVariables, GetVPanel());
  921. }
  922. }
  923. }
  924. //-----------------------------------------------------------------------------
  925. // Purpose: lazy creation of localization vars object
  926. //-----------------------------------------------------------------------------
  927. KeyValues *EditablePanel::GetDialogVariables()
  928. {
  929. if (m_pDialogVariables)
  930. return m_pDialogVariables;
  931. m_pDialogVariables = new KeyValues("DialogVariables");
  932. return m_pDialogVariables;
  933. }
  934. //-----------------------------------------------------------------------------
  935. // Purpose: Virtual factory for control creation
  936. //-----------------------------------------------------------------------------
  937. Panel *EditablePanel::CreateControlByName(const char *controlName)
  938. {
  939. Panel *fromFactory = CBuildFactoryHelper::InstancePanel( controlName );
  940. if ( fromFactory )
  941. {
  942. return fromFactory;
  943. }
  944. return NULL;
  945. }