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.

2382 lines
69 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "ienginevgui.h"
  8. #include <vgui_controls/ScrollBarSlider.h>
  9. #include "vgui/ILocalize.h"
  10. #include "vgui/ISurface.h"
  11. #include "vgui/IInput.h"
  12. #include "econ_controls.h"
  13. #include "vgui_controls/TextImage.h"
  14. #include "vgui_controls/PropertyPage.h"
  15. #include "econ_item_system.h"
  16. #include "econ_item_tools.h"
  17. #include "iachievementmgr.h"
  18. #include "econ_item_description.h"
  19. #if defined(TF_DLL) || defined(TF_CLIENT_DLL)
  20. #include "tf_shareddefs.h"
  21. #endif
  22. using namespace vgui;
  23. DECLARE_BUILD_FACTORY_DEFAULT_TEXT( CExButton, CExButton );
  24. DECLARE_BUILD_FACTORY_DEFAULT_TEXT( CExImageButton, CExImageButton );
  25. DECLARE_BUILD_FACTORY_DEFAULT_TEXT( CExLabel, CExLabel );
  26. DECLARE_BUILD_FACTORY( CExRichText );
  27. DECLARE_BUILD_FACTORY( CRichTextWithScrollbarBorders );
  28. DECLARE_BUILD_FACTORY( CEconItemDetailsRichText );
  29. DECLARE_BUILD_FACTORY( CExplanationPopup );
  30. //-----------------------------------------------------------------------------
  31. // Purpose:
  32. //-----------------------------------------------------------------------------
  33. bool SetChildPanelVisible( vgui::Panel *pParent, const char *pChildName, bool bVisible, bool bSearchForChildRecursively )
  34. {
  35. vgui::Panel *pPanel = pParent->FindChildByName( pChildName, bSearchForChildRecursively );
  36. if ( pPanel )
  37. {
  38. if ( pPanel->IsVisible() != bVisible )
  39. {
  40. pPanel->SetVisible( bVisible );
  41. }
  42. return true;
  43. }
  44. return false;
  45. }
  46. //-----------------------------------------------------------------------------
  47. // Purpose:
  48. //-----------------------------------------------------------------------------
  49. bool SetChildPanelEnabled( vgui::Panel *pParent, const char *pChildName, bool bEnabled, bool bSearchForChildRecursively )
  50. {
  51. vgui::Panel *pPanel = pParent->FindChildByName( pChildName, bSearchForChildRecursively );
  52. if ( pPanel )
  53. {
  54. if ( pPanel->IsEnabled() != bEnabled )
  55. {
  56. pPanel->SetEnabled( bEnabled );
  57. }
  58. return true;
  59. }
  60. return false;
  61. }
  62. //-----------------------------------------------------------------------------
  63. // Purpose:
  64. //-----------------------------------------------------------------------------
  65. bool SetChildButtonSelected( vgui::Panel *pParent, const char *pChildName, bool bSelected, bool bSearchForChildRecursively )
  66. {
  67. vgui::Button *pPanel = dynamic_cast< vgui::Button* >( pParent->FindChildByName( pChildName, bSearchForChildRecursively ) );
  68. if ( pPanel )
  69. {
  70. if ( pPanel->IsSelected() != bSelected )
  71. {
  72. pPanel->SetSelected( bSelected );
  73. }
  74. return true;
  75. }
  76. return false;
  77. }
  78. //-----------------------------------------------------------------------------
  79. // Purpose:
  80. //-----------------------------------------------------------------------------
  81. bool IsChildButtonSelected( vgui::Panel *pParent, const char *pChildName, bool bSearchForChildRecursively )
  82. {
  83. vgui::Button *pPanel = dynamic_cast< vgui::Button* >( pParent->FindChildByName( pChildName, bSearchForChildRecursively ) );
  84. if ( pPanel )
  85. {
  86. return pPanel->IsSelected();
  87. }
  88. return false;
  89. }
  90. //-----------------------------------------------------------------------------
  91. // Purpose:
  92. //-----------------------------------------------------------------------------
  93. bool AddChildActionSignalTarget( vgui::Panel *pParent, const char *pChildName, Panel *messageTarget, bool bSearchForChildRecursively )
  94. {
  95. vgui::Panel *pPanel = pParent->FindChildByName( pChildName, bSearchForChildRecursively );
  96. if ( pPanel )
  97. {
  98. pPanel->AddActionSignalTarget( messageTarget );
  99. return true;
  100. }
  101. return false;
  102. }
  103. //-----------------------------------------------------------------------------
  104. // Purpose:
  105. //-----------------------------------------------------------------------------
  106. bool SetXToRed( vgui::Label *pPanel )
  107. {
  108. if ( !pPanel )
  109. return false;
  110. wchar_t wszConfirmText[256];
  111. pPanel->GetText( wszConfirmText, sizeof( wszConfirmText ) );
  112. if ( ( wszConfirmText[0] == L'x' || wszConfirmText[0] == L'X' ) && wszConfirmText[1] == L' ' )
  113. {
  114. pPanel->GetTextImage()->ClearColorChangeStream();
  115. pPanel->GetTextImage()->AddColorChange( Color(200,80,60,255), 0 );
  116. pPanel->GetTextImage()->AddColorChange( pPanel->GetFgColor(), 1 );
  117. return true;
  118. }
  119. return false;
  120. }
  121. //-----------------------------------------------------------------------------
  122. // Purpose:
  123. //-----------------------------------------------------------------------------
  124. CExButton::CExButton( Panel *parent, const char *name, const char *text, vgui::Panel *pActionSignalTarget, const char *cmd ) : Button( parent, name, text, pActionSignalTarget, cmd )
  125. {
  126. m_szFont[0] = '\0';
  127. m_szColor[0] = '\0';
  128. m_pArmedBorder = NULL;
  129. m_pDefaultBorderOverride = NULL;
  130. m_pSelectedBorder = NULL;
  131. m_pDisabledBorder = NULL;
  132. m_bbCursorEnterExitEvent = false;
  133. }
  134. //-----------------------------------------------------------------------------
  135. // Purpose:
  136. //-----------------------------------------------------------------------------
  137. CExButton::CExButton( Panel *parent, const char *name, const wchar_t *wszText, vgui::Panel *pActionSignalTarget, const char *cmd ) : Button( parent, name, wszText, pActionSignalTarget, cmd )
  138. {
  139. m_szFont[0] = '\0';
  140. m_szColor[0] = '\0';
  141. m_pArmedBorder = NULL;
  142. m_pDefaultBorderOverride = NULL;
  143. m_pSelectedBorder = NULL;
  144. m_pDisabledBorder = NULL;
  145. m_bbCursorEnterExitEvent = false;
  146. }
  147. //-----------------------------------------------------------------------------
  148. // Purpose:
  149. //-----------------------------------------------------------------------------
  150. void CExButton::ApplySettings( KeyValues *inResourceData )
  151. {
  152. BaseClass::ApplySettings( inResourceData );
  153. SetFontStr( inResourceData->GetString( "font", "Default" ) );
  154. SetColorStr( inResourceData->GetString( "fgcolor", "Button.TextColor" ) );
  155. IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
  156. const char *pszBorder = inResourceData->GetString( "border_default", "" );
  157. if ( *pszBorder )
  158. {
  159. m_pDefaultBorderOverride = pScheme->GetBorder( pszBorder );
  160. }
  161. pszBorder = inResourceData->GetString( "border_armed", "" );
  162. if ( *pszBorder )
  163. {
  164. m_pArmedBorder = pScheme->GetBorder( pszBorder );
  165. }
  166. pszBorder = inResourceData->GetString( "border_disabled", "" );
  167. if ( *pszBorder )
  168. {
  169. m_pDisabledBorder = pScheme->GetBorder( pszBorder );
  170. }
  171. const char *pszSelectedBorder = inResourceData->GetString( "border_selected", "" );
  172. if ( *pszSelectedBorder )
  173. {
  174. m_pSelectedBorder = pScheme->GetBorder( pszSelectedBorder );
  175. }
  176. }
  177. //-----------------------------------------------------------------------------
  178. // Purpose:
  179. //-----------------------------------------------------------------------------
  180. vgui::IBorder *CExButton::GetBorder(bool depressed, bool armed, bool selected, bool keyfocus)
  181. {
  182. if ( !IsEnabled() && m_pDisabledBorder )
  183. return m_pDisabledBorder;
  184. if ( selected && m_pSelectedBorder )
  185. return m_pSelectedBorder;
  186. if ( armed && m_pArmedBorder )
  187. return m_pArmedBorder;
  188. if ( m_pDefaultBorderOverride )
  189. return m_pDefaultBorderOverride;
  190. return BaseClass::GetBorder( depressed, armed, selected, keyfocus );
  191. }
  192. //-----------------------------------------------------------------------------
  193. // Purpose:
  194. //-----------------------------------------------------------------------------
  195. void CExButton::SetFontStr( const char *pFont )
  196. {
  197. V_strcpy_safe( m_szFont, pFont );
  198. IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
  199. SetFont( pScheme->GetFont( m_szFont, true ) );
  200. }
  201. //-----------------------------------------------------------------------------
  202. // Purpose:
  203. //-----------------------------------------------------------------------------
  204. void CExButton::SetColorStr( const char *pColor )
  205. {
  206. V_strcpy_safe( m_szColor, pColor );
  207. IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
  208. SetFgColor( pScheme->GetColor( m_szColor, Color( 255, 255, 255, 255 ) ) );
  209. }
  210. //-----------------------------------------------------------------------------
  211. // Purpose:
  212. //-----------------------------------------------------------------------------
  213. void CExButton::OnMouseFocusTicked()
  214. {
  215. BaseClass::OnMouseFocusTicked();
  216. if ( m_hMouseTickTarget )
  217. {
  218. KeyValues *pMessage = new KeyValues("MouseFocusTicked");
  219. vgui::ipanel()->SendMessage( m_hMouseTickTarget, pMessage, GetVPanel());
  220. pMessage->deleteThis();
  221. }
  222. }
  223. //-----------------------------------------------------------------------------
  224. // Purpose:
  225. //-----------------------------------------------------------------------------
  226. void CExButton::OnCursorEntered()
  227. {
  228. BaseClass::OnCursorEntered();
  229. if ( m_hMouseTickTarget && m_bbCursorEnterExitEvent )
  230. {
  231. KeyValues *pMessage = new KeyValues("CursorEntered");
  232. vgui::ipanel()->SendMessage( m_hMouseTickTarget, pMessage, GetVPanel());
  233. pMessage->deleteThis();
  234. }
  235. }
  236. //-----------------------------------------------------------------------------
  237. // Purpose:
  238. //-----------------------------------------------------------------------------
  239. void CExButton::OnCursorExited()
  240. {
  241. BaseClass::OnCursorExited();
  242. if ( m_hMouseTickTarget && m_bbCursorEnterExitEvent )
  243. {
  244. KeyValues *pMessage = new KeyValues("CursorExited");
  245. vgui::ipanel()->SendMessage( m_hMouseTickTarget, pMessage, GetVPanel());
  246. pMessage->deleteThis();
  247. }
  248. }
  249. //-----------------------------------------------------------------------------
  250. // Purpose:
  251. //-----------------------------------------------------------------------------
  252. CExImageButton::CExImageButton( Panel *parent, const char *name, const char *text, vgui::Panel *pActionSignalTarget, const char *cmd ) : CExButton( parent, name, text, pActionSignalTarget, cmd )
  253. {
  254. m_ImageDrawColor = Color(255,255,255,255);
  255. m_ImageArmedColor = Color(255,255,255,255);
  256. m_ImageDepressedColor = Color(255,255,255,255);
  257. m_ImageDisabledColor = Color(255,255,255,255);
  258. m_ImageSelectedColor = Color(255,255,255,255);
  259. m_pEmbeddedImagePanel = new vgui::ImagePanel( this, "SubImage" );
  260. m_szImageDefault[0] = '\0';
  261. m_szImageArmed[0] = '\0';
  262. m_szImageSelected[0] = '\0';
  263. }
  264. //-----------------------------------------------------------------------------
  265. // Purpose:
  266. //-----------------------------------------------------------------------------
  267. CExImageButton::CExImageButton( Panel *parent, const char *name, const wchar_t *wszText, vgui::Panel *pActionSignalTarget, const char *cmd ) : CExButton( parent, name, wszText, pActionSignalTarget, cmd )
  268. {
  269. m_ImageDrawColor = Color(255,255,255,255);
  270. m_ImageArmedColor = Color(255,255,255,255);
  271. m_ImageDepressedColor = Color(255,255,255,255);
  272. m_ImageDisabledColor = Color(255,255,255,255);
  273. m_ImageSelectedColor = Color(255,255,255,255);
  274. m_pEmbeddedImagePanel = new vgui::ImagePanel( this, "SubImage" );
  275. m_szImageDefault[0] = '\0';
  276. m_szImageArmed[0] = '\0';
  277. m_szImageSelected[0] = '\0';
  278. }
  279. //-----------------------------------------------------------------------------
  280. // Purpose:
  281. //-----------------------------------------------------------------------------
  282. CExImageButton::~CExImageButton( void )
  283. {
  284. m_pEmbeddedImagePanel->MarkForDeletion();
  285. m_pEmbeddedImagePanel = 0;
  286. }
  287. //-----------------------------------------------------------------------------
  288. // Purpose:
  289. //-----------------------------------------------------------------------------
  290. void CExImageButton::ApplySettings( KeyValues *inResourceData )
  291. {
  292. BaseClass::ApplySettings( inResourceData );
  293. int r,g,b,a;
  294. const char *pszDrawColor = inResourceData->GetString("image_drawcolor", "");
  295. if (*pszDrawColor)
  296. {
  297. if (sscanf(pszDrawColor, "%d %d %d %d", &r, &g, &b, &a) >= 3)
  298. {
  299. m_ImageDrawColor = Color(r, g, b, a);
  300. }
  301. }
  302. pszDrawColor = inResourceData->GetString("image_armedcolor", "");
  303. if (*pszDrawColor)
  304. {
  305. if (sscanf(pszDrawColor, "%d %d %d %d", &r, &g, &b, &a) >= 3)
  306. {
  307. m_ImageArmedColor = Color(r, g, b, a);
  308. }
  309. }
  310. pszDrawColor = inResourceData->GetString("image_depressedcolor", "");
  311. if (*pszDrawColor)
  312. {
  313. if (sscanf(pszDrawColor, "%d %d %d %d", &r, &g, &b, &a) >= 3)
  314. {
  315. m_ImageDepressedColor = Color(r, g, b, a);
  316. }
  317. }
  318. pszDrawColor = inResourceData->GetString("image_disabledcolor", "");
  319. if (*pszDrawColor)
  320. {
  321. if (sscanf(pszDrawColor, "%d %d %d %d", &r, &g, &b, &a) >= 3)
  322. {
  323. m_ImageDisabledColor = Color(r, g, b, a);
  324. }
  325. }
  326. pszDrawColor = inResourceData->GetString( "image_selectedcolor", "" );
  327. if (*pszDrawColor)
  328. {
  329. if (sscanf(pszDrawColor, "%d %d %d %d", &r, &g, &b, &a) >= 3)
  330. {
  331. m_ImageSelectedColor = Color(r, g, b, a);
  332. }
  333. }
  334. KeyValues *pButtonKV = inResourceData->FindKey( "SubImage" );
  335. if ( pButtonKV )
  336. {
  337. m_pEmbeddedImagePanel->ApplySettings( pButtonKV );
  338. }
  339. const char *pszImageDefault = inResourceData->GetString("image_default", "");
  340. if (*pszImageDefault)
  341. {
  342. SetImageDefault( pszImageDefault );
  343. }
  344. const char *pszImageArmed = inResourceData->GetString("image_armed", "");
  345. if (*pszImageArmed)
  346. {
  347. SetImageArmed( pszImageArmed );
  348. }
  349. const char *pszImageSelected = inResourceData->GetString("image_selected", "");
  350. if (*pszImageSelected)
  351. {
  352. SetImageSelected( pszImageSelected );
  353. }
  354. }
  355. //-----------------------------------------------------------------------------
  356. // Purpose:
  357. //-----------------------------------------------------------------------------
  358. Color CExImageButton::GetImageColor( void )
  359. {
  360. if ( !IsEnabled() )
  361. return m_ImageDisabledColor;
  362. if ( IsSelected() )
  363. return m_ImageSelectedColor;
  364. if ( IsDepressed() )
  365. return m_ImageDepressedColor;
  366. if ( IsArmed() )
  367. return m_ImageArmedColor;
  368. return m_ImageDrawColor;
  369. }
  370. //-----------------------------------------------------------------------------
  371. // Purpose:
  372. //-----------------------------------------------------------------------------
  373. void CExImageButton::ApplySchemeSettings( IScheme *pScheme )
  374. {
  375. BaseClass::ApplySchemeSettings( pScheme );
  376. m_pEmbeddedImagePanel->SetMouseInputEnabled( false );
  377. m_pEmbeddedImagePanel->SetDrawColor( GetImageColor() );
  378. }
  379. //-----------------------------------------------------------------------------
  380. // Purpose:
  381. //-----------------------------------------------------------------------------
  382. void CExImageButton::SetArmed(bool state)
  383. {
  384. BaseClass::SetArmed( state );
  385. if ( m_pEmbeddedImagePanel )
  386. {
  387. m_pEmbeddedImagePanel->SetDrawColor( GetImageColor() );
  388. const char *pszImage = state ? m_szImageArmed : m_szImageDefault;
  389. if ( *pszImage )
  390. {
  391. SetSubImage( pszImage );
  392. }
  393. }
  394. }
  395. //-----------------------------------------------------------------------------
  396. // Purpose:
  397. //-----------------------------------------------------------------------------
  398. void CExImageButton::SetEnabled(bool state)
  399. {
  400. BaseClass::SetEnabled( state );
  401. if ( m_pEmbeddedImagePanel )
  402. {
  403. m_pEmbeddedImagePanel->SetDrawColor( GetImageColor() );
  404. }
  405. }
  406. //-----------------------------------------------------------------------------
  407. // Purpose:
  408. //-----------------------------------------------------------------------------
  409. void CExImageButton::SetSelected(bool state)
  410. {
  411. BaseClass::SetSelected( state );
  412. if ( m_pEmbeddedImagePanel )
  413. {
  414. m_pEmbeddedImagePanel->SetDrawColor( GetImageColor() );
  415. const char *pszImage = state ? m_szImageSelected : m_szImageDefault;
  416. if ( *pszImage )
  417. {
  418. SetSubImage( pszImage );
  419. }
  420. }
  421. }
  422. //-----------------------------------------------------------------------------
  423. // Purpose:
  424. //-----------------------------------------------------------------------------
  425. void CExImageButton::SetSubImage( const char *pszImage )
  426. {
  427. m_pEmbeddedImagePanel->SetImage( pszImage );
  428. }
  429. //-----------------------------------------------------------------------------
  430. // Purpose:
  431. //-----------------------------------------------------------------------------
  432. void CExImageButton::SetImageDefault( const char *pszImageDefault )
  433. {
  434. V_strcpy_safe( m_szImageDefault, pszImageDefault );
  435. if ( !IsArmed() )
  436. {
  437. SetSubImage( pszImageDefault );
  438. }
  439. }
  440. //-----------------------------------------------------------------------------
  441. // Purpose:
  442. //-----------------------------------------------------------------------------
  443. void CExImageButton::SetImageArmed( const char *pszImageArmed )
  444. {
  445. V_strcpy_safe( m_szImageArmed, pszImageArmed );
  446. if ( IsArmed() )
  447. {
  448. SetSubImage( m_szImageArmed );
  449. }
  450. }
  451. //-----------------------------------------------------------------------------
  452. // Purpose:
  453. //-----------------------------------------------------------------------------
  454. void CExImageButton::SetImageSelected( const char *pszImageSelected )
  455. {
  456. V_strcpy_safe( m_szImageSelected, pszImageSelected );
  457. if ( IsSelected() )
  458. {
  459. SetSubImage( m_szImageSelected );
  460. }
  461. }
  462. //-----------------------------------------------------------------------------
  463. // Purpose:
  464. //-----------------------------------------------------------------------------
  465. CExLabel::CExLabel( Panel *parent, const char *name, const char *text ) : Label( parent, name, text )
  466. {
  467. m_szColor[0] = '\0';
  468. }
  469. //-----------------------------------------------------------------------------
  470. // Purpose:
  471. //-----------------------------------------------------------------------------
  472. CExLabel::CExLabel( Panel *parent, const char *name, const wchar_t *wszText ) : Label( parent, name, wszText )
  473. {
  474. m_szColor[0] = '\0';
  475. }
  476. //-----------------------------------------------------------------------------
  477. // Purpose:
  478. //-----------------------------------------------------------------------------
  479. void CExLabel::ApplySettings( KeyValues *inResourceData )
  480. {
  481. BaseClass::ApplySettings( inResourceData );
  482. SetColorStr( inResourceData->GetString( "fgcolor", "Label.TextColor" ) );
  483. }
  484. //-----------------------------------------------------------------------------
  485. // Purpose:
  486. //-----------------------------------------------------------------------------
  487. void CExLabel::ApplySchemeSettings( IScheme *pScheme )
  488. {
  489. BaseClass::ApplySchemeSettings( pScheme );
  490. // Reapply our custom color, so we stomp the base scheme's
  491. SetColorStr( m_szColor );
  492. }
  493. //-----------------------------------------------------------------------------
  494. // Purpose:
  495. //-----------------------------------------------------------------------------
  496. void CExLabel::SetColorStr( const char *pColor )
  497. {
  498. IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
  499. SetColorStr( pScheme->GetColor( pColor, Color( 0, 255, 0, 255 ) ) );
  500. }
  501. //-----------------------------------------------------------------------------
  502. // Purpose:
  503. //-----------------------------------------------------------------------------
  504. void CExLabel::SetColorStr( Color cColor )
  505. {
  506. Q_snprintf( m_szColor, ARRAYSIZE(m_szColor), "%d %d %d %d", cColor.r(), cColor.g(), cColor.b(), cColor.a() );
  507. SetFgColor( cColor );
  508. }
  509. //-----------------------------------------------------------------------------
  510. // Purpose:
  511. //-----------------------------------------------------------------------------
  512. CExRichText::CExRichText( Panel *parent, const char *name ) : RichText( parent, name )
  513. {
  514. m_szFont[0] = '\0';
  515. m_szColor[0] = '\0';
  516. m_szImageUpArrow[0] = '\0';
  517. m_szImageDownArrow[0] = '\0';
  518. m_szImageLine[0] = '\0';
  519. m_szImageBox[0] = '\0';
  520. m_bUseImageBorders = false;
  521. m_pBox = NULL;
  522. m_pLine = NULL;
  523. SetCursor(dc_arrow);
  524. m_pUpArrow = new CExImageButton( this, "UpArrow", "" );
  525. if ( m_pUpArrow )
  526. {
  527. m_pUpArrow->AddActionSignalTarget( _vertScrollBar );
  528. m_pUpArrow->SetCommand(new KeyValues("ScrollButtonPressed", "index", 0));
  529. m_pUpArrow->GetImage()->SetShouldScaleImage( true );
  530. m_pUpArrow->SetFgColor( Color( 255, 255, 255, 255 ) );
  531. m_pUpArrow->SetAlpha( 255 );
  532. m_pUpArrow->SetPaintBackgroundEnabled( false );
  533. m_pUpArrow->SetVisible( false );
  534. }
  535. m_pDownArrow = new CExImageButton( this, "DownArrow", "" );
  536. if ( m_pDownArrow )
  537. {
  538. m_pDownArrow->AddActionSignalTarget( _vertScrollBar );
  539. m_pDownArrow->SetCommand(new KeyValues("ScrollButtonPressed", "index", 1));
  540. m_pDownArrow->GetImage()->SetShouldScaleImage( true );
  541. m_pDownArrow->SetFgColor( Color( 255, 255, 255, 255 ) );
  542. m_pDownArrow->SetAlpha( 255 );
  543. m_pDownArrow->SetPaintBackgroundEnabled( false );
  544. m_pDownArrow->SetVisible( false );
  545. }
  546. _vertScrollBar->SetOverriddenButtons( m_pUpArrow, m_pDownArrow );
  547. m_pUpArrow->PassMouseTicksTo( _vertScrollBar );
  548. m_pDownArrow->PassMouseTicksTo( _vertScrollBar );
  549. vgui::ivgui()->AddTickSignal( GetVPanel() );
  550. }
  551. //-----------------------------------------------------------------------------
  552. // Purpose:
  553. //-----------------------------------------------------------------------------
  554. void CExRichText::CreateImagePanels( void )
  555. {
  556. if ( m_pBox || m_pLine )
  557. return;
  558. if ( m_bUseImageBorders )
  559. {
  560. m_pLine = new vgui::Panel( this, "Line" );
  561. m_pBox = new vgui::Panel( this, "Box" );
  562. }
  563. else
  564. {
  565. m_pLine = new vgui::ImagePanel( this, "Line" );
  566. m_pBox = new vgui::ImagePanel( this, "Box" );
  567. dynamic_cast<vgui::ImagePanel *>(m_pBox)->SetShouldScaleImage( true );
  568. dynamic_cast<vgui::ImagePanel *>(m_pLine)->SetShouldScaleImage( true );
  569. }
  570. m_pBox->SetVisible( false );
  571. m_pLine->SetVisible( false );
  572. }
  573. //-----------------------------------------------------------------------------
  574. // Purpose:
  575. //-----------------------------------------------------------------------------
  576. void CExRichText::ApplySettings( KeyValues *inResourceData )
  577. {
  578. BaseClass::ApplySettings( inResourceData );
  579. SetFontStr( inResourceData->GetString( "font", "Default" ) );
  580. SetColorStr( inResourceData->GetString( "fgcolor", "RichText.TextColor" ) );
  581. SetCustomImage( m_pUpArrow->GetImage(), inResourceData->GetString( "image_up_arrow", "chalkboard_scroll_up" ), m_szImageUpArrow );
  582. SetCustomImage( m_pDownArrow->GetImage(), inResourceData->GetString( "image_down_arrow", "chalkboard_scroll_down" ), m_szImageDownArrow );
  583. SetCustomImage( m_pLine, inResourceData->GetString( "image_line", "chalkboard_scroll_line" ), m_szImageLine );
  584. SetCustomImage( m_pBox, inResourceData->GetString( "image_box", "chalkboard_scroll_box" ), m_szImageBox );
  585. const char *pszMouseover = inResourceData->GetString( "image_up_arrow_mouseover", NULL );
  586. if ( pszMouseover )
  587. {
  588. m_pUpArrow->SetImageArmed( pszMouseover );
  589. m_pUpArrow->SetImageDefault( m_szImageUpArrow );
  590. }
  591. pszMouseover = inResourceData->GetString( "image_down_arrow_mouseover", NULL );
  592. if ( pszMouseover )
  593. {
  594. m_pDownArrow->SetImageArmed( pszMouseover );
  595. m_pDownArrow->SetImageDefault( m_szImageDownArrow );
  596. }
  597. }
  598. //-----------------------------------------------------------------------------
  599. // Purpose:
  600. //-----------------------------------------------------------------------------
  601. void CExRichText::SetFontStr( const char *pFont )
  602. {
  603. if ( pFont != m_szFont )
  604. {
  605. V_strcpy_safe( m_szFont, pFont );
  606. }
  607. IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
  608. SetFont( pScheme->GetFont( m_szFont, true ) );
  609. }
  610. //-----------------------------------------------------------------------------
  611. // Purpose:
  612. //-----------------------------------------------------------------------------
  613. void CExRichText::SetColorStr( const char *pColor )
  614. {
  615. if ( pColor != m_szColor )
  616. {
  617. V_strcpy_safe( m_szColor, pColor );
  618. }
  619. IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
  620. SetFgColor( pScheme->GetColor( m_szColor, Color( 255, 255, 255, 255 ) ) );
  621. }
  622. //-----------------------------------------------------------------------------
  623. // Purpose:
  624. //-----------------------------------------------------------------------------
  625. void CExRichText::SetCustomImage( vgui::Panel *pImage, const char *pszImage, char *pszStorage )
  626. {
  627. if ( pszStorage )
  628. {
  629. V_strcpy( pszStorage, pszImage );
  630. }
  631. if ( !pImage )
  632. return;
  633. if ( m_bUseImageBorders )
  634. {
  635. vgui::IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
  636. IBorder *pBorder = pScheme->GetBorder( pszImage );
  637. if ( pBorder )
  638. {
  639. pImage->SetBorder( pBorder );
  640. return;
  641. }
  642. }
  643. vgui::ImagePanel *pImagePanel = dynamic_cast<vgui::ImagePanel *>(pImage);
  644. if ( pImagePanel )
  645. {
  646. pImagePanel->SetImage( pszImage );
  647. }
  648. }
  649. //-----------------------------------------------------------------------------
  650. // Purpose:
  651. //-----------------------------------------------------------------------------
  652. void CExRichText::ApplySchemeSettings( IScheme *pScheme )
  653. {
  654. CreateImagePanels();
  655. BaseClass::ApplySchemeSettings( pScheme );
  656. // Reapply any custom font/color, so we stomp the base scheme's
  657. SetFontStr( m_szFont );
  658. SetColorStr( m_szColor );
  659. SetCustomImage( m_pUpArrow->GetImage(), m_szImageUpArrow, NULL );
  660. SetCustomImage( m_pDownArrow->GetImage(), m_szImageDownArrow, NULL );
  661. SetCustomImage( m_pLine, m_szImageLine, NULL );
  662. SetCustomImage( m_pBox, m_szImageBox, NULL );
  663. SetBorder( pScheme->GetBorder( "NoBorder" ) );
  664. SetBgColor( pScheme->GetColor( "Blank", Color( 0,0,0,0 ) ) );
  665. SetPanelInteractive( false );
  666. SetUnusedScrollbarInvisible( true );
  667. if ( m_pDownArrow )
  668. {
  669. m_pDownArrow->SetFgColor( Color( 255, 255, 255, 255 ) );
  670. }
  671. if ( m_pUpArrow )
  672. {
  673. m_pUpArrow->SetFgColor( Color( 255, 255, 255, 255 ) );
  674. }
  675. SetScrollBarImagesVisible( false );
  676. }
  677. //-----------------------------------------------------------------------------
  678. // Purpose:
  679. //-----------------------------------------------------------------------------
  680. void CExRichText::PerformLayout()
  681. {
  682. BaseClass::PerformLayout();
  683. if ( _vertScrollBar )
  684. {
  685. _vertScrollBar->SetZPos( 500 );
  686. m_pUpArrow->SetZPos( 501 );
  687. m_pDownArrow->SetZPos( 501 );
  688. // turn off painting the vertical scrollbar
  689. _vertScrollBar->SetPaintBackgroundEnabled( false );
  690. _vertScrollBar->SetPaintBorderEnabled( false );
  691. _vertScrollBar->SetPaintEnabled( false );
  692. _vertScrollBar->SetScrollbarButtonsVisible( false );
  693. _vertScrollBar->GetButton(0)->SetMouseInputEnabled( false );
  694. _vertScrollBar->GetButton(1)->SetMouseInputEnabled( false );
  695. if ( _vertScrollBar->IsVisible() )
  696. {
  697. int nMin, nMax;
  698. _vertScrollBar->GetRange( nMin, nMax );
  699. _vertScrollBar->SetValue( nMin );
  700. int nScrollbarWide = _vertScrollBar->GetWide();
  701. int wide, tall;
  702. GetSize( wide, tall );
  703. if ( m_pUpArrow )
  704. {
  705. m_pUpArrow->SetBounds( wide - nScrollbarWide, 0, nScrollbarWide, nScrollbarWide );
  706. m_pUpArrow->GetImage()->SetSize( nScrollbarWide, nScrollbarWide );
  707. }
  708. if ( m_pLine )
  709. {
  710. m_pLine->SetBounds( wide - nScrollbarWide, nScrollbarWide, nScrollbarWide, tall - ( 2 * nScrollbarWide ) );
  711. }
  712. if ( m_pBox )
  713. {
  714. m_pBox->SetBounds( wide - nScrollbarWide, nScrollbarWide, nScrollbarWide, nScrollbarWide );
  715. }
  716. if ( m_pDownArrow )
  717. {
  718. m_pDownArrow->SetBounds( wide - nScrollbarWide, tall - nScrollbarWide, nScrollbarWide, nScrollbarWide );
  719. m_pDownArrow->GetImage()->SetSize( nScrollbarWide, nScrollbarWide );
  720. }
  721. SetScrollBarImagesVisible( false );
  722. }
  723. }
  724. }
  725. //-----------------------------------------------------------------------------
  726. // Purpose:
  727. //-----------------------------------------------------------------------------
  728. void CExRichText::SetText( const wchar_t *text )
  729. {
  730. wchar_t buffer[2048];
  731. Q_wcsncpy( buffer, text, sizeof( buffer ) );
  732. // transform '\r' to ' ' to eliminate double-spacing on line returns
  733. for ( wchar_t *ch = buffer; *ch != 0; ch++ )
  734. {
  735. if ( *ch == '\r' )
  736. {
  737. *ch = ' ';
  738. }
  739. }
  740. BaseClass::SetText( buffer );
  741. }
  742. //-----------------------------------------------------------------------------
  743. // Purpose:
  744. //-----------------------------------------------------------------------------
  745. void CExRichText::SetText( const char *text )
  746. {
  747. char buffer[2048];
  748. Q_strncpy( buffer, text, sizeof( buffer ) );
  749. // transform '\r' to ' ' to eliminate double-spacing on line returns
  750. for ( char *ch = buffer; *ch != 0; ch++ )
  751. {
  752. if ( *ch == '\r' )
  753. {
  754. *ch = ' ';
  755. }
  756. }
  757. BaseClass::SetText( buffer );
  758. }
  759. //-----------------------------------------------------------------------------
  760. // Purpose:
  761. //-----------------------------------------------------------------------------
  762. void CExRichText::SetScrollBarImagesVisible( bool visible )
  763. {
  764. if ( m_pDownArrow && m_pDownArrow->IsVisible() != visible )
  765. {
  766. m_pDownArrow->SetVisible( visible );
  767. m_pDownArrow->SetEnabled( visible );
  768. }
  769. if ( m_pUpArrow && m_pUpArrow->IsVisible() != visible )
  770. {
  771. m_pUpArrow->SetVisible( visible );
  772. m_pUpArrow->SetEnabled( visible );
  773. }
  774. if ( m_pLine && m_pLine->IsVisible() != visible )
  775. {
  776. m_pLine->SetVisible( visible );
  777. }
  778. if ( m_pBox && m_pBox->IsVisible() != visible )
  779. {
  780. m_pBox->SetVisible( visible );
  781. }
  782. }
  783. //-----------------------------------------------------------------------------
  784. // Purpose:
  785. //-----------------------------------------------------------------------------
  786. void CExRichText::OnTick()
  787. {
  788. if ( !IsVisible() )
  789. return;
  790. if ( m_pDownArrow && m_pUpArrow && m_pLine && m_pBox )
  791. {
  792. if ( _vertScrollBar && _vertScrollBar->IsVisible() )
  793. {
  794. // turn on our own images
  795. SetScrollBarImagesVisible ( true );
  796. // set the alpha on the up arrow
  797. int nMin, nMax;
  798. _vertScrollBar->GetRange( nMin, nMax );
  799. int nScrollPos = _vertScrollBar->GetValue();
  800. int nRangeWindow = _vertScrollBar->GetRangeWindow();
  801. int nBottom = nMax - nRangeWindow;
  802. if ( nBottom < 0 )
  803. {
  804. nBottom = 0;
  805. }
  806. // set the alpha on the up arrow
  807. int nAlpha = ( nScrollPos - nMin <= 0 ) ? 90 : 255;
  808. m_pUpArrow->SetAlpha( nAlpha );
  809. // set the alpha on the down arrow
  810. nAlpha = ( nScrollPos >= nBottom ) ? 90 : 255;
  811. m_pDownArrow->SetAlpha( nAlpha );
  812. ScrollBarSlider *pSlider = _vertScrollBar->GetSlider();
  813. if ( pSlider && pSlider->GetRangeWindow() > 0 )
  814. {
  815. int x, y, w, t, min, max;
  816. m_pLine->GetBounds( x, y, w, t );
  817. pSlider->GetNobPos( min, max );
  818. m_pBox->SetBounds( x, y + min, w, ( max - min ) );
  819. }
  820. }
  821. else
  822. {
  823. // turn off our images
  824. SetScrollBarImagesVisible ( false );
  825. }
  826. }
  827. }
  828. //-----------------------------------------------------------------------------
  829. // Purpose: Rich text control that knows how to fill itself with information
  830. // that describes a specific item definition.
  831. //-----------------------------------------------------------------------------
  832. CEconItemDetailsRichText::CEconItemDetailsRichText( vgui::Panel *parent, const char *panelName )
  833. : BaseClass( parent, panelName ),
  834. m_bAllowItemSetLinks( false ),
  835. m_bLimitedItem( false ),
  836. m_hLinkFont( INVALID_FONT )
  837. {
  838. }
  839. //-----------------------------------------------------------------------------
  840. // Purpose:
  841. //-----------------------------------------------------------------------------
  842. void CEconItemDetailsRichText::ApplySettings( KeyValues *inResourceData )
  843. {
  844. BaseClass::ApplySettings( inResourceData );
  845. const char *pszHighlightColor = inResourceData->GetString( "highlight_color", "Orange" );
  846. const char *pszItemSetColor = inResourceData->GetString( "itemset_color", "Blue" );
  847. const char *pszLinkColor = inResourceData->GetString( "link_color", "LightOrange" );
  848. IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
  849. m_colTextHighlight = pScheme->GetColor( pszHighlightColor, Color( 255, 255, 255, 255 ) );
  850. m_colItemSet = pScheme->GetColor( pszItemSetColor, Color( 255, 255, 255, 255 ) );
  851. m_colLink = pScheme->GetColor( pszLinkColor, Color( 255, 255, 255, 255 ) );
  852. m_hLinkFont = pScheme->GetFont( "Link", true );
  853. }
  854. //-----------------------------------------------------------------------------
  855. // Purpose:
  856. //-----------------------------------------------------------------------------
  857. void CEconItemDetailsRichText::ApplySchemeSettings( vgui::IScheme *pScheme )
  858. {
  859. BaseClass::ApplySchemeSettings( pScheme );
  860. SetUnderlineFont( m_hLinkFont );
  861. }
  862. //-----------------------------------------------------------------------------
  863. // Purpose:
  864. //-----------------------------------------------------------------------------
  865. void CEconItemDetailsRichText::UpdateDetailsForItem( const CEconItemDefinition *pDef )
  866. {
  867. SetText( "" );
  868. if ( !m_ToolList.Count() )
  869. {
  870. UpdateToolList();
  871. }
  872. DataText_AppendStoreFlags( pDef );
  873. DataText_AppendItemData( pDef );
  874. DataText_AppendAttributeData( pDef );
  875. DataText_AppendUsageData( pDef );
  876. DataText_AppendToolUsage( pDef );
  877. }
  878. //-----------------------------------------------------------------------------
  879. // Purpose:
  880. //-----------------------------------------------------------------------------
  881. void CEconItemDetailsRichText::AddDataText( const char *pszText, bool bAddPostLines, const wchar_t *wpszArg, const wchar_t *wpszArg2, const int *pItemDefIndex )
  882. {
  883. static wchar_t wszConstructedString[4096];
  884. static wchar_t wszText[4096];
  885. if ( pszText[0] != '#' )
  886. {
  887. InsertString( pszText );
  888. return;
  889. }
  890. wchar_t *pLocText = g_pVGuiLocalize->Find( pszText );
  891. if ( wpszArg && pLocText )
  892. {
  893. if ( wpszArg2 )
  894. {
  895. g_pVGuiLocalize->ConstructString_safe( wszConstructedString, pLocText, 2, wpszArg, wpszArg2 );
  896. }
  897. else
  898. {
  899. g_pVGuiLocalize->ConstructString_safe( wszConstructedString, pLocText, 1, wpszArg );
  900. }
  901. pLocText = wszConstructedString;
  902. }
  903. if ( pLocText )
  904. {
  905. enum
  906. {
  907. STATE_COLOR_NORMAL = 1,
  908. STATE_COLOR_HINT,
  909. STATE_COLOR_ITEMSET,
  910. STATE_LINK_START,
  911. STATE_LINK_STOP,
  912. };
  913. Color color = GetFgColor();
  914. Color newColor = color;
  915. int startIdx = 0;
  916. int endIdx = 0;
  917. bool bContinue = true;
  918. bool bInLink = false;
  919. while ( bContinue )
  920. {
  921. bool bSetText = false;
  922. bool bEnd = false;
  923. switch ( pLocText[endIdx] )
  924. {
  925. case 0:
  926. bContinue = false;
  927. bSetText = true;
  928. bEnd = true;
  929. break;
  930. case STATE_COLOR_NORMAL:
  931. newColor = GetFgColor();
  932. bSetText = true;
  933. break;
  934. case STATE_COLOR_HINT:
  935. newColor = m_colTextHighlight;
  936. bSetText = true;
  937. break;
  938. case STATE_COLOR_ITEMSET:
  939. newColor = m_colItemSet;
  940. bSetText = true;
  941. break;
  942. case STATE_LINK_START:
  943. bInLink = true;
  944. break;
  945. }
  946. if ( startIdx != endIdx )
  947. {
  948. if ( bSetText )
  949. {
  950. // copy the colored text to wide
  951. int len = endIdx - startIdx + 1;
  952. wcsncpy( wszText, pLocText + startIdx, len );
  953. wszText[len-1] = 0;
  954. // If the next character isn't the end of a link, insert the string
  955. if ( bInLink && pItemDefIndex )
  956. {
  957. InsertItemLink( wszText, *pItemDefIndex, &color );
  958. }
  959. else
  960. {
  961. InsertColorChange( color );
  962. InsertString( wszText );
  963. }
  964. bInLink = false;
  965. color = newColor;
  966. // skip past the color change character
  967. startIdx = endIdx + 1;
  968. }
  969. }
  970. ++endIdx;
  971. }
  972. if ( bAddPostLines )
  973. {
  974. InsertString( L"\n\n" );
  975. }
  976. }
  977. }
  978. //-----------------------------------------------------------------------------
  979. // Purpose:
  980. //-----------------------------------------------------------------------------
  981. void CEconItemDetailsRichText::DataText_AppendUsageData( const CEconItemDefinition *pBaseDef )
  982. {
  983. // Don't show class/slot usage for class/slot tokens
  984. if ( pBaseDef->GetItemClass() && ( !V_strcmp( pBaseDef->GetItemClass(), "class_token" ) || !V_strcmp( pBaseDef->GetItemClass(), "slot_token" ) ) )
  985. return;
  986. #if defined(TF_DLL) || defined(TF_CLIENT_DLL)
  987. const CTFItemDefinition *pDef = dynamic_cast< const CTFItemDefinition *>( pBaseDef );
  988. if ( !pDef )
  989. return;
  990. // Class usage
  991. if ( pDef->CanBeUsedByAllClasses() )
  992. {
  993. if ( pDef->GetBundleInfo() != NULL )
  994. {
  995. AddDataText( "#TF_Armory_Item_ClassUsageAllBundle", false );
  996. }
  997. else
  998. {
  999. AddDataText( "#TF_Armory_Item_ClassUsageAll", false );
  1000. }
  1001. AddDataText( "\n" );
  1002. }
  1003. else
  1004. {
  1005. bool bFirst = true;
  1006. for ( int i = TF_FIRST_NORMAL_CLASS; i < TF_LAST_NORMAL_CLASS; i++ )
  1007. {
  1008. if ( pDef->CanBeUsedByClass(i) )
  1009. {
  1010. if ( bFirst )
  1011. {
  1012. bFirst = false;
  1013. if ( pDef->GetBundleInfo() != NULL )
  1014. {
  1015. AddDataText( "#TF_Armory_Item_ClassUsageBundle", false );
  1016. }
  1017. else
  1018. {
  1019. AddDataText( "#TF_Armory_Item_ClassUsage", false );
  1020. }
  1021. }
  1022. else
  1023. {
  1024. AddDataText( ", " );
  1025. }
  1026. const wchar_t *pwszClassName = g_pVGuiLocalize->Find( g_aPlayerClassNames[i] );
  1027. if ( pwszClassName )
  1028. {
  1029. InsertColorChange( m_colTextHighlight );
  1030. InsertString( pwszClassName );
  1031. InsertColorChange( GetFgColor() );
  1032. }
  1033. }
  1034. }
  1035. if ( !bFirst )
  1036. {
  1037. AddDataText( ".\n" );
  1038. }
  1039. }
  1040. // Slot usage. First, find out if everyone uses it in the same slot, or whether it's used in different slots per class
  1041. bool bHasPerClassSlots = false;
  1042. int iDefaultSlot = pDef->GetDefaultLoadoutSlot();
  1043. for ( int i = TF_FIRST_NORMAL_CLASS; i < TF_LAST_NORMAL_CLASS; i++ )
  1044. {
  1045. if ( !pDef->CanBeUsedByClass(i) )
  1046. continue;
  1047. int iClassSlot = pDef->GetLoadoutSlot(i);
  1048. if ( iClassSlot != iDefaultSlot )
  1049. {
  1050. bHasPerClassSlots = true;
  1051. break;
  1052. }
  1053. }
  1054. // Now print the easy line, or the per-class lines
  1055. if ( !bHasPerClassSlots )
  1056. {
  1057. if ( iDefaultSlot != -1 )
  1058. {
  1059. AddDataText( "#TF_Armory_Item_SlotUsageAll", true, g_pVGuiLocalize->Find( ItemSystem()->GetItemSchema()->GetLoadoutStringsForDisplay( pDef->GetEquipType() )[iDefaultSlot] ) );
  1060. }
  1061. }
  1062. else
  1063. {
  1064. bool bFirst = true;
  1065. for ( int i = TF_FIRST_NORMAL_CLASS; i < TF_LAST_NORMAL_CLASS; i++ )
  1066. {
  1067. if ( !pDef->CanBeUsedByClass(i) )
  1068. continue;
  1069. if ( bFirst )
  1070. {
  1071. bFirst = false;
  1072. AddDataText( "#TF_Armory_Item_SlotUsageClassHeader", false );
  1073. }
  1074. else
  1075. {
  1076. AddDataText( ", " );
  1077. }
  1078. int iClassSlot = pDef->GetLoadoutSlot(i);
  1079. AddDataText( "#TF_Armory_Item_SlotUsageClass", false, g_pVGuiLocalize->Find( ItemSystem()->GetItemSchema()->GetLoadoutStringsForDisplay( pDef->GetEquipType() )[iClassSlot] ), g_pVGuiLocalize->Find( g_aPlayerClassNames[i] ) );
  1080. }
  1081. if ( !bFirst )
  1082. {
  1083. AddDataText( ".\n\n" );
  1084. }
  1085. }
  1086. #endif // #if defined(TF_DLL) || defined(TF_CLIENT_DLL)
  1087. }
  1088. //-----------------------------------------------------------------------------
  1089. // Purpose:
  1090. //-----------------------------------------------------------------------------
  1091. void CEconItemDetailsRichText::DataText_AppendToolUsage( const CEconItemDefinition *pDef )
  1092. {
  1093. // Loop through the tools, and list any that can be applied to this item
  1094. bool bFirstTool = true;
  1095. for ( int i = 0; i < m_ToolList.Count(); i++ )
  1096. {
  1097. const GameItemDefinition_t *pToolDef = dynamic_cast<const GameItemDefinition_t *>( GetItemSchema()->GetItemDefinition( m_ToolList[i] ) );
  1098. if ( !CEconSharedToolSupport::ToolCanApplyToDefinition( pToolDef, dynamic_cast<const GameItemDefinition_t *>( pDef ) ) )
  1099. continue;
  1100. if ( bFirstTool )
  1101. {
  1102. bFirstTool = false;
  1103. AddDataText( "#TF_Armory_Item_ToolUsage", false );
  1104. }
  1105. else
  1106. {
  1107. AddDataText( ", " );
  1108. }
  1109. // Create a link to the item
  1110. {
  1111. // we need an econ item view here for just the item name
  1112. CEconItemView tmpTool;
  1113. tmpTool.Init( m_ToolList[i], AE_USE_SCRIPT_VALUE, AE_USE_SCRIPT_VALUE, true );
  1114. InsertItemLink( tmpTool.GetItemName(), pToolDef->GetDefinitionIndex() );
  1115. }
  1116. }
  1117. if ( !bFirstTool )
  1118. {
  1119. AddDataText( ".\n" );
  1120. }
  1121. }
  1122. //-----------------------------------------------------------------------------
  1123. // Purpose:
  1124. //-----------------------------------------------------------------------------
  1125. void CEconItemDetailsRichText::DataText_AppendStoreFlags( const CEconItemDefinition *pDef )
  1126. {
  1127. if ( !ItemSystem() || !ItemSystem()->GetItemSchema() )
  1128. return;
  1129. const bool bHolidayRestriction = pDef->GetHolidayRestriction() != NULL && V_strlen( pDef->GetHolidayRestriction() ) > 0;
  1130. if ( bHolidayRestriction )
  1131. {
  1132. wchar_t *pRestrictedText = g_pVGuiLocalize->Find( "#Store_HolidayRestrictionText" );
  1133. if ( pRestrictedText )
  1134. {
  1135. InsertColorChange( Color( 200, 80, 60, 255 ) );
  1136. InsertString( pRestrictedText );
  1137. InsertString( L".\n\n" );
  1138. }
  1139. }
  1140. if ( m_bLimitedItem )
  1141. {
  1142. wchar_t *pLocText = bHolidayRestriction
  1143. ? g_pVGuiLocalize->Find( "#TF_Armory_Item_Limited_Holiday" )
  1144. : g_pVGuiLocalize->Find( "#TF_Armory_Item_Limited" );
  1145. if ( pLocText )
  1146. {
  1147. InsertColorChange( Color( 255, 140, 0, 255 ) );
  1148. InsertString ( pLocText );
  1149. InsertString( L"\n\n" );
  1150. }
  1151. }
  1152. }
  1153. //-----------------------------------------------------------------------------
  1154. // Purpose:
  1155. //-----------------------------------------------------------------------------
  1156. void CEconItemDetailsRichText::DataText_AppendItemData( const CEconItemDefinition *pDef )
  1157. {
  1158. if ( !GetItemSchema() )
  1159. return;
  1160. // Start by looking for a specified armory desc string
  1161. const char *pDesc = pDef->GetArmoryDescString();
  1162. if ( pDesc && pDesc[0] )
  1163. {
  1164. const ArmoryStringDict_t &ArmoryItemData = ItemSystem()->GetItemSchema()->GetArmoryDataItems();
  1165. // Tokenize it, and look for localization strings for each token
  1166. CUtlVector< char * > vecArmoryKeys;
  1167. Q_SplitString( pDesc, " ", vecArmoryKeys );
  1168. FOR_EACH_VEC( vecArmoryKeys, i )
  1169. {
  1170. int iIdx = ArmoryItemData.Find( vecArmoryKeys[i] );
  1171. if ( ArmoryItemData.IsValidIndex( iIdx ) )
  1172. {
  1173. const char *pLoc = ArmoryItemData.Element( iIdx ).Get();
  1174. AddDataText( pLoc );
  1175. }
  1176. }
  1177. vecArmoryKeys.PurgeAndDeleteElements();
  1178. }
  1179. // Is this item part of a set?
  1180. if ( pDef->GetItemSetDefinition() )
  1181. {
  1182. DataText_AppendSetData( pDef );
  1183. }
  1184. if ( pDef->GetBundleInfo() != NULL )
  1185. {
  1186. DataText_AppendBundleData( pDef );
  1187. }
  1188. // Does this item type have data associated with it?
  1189. const ArmoryStringDict_t &ArmoryItemTypeData = GetItemSchema()->GetArmoryDataItemTypes();
  1190. int iIdx = ArmoryItemTypeData.Find( pDef->GetItemTypeName() );
  1191. if ( ArmoryItemTypeData.IsValidIndex( iIdx ) )
  1192. {
  1193. const char *pLoc = ArmoryItemTypeData.Element( iIdx ).Get();
  1194. AddDataText( pLoc );
  1195. }
  1196. // Does this item class have data associated with it?
  1197. const ArmoryStringDict_t &ArmoryItemClassData = GetItemSchema()->GetArmoryDataItemClasses();
  1198. iIdx = pDef->GetItemClass() ? ArmoryItemClassData.Find( pDef->GetItemClass() ) : ArmoryItemClassData.InvalidIndex();
  1199. if ( ArmoryItemClassData.IsValidIndex( iIdx ) )
  1200. {
  1201. if ( !pDef->GetDefinitionKey( "hack_disable_armory_type_desc" ) )
  1202. {
  1203. const char *pLoc = ArmoryItemClassData.Element( iIdx ).Get();
  1204. AddDataText( pLoc );
  1205. }
  1206. }
  1207. // Can this item be earned by an achievement?
  1208. const AchievementAward_t *pAchievementAward = GetItemSchema()->GetAchievementRewardByDefIndex( pDef->GetDefinitionIndex() );
  1209. if( pAchievementAward )
  1210. {
  1211. wchar_t *pszAchName = ACHIEVEMENT_LOCALIZED_NAME_FROM_STR( pAchievementAward->m_sNativeName.String() );
  1212. if ( pszAchName )
  1213. {
  1214. AddDataText( "#TF_Armory_Item_AchievementReward", true, pszAchName );
  1215. }
  1216. }
  1217. // Is this a Holiday item?
  1218. if ( pDef->GetHolidayRestriction() )
  1219. {
  1220. AddDataText( "#TF_Armory_Item_HolidayRestriction" );
  1221. }
  1222. }
  1223. //-----------------------------------------------------------------------------
  1224. // Purpose:
  1225. //-----------------------------------------------------------------------------
  1226. void CEconItemDetailsRichText::DataText_AppendBundleData( const CEconItemDefinition *pDef )
  1227. {
  1228. bool bFirstItem = true;
  1229. const bundleinfo_t *pBundleInfo = pDef->GetBundleInfo();
  1230. FOR_EACH_VEC( pBundleInfo->vecItemDefs, i )
  1231. {
  1232. CEconItemDefinition *pBundledItem = pBundleInfo->vecItemDefs[i];
  1233. if ( pBundledItem )
  1234. {
  1235. if ( bFirstItem )
  1236. {
  1237. bFirstItem = false;
  1238. AddDataText( "#TF_Armory_Item_Bundle", false );
  1239. }
  1240. else
  1241. {
  1242. AddDataText( ", " );
  1243. }
  1244. CEconItemView bundleItemData;
  1245. bundleItemData.Init( pBundledItem->GetDefinitionIndex(), AE_UNIQUE, AE_USE_SCRIPT_VALUE, true );
  1246. InsertItemLink( bundleItemData.GetItemName(), bundleItemData.GetItemDefIndex() );
  1247. }
  1248. }
  1249. if ( !bFirstItem )
  1250. {
  1251. AddDataText( ".\n\n" );
  1252. }
  1253. }
  1254. //-----------------------------------------------------------------------------
  1255. // Purpose:
  1256. //-----------------------------------------------------------------------------
  1257. void CEconItemDetailsRichText::DataText_AppendAttributeData( const CEconItemDefinition *pDef )
  1258. {
  1259. if ( !ItemSystem() || !ItemSystem()->GetItemSchema() )
  1260. return;
  1261. const ArmoryStringDict_t &ArmoryAttribData = ItemSystem()->GetItemSchema()->GetArmoryDataAttributes();
  1262. CVarBitVec m_AttribsShown;
  1263. m_AttribsShown.Resize( ArmoryAttribData.Count() );
  1264. m_AttribsShown.ClearAll();
  1265. const CUtlVector<static_attrib_t> &vecStaticAttribs = pDef->GetStaticAttributes();
  1266. FOR_EACH_VEC( vecStaticAttribs, i )
  1267. {
  1268. const static_attrib_t &attrib = vecStaticAttribs[i];
  1269. CEconItemAttributeDefinition *pAttributeDef = ItemSystem()->GetStaticDataForAttributeByDefIndex( attrib.iDefIndex );
  1270. if ( !pAttributeDef )
  1271. continue;
  1272. if ( pAttributeDef->IsHidden() )
  1273. continue;
  1274. const char *pDesc = pAttributeDef->GetArmoryDescString();
  1275. if ( !pDesc || !pDesc[0] )
  1276. continue;
  1277. // Tokenize it, and look for localization strings for each token
  1278. CUtlVector< char * > vecArmoryKeys;
  1279. Q_SplitString( pDesc, " ", vecArmoryKeys );
  1280. FOR_EACH_VEC( vecArmoryKeys, iKey )
  1281. {
  1282. int iIdx = ArmoryAttribData.Find( vecArmoryKeys[iKey] );
  1283. if ( ArmoryAttribData.IsValidIndex( iIdx ) )
  1284. {
  1285. if ( m_AttribsShown[iIdx] == false )
  1286. {
  1287. const char *pLoc = ArmoryAttribData.Element( iIdx ).Get();
  1288. AddDataText( pLoc );
  1289. m_AttribsShown.Set( iIdx );
  1290. }
  1291. }
  1292. }
  1293. vecArmoryKeys.PurgeAndDeleteElements();
  1294. }
  1295. }
  1296. //-----------------------------------------------------------------------------
  1297. // Purpose:
  1298. //-----------------------------------------------------------------------------
  1299. void CEconItemDetailsRichText::DataText_AppendSetData( const CEconItemDefinition *pDef )
  1300. {
  1301. if ( !ItemSystem() || !ItemSystem()->GetItemSchema() )
  1302. return;
  1303. CEconItemSchema *pSchema = ItemSystem()->GetItemSchema();
  1304. if ( pSchema )
  1305. {
  1306. const CEconItemSetDefinition *pItemSet = pDef->GetItemSetDefinition();
  1307. if ( pItemSet )
  1308. {
  1309. // Does this set provide bonus attributes when completely worn?
  1310. if ( pItemSet->m_iAttributes.Count() > 0 )
  1311. {
  1312. // Used for grabbing display colors.
  1313. vgui::HScheme hScheme = vgui::scheme()->GetScheme( "ClientScheme" );
  1314. vgui::IScheme *pScheme = vgui::scheme()->GetIScheme( hScheme );
  1315. Assert( pScheme );
  1316. // Insert the set description
  1317. wchar_t *pLocText = g_pVGuiLocalize->Find( pItemSet->m_pszLocalizedName );
  1318. AddDataText( "#TF_Armory_Item_InSet", false, pLocText, NULL, m_bAllowItemSetLinks ? &pItemSet->m_iBundleItemDef : NULL );
  1319. for ( int i = 0; i < pItemSet->m_iAttributes.Count(); i++ )
  1320. {
  1321. const CEconItemAttributeDefinition *pAttrDef = GetItemSchema()->GetAttributeDefinition( pItemSet->m_iAttributes[i].m_iAttribDefIndex );
  1322. if ( !pAttrDef )
  1323. continue;
  1324. CEconAttributeDescription AttrDesc( GLocalizationProvider(), pAttrDef, pItemSet->m_iAttributes[i].m_flValue );
  1325. if ( !AttrDesc.GetDescription().IsEmpty() )
  1326. {
  1327. InsertColorChange( pScheme->GetColor( GetColorNameForAttribColor( AttrDesc.GetDefaultColor() ), Color(255, 255, 255, 255) ) );
  1328. AddDataText( " " );
  1329. InsertString( AttrDesc.GetDescription().Get() );
  1330. AddDataText( "\n" );
  1331. }
  1332. }
  1333. AddDataText( "\n" );
  1334. }
  1335. // This set is visual and provides no additional bonuses when worn completely.
  1336. else
  1337. {
  1338. // Insert the set description
  1339. wchar_t *pLocText = g_pVGuiLocalize->Find( pItemSet->m_pszLocalizedName );
  1340. AddDataText( "#TF_Armory_Item_InSet_NoBonus", false, pLocText, NULL, m_bAllowItemSetLinks ? &pItemSet->m_iBundleItemDef : NULL );
  1341. }
  1342. }
  1343. }
  1344. }
  1345. //-----------------------------------------------------------------------------
  1346. // Purpose:
  1347. //-----------------------------------------------------------------------------
  1348. void CEconItemDetailsRichText::UpdateToolList( void )
  1349. {
  1350. m_ToolList.Purge();
  1351. // Find all the tool types in our items list
  1352. const CEconItemSchema::ToolsItemDefinitionMap_t &mapItemDefs = ItemSystem()->GetItemSchema()->GetToolsItemDefinitionMap();
  1353. FOR_EACH_MAP( mapItemDefs, i )
  1354. {
  1355. const CEconItemDefinition *pDef = mapItemDefs[i];
  1356. if ( !pDef->GetItemClass() )
  1357. continue;
  1358. if ( !pDef->IsTool() )
  1359. continue;
  1360. const IEconTool *pEconTool = pDef->GetEconTool();
  1361. if ( !pEconTool )
  1362. continue;
  1363. if ( !pEconTool->ShouldDisplayAsUseableOnItemsInArmory() )
  1364. continue;
  1365. // Now make sure it doesn't have the same type as an existing tool
  1366. bool bAlreadyFound = false;
  1367. FOR_EACH_VEC( m_ToolList, tool )
  1368. {
  1369. CEconItemDefinition *pOtherDef = ItemSystem()->GetStaticDataForItemByDefIndex( m_ToolList[tool] );
  1370. Assert( pOtherDef );
  1371. const IEconTool *pOtherEconTool = pOtherDef->GetEconTool();
  1372. Assert( pOtherEconTool );
  1373. bAlreadyFound = !V_strcmp( pEconTool->GetTypeName(), pOtherEconTool->GetTypeName() );
  1374. if ( bAlreadyFound )
  1375. {
  1376. break;
  1377. }
  1378. }
  1379. if ( !bAlreadyFound )
  1380. {
  1381. m_ToolList.AddToTail( pDef->GetDefinitionIndex() );
  1382. }
  1383. }
  1384. }
  1385. //-----------------------------------------------------------------------------
  1386. // Purpose:
  1387. //-----------------------------------------------------------------------------
  1388. void CEconItemDetailsRichText::InsertItemLink( const wchar_t *pwzItemName, int iItemDef, Color *pColorOverride )
  1389. {
  1390. char szTmpToolName[256];
  1391. ::ILocalize::ConvertUnicodeToANSI(pwzItemName, szTmpToolName, sizeof( szTmpToolName ));
  1392. char szToolStoreURL[256];
  1393. V_snprintf( szToolStoreURL, sizeof( szToolStoreURL ), "<a href=item://%u>%s</a>", iItemDef, szTmpToolName );
  1394. InsertPossibleURLString( szToolStoreURL, pColorOverride ? *pColorOverride : m_colLink, GetFgColor() );
  1395. };
  1396. //-----------------------------------------------------------------------------
  1397. // Purpose:
  1398. //-----------------------------------------------------------------------------
  1399. CExplanationPopup::CExplanationPopup(Panel *parent, const char *panelName) : vgui::EditablePanel( parent, panelName )
  1400. {
  1401. m_pCallout = new CExplanationPopupCalloutArrow( parent );
  1402. m_pCallout->SetVisible( false );
  1403. m_pCallout->SetAutoDelete( false );
  1404. m_szPrevExplanation[0] = '\0';
  1405. m_szNextExplanation[0] = '\0';
  1406. m_bFinishedPopup = false;
  1407. ListenForGameEvent( "gameui_hidden" );
  1408. }
  1409. //-----------------------------------------------------------------------------
  1410. // Purpose:
  1411. //-----------------------------------------------------------------------------
  1412. CExplanationPopup::~CExplanationPopup( void )
  1413. {
  1414. m_pCallout->MarkForDeletion();
  1415. m_pCallout = NULL;
  1416. }
  1417. //-----------------------------------------------------------------------------
  1418. // Purpose:
  1419. //-----------------------------------------------------------------------------
  1420. void CExplanationPopup::OnCommand( const char *command )
  1421. {
  1422. if ( !Q_stricmp( command, "close" ) )
  1423. {
  1424. Hide( 0 );
  1425. }
  1426. else if ( !Q_stricmp( command, "nextexplanation" ) )
  1427. {
  1428. Hide( 1 );
  1429. }
  1430. else if ( !Q_stricmp( command, "prevexplanation" ) )
  1431. {
  1432. Hide( -1 );
  1433. }
  1434. else
  1435. {
  1436. BaseClass::OnCommand( command );
  1437. }
  1438. }
  1439. //-----------------------------------------------------------------------------
  1440. // Purpose:
  1441. //-----------------------------------------------------------------------------
  1442. void CExplanationPopup::Hide( int iExplanationDelta )
  1443. {
  1444. int iPos = m_iPositionInChain;
  1445. const char *pszMoveTo = NULL;
  1446. if ( iExplanationDelta == -1 )
  1447. {
  1448. if ( !m_szPrevExplanation || m_szPrevExplanation[ 0 ] == '\0' )
  1449. return;
  1450. pszMoveTo = m_szPrevExplanation;
  1451. iPos--;
  1452. }
  1453. else if ( iExplanationDelta == 1 )
  1454. {
  1455. if ( !m_szNextExplanation || m_szNextExplanation[ 0 ] == '\0' )
  1456. return;
  1457. pszMoveTo = m_szNextExplanation;
  1458. iPos++;
  1459. }
  1460. SetVisible( false );
  1461. m_pCallout->SetVisible( false );
  1462. vgui::ivgui()->RemoveTickSignal( GetVPanel() );
  1463. if ( m_bForceClose )
  1464. {
  1465. TFModalStack()->PopModal( this );
  1466. }
  1467. if ( iExplanationDelta == 0 )
  1468. {
  1469. if ( GetParent() )
  1470. {
  1471. GetParent()->NavigateTo();
  1472. }
  1473. return;
  1474. }
  1475. CExplanationPopup *pPopup = dynamic_cast<CExplanationPopup*>( GetParent()->FindChildByName( pszMoveTo ) );
  1476. if ( pPopup )
  1477. {
  1478. pPopup->Popup( iPos, m_iTotalInChain );
  1479. }
  1480. }
  1481. //-----------------------------------------------------------------------------
  1482. // Purpose:
  1483. //-----------------------------------------------------------------------------
  1484. void CExplanationPopup::Popup( int iPosition, int iTotalPanels )
  1485. {
  1486. // Parent this to our parent. Doing it in our constructor doesn't work because
  1487. // the parent passed in there hasn't been initialized properly.
  1488. m_pCallout->SetParent( GetParent() );
  1489. m_pCallout->SetZPos( GetZPos() - 1 );
  1490. if ( m_bForceClose )
  1491. {
  1492. TFModalStack()->PushModal( this );
  1493. }
  1494. // If they don't specify X,Y,W,H, we start tiny on the callout position
  1495. if ( !m_iStartX && !m_iStartY )
  1496. {
  1497. m_iStartX = m_iCalloutInParentsX;
  1498. m_iStartY = m_iCalloutInParentsY;
  1499. }
  1500. if ( !m_iStartW && !m_iStartH )
  1501. {
  1502. m_iStartW = 1;
  1503. m_iStartH = 1;
  1504. }
  1505. // If we weren't given a position, we're the first in a chain. Figure out
  1506. // how many there are in the total chain.
  1507. m_iPositionInChain = iPosition;
  1508. m_iTotalInChain = iTotalPanels;
  1509. if ( !m_iTotalInChain )
  1510. {
  1511. m_iTotalInChain = 0;
  1512. m_iPositionInChain = 1;
  1513. CExplanationPopup *pPopup = this;
  1514. while ( pPopup )
  1515. {
  1516. m_iTotalInChain++;
  1517. const char *pszNext = pPopup->GetNextExplanation();
  1518. if ( !pszNext[0] )
  1519. break;
  1520. const char *pszPrev = pPopup->GetName();
  1521. pPopup = dynamic_cast<CExplanationPopup*>( GetParent()->FindChildByName( pszNext ) );
  1522. if ( pPopup )
  1523. {
  1524. pPopup->SetPrevExplanation( pszPrev );
  1525. }
  1526. }
  1527. }
  1528. // Now assemble our position label
  1529. char szTmp[16];
  1530. Q_snprintf(szTmp, 16, "%d/%d", m_iPositionInChain, m_iTotalInChain );
  1531. SetDialogVariable( "explanationnumber", szTmp );
  1532. SetBounds( m_iStartX, m_iStartY, m_iStartW, m_iStartH );
  1533. SetVisible( true );
  1534. vgui::ivgui()->AddTickSignal( GetVPanel() );
  1535. m_flStartTime = Plat_FloatTime();
  1536. m_flEndTime = m_flStartTime + 0.5;
  1537. m_bFinishedPopup = false;
  1538. // If our endX & endW is going to result in us being off the side of the screen, move back on
  1539. if ( m_iEndX < 0 )
  1540. {
  1541. m_iEndX = XRES(5);
  1542. }
  1543. else if ( (m_iEndX + m_iEndW) > ScreenWidth() )
  1544. {
  1545. m_iEndX = ScreenWidth() - m_iEndW - XRES(5);
  1546. }
  1547. // Figure out what side of the bubble we should have the arrow attached to
  1548. m_iCalloutSide = EXC_SIDE_TOP;
  1549. Vector vecCallout( m_iCalloutInParentsX, m_iCalloutInParentsY, 0 );
  1550. Vector vecMins( m_iEndX, m_iEndY, 0 );
  1551. Vector vecMaxs( m_iEndX + m_iEndW, m_iEndY + m_iEndH, 0 );
  1552. Vector vecPoint;
  1553. CalcClosestPointOnAABB( vecMins, vecMaxs, vecCallout, vecPoint );
  1554. if ( vecPoint.x == vecMins.x && vecCallout.x != vecMins.x )
  1555. {
  1556. m_iCalloutSide = EXC_SIDE_LEFT;
  1557. }
  1558. else if ( vecPoint.y == vecMins.y && vecCallout.y != vecMins.y )
  1559. {
  1560. m_iCalloutSide = EXC_SIDE_TOP;
  1561. }
  1562. else if ( vecPoint.x == vecMaxs.x && vecCallout.x != vecMaxs.x )
  1563. {
  1564. m_iCalloutSide = EXC_SIDE_RIGHT;
  1565. }
  1566. else
  1567. {
  1568. m_iCalloutSide = EXC_SIDE_BOTTOM;
  1569. }
  1570. }
  1571. //-----------------------------------------------------------------------------
  1572. // Purpose:
  1573. //-----------------------------------------------------------------------------
  1574. void CExplanationPopup::OnTick( void )
  1575. {
  1576. float flElapsed = Plat_FloatTime() - m_flStartTime;
  1577. float flTotal = m_flEndTime - m_flStartTime;
  1578. float flBias = Bias( RemapValClamped( flElapsed, 0.f, flTotal, 0.f, 1.f ), 0.7f );
  1579. flElapsed = flTotal * flBias;
  1580. if ( flElapsed >= flTotal )
  1581. {
  1582. //vgui::ivgui()->RemoveTickSignal( GetVPanel() );
  1583. if ( !m_bFinishedPopup )
  1584. {
  1585. SetBounds( m_iEndX, m_iEndY, m_iEndW, m_iEndH );
  1586. PositionCallout( 1.0 );
  1587. m_bFinishedPopup = true;
  1588. }
  1589. // If we've lost focus, or been hidden, release our modal lock
  1590. if ( !ipanel()->IsFullyVisible( GetVPanel() ))
  1591. {
  1592. Hide(0);
  1593. }
  1594. return;
  1595. }
  1596. int iExpandW = XRES(30);
  1597. int iExpandH = YRES(30);
  1598. int iExpandedW = m_iEndW + iExpandW;
  1599. int iExpandedH = m_iEndH + iExpandH;
  1600. int iExpandedX = m_iEndX - (iExpandW * 0.5);
  1601. int iExpandedY = m_iEndY - (iExpandH * 0.5);
  1602. int iW, iH, iX, iY;
  1603. float flExpandTime = (flTotal * 0.66);
  1604. PositionCallout( RemapVal( flElapsed, 0, flTotal, 0, 1 ) );
  1605. // iW = RemapValClamped( flElapsed, 0, flTotal, m_iStartW, m_iEndW );
  1606. // iH = RemapValClamped( flElapsed, 0, flTotal, m_iStartH, m_iEndH );
  1607. // iX = RemapValClamped( flElapsed, 0, flTotal, m_iStartX, m_iEndX );
  1608. // iY = RemapValClamped( flElapsed, 0, flTotal, m_iStartY, m_iEndY );
  1609. // SetBounds( iX, iY, iW, iH );
  1610. // return;
  1611. if ( flElapsed < flExpandTime )
  1612. {
  1613. // Expand to greater than the end size
  1614. iW = RemapValClamped( flElapsed, 0, flExpandTime, m_iStartW, iExpandedW );
  1615. iH = RemapValClamped( flElapsed, 0, flExpandTime, m_iStartH, iExpandedH );
  1616. iX = RemapValClamped( flElapsed, 0, flExpandTime, m_iStartX, iExpandedX );
  1617. iY = RemapValClamped( flElapsed, 0, flExpandTime, m_iStartY, iExpandedY );
  1618. }
  1619. else
  1620. {
  1621. // Contract to the end size
  1622. iW = RemapValClamped( flElapsed, flExpandTime, flTotal, iExpandedW, m_iEndW );
  1623. iH = RemapValClamped( flElapsed, flExpandTime, flTotal, iExpandedH, m_iEndH );
  1624. iX = RemapValClamped( flElapsed, flExpandTime, flTotal, iExpandedX, m_iEndX );
  1625. iY = RemapValClamped( flElapsed, flExpandTime, flTotal, iExpandedY, m_iEndY );
  1626. }
  1627. SetBounds( iX, iY, iW, iH );
  1628. }
  1629. void CExplanationPopup::OnKeyCodeTyped( vgui::KeyCode code )
  1630. {
  1631. if ( IsVisible() && m_pCallout && m_pCallout->IsVisible() )
  1632. {
  1633. // swallow all keys
  1634. if ( code == KEY_ESCAPE )
  1635. {
  1636. OnCommand( "close" );
  1637. return;
  1638. }
  1639. }
  1640. BaseClass::OnKeyCodePressed( code );
  1641. }
  1642. //-----------------------------------------------------------------------------
  1643. // Purpose:
  1644. //-----------------------------------------------------------------------------
  1645. void CExplanationPopup::OnKeyCodePressed( vgui::KeyCode code )
  1646. {
  1647. if ( IsVisible() && m_pCallout && m_pCallout->IsVisible() )
  1648. {
  1649. ButtonCode_t nButtonCode = GetBaseButtonCode( code );
  1650. // swallow all keys
  1651. if ( nButtonCode == KEY_XBUTTON_B )
  1652. {
  1653. OnCommand( "close" );
  1654. return;
  1655. }
  1656. else if ( nButtonCode == KEY_XBUTTON_LEFT ||
  1657. nButtonCode == KEY_XSTICK1_LEFT ||
  1658. nButtonCode == KEY_XSTICK2_LEFT ||
  1659. code == KEY_LEFT )
  1660. {
  1661. OnCommand( "prevexplanation" );
  1662. return;
  1663. }
  1664. else if ( nButtonCode == KEY_XBUTTON_RIGHT ||
  1665. nButtonCode == KEY_XSTICK1_RIGHT ||
  1666. nButtonCode == KEY_XSTICK2_RIGHT ||
  1667. code == KEY_RIGHT )
  1668. {
  1669. OnCommand( "nextexplanation" );
  1670. return;
  1671. }
  1672. }
  1673. BaseClass::OnKeyCodePressed( code );
  1674. }
  1675. //-----------------------------------------------------------------------------
  1676. // Purpose:
  1677. //-----------------------------------------------------------------------------
  1678. void CExplanationPopup::PositionCallout( float flElapsed )
  1679. {
  1680. // Size and position the callout
  1681. if ( !m_pCallout->IsVisible() )
  1682. {
  1683. m_pCallout->SetVisible( true );
  1684. }
  1685. int iCalloutSize = 20;
  1686. int iIndent = 15;
  1687. int iMyPos[2];
  1688. GetPos( iMyPos[0], iMyPos[1] );
  1689. int iMySize[2];
  1690. iMySize[0] = GetWide();
  1691. iMySize[1] = GetTall();
  1692. int iCalloutPos[2];
  1693. iCalloutPos[0] = m_iCalloutInParentsX;
  1694. iCalloutPos[1] = m_iCalloutInParentsY;
  1695. // We need to figure out the three corners of the callout triangle, in parent space
  1696. int iArrowA[2];
  1697. int iArrowB[2];
  1698. int iW, iH, iX, iY;
  1699. // Determine which axis the arrow's extruding along
  1700. int x = (m_iCalloutSide == EXC_SIDE_TOP || m_iCalloutSide == EXC_SIDE_BOTTOM) ? 0 : 1;
  1701. int y = !x;
  1702. // Figure out where the center will be of the arrow on the edge that the arrow's extruding (ensure it's always somewhat indented from the corners)
  1703. iArrowA[x] = iMyPos[x] + clamp( iCalloutPos[x] - iMyPos[x] - XRES(iCalloutSize * 0.5), XRES(iIndent), iMySize[x] - XRES(iIndent) - XRES(iCalloutSize) );
  1704. iArrowB[x] = iArrowA[x] + XRES(iCalloutSize);
  1705. iArrowA[y] = iMyPos[y] + (( iCalloutPos[y] > iMyPos[y] ) ? iMySize[y] : 0);
  1706. iArrowB[y] = iMyPos[y] + (( iCalloutPos[y] > iMyPos[y] ) ? iMySize[y] : 0);
  1707. // Slide the arrow out towards the callout over time.
  1708. for ( int i = 0; i < 2; i++ )
  1709. {
  1710. iCalloutPos[i] = RemapValClamped( flElapsed, 0, 1, iArrowA[i] + (iArrowB[i] - iArrowA[i]), iCalloutPos[i] );
  1711. }
  1712. // Assemble a bounding box that contains the arrow points
  1713. iX = MIN( MIN( iCalloutPos[0], iArrowA[0] ), iArrowB[0] );
  1714. iW = MAX( MAX( iCalloutPos[0], iArrowA[0] ), iArrowB[0] ) - iX;
  1715. iY = MIN( MIN( iCalloutPos[1], iArrowA[1] ), iArrowB[1] );
  1716. iH = MAX( MAX( iCalloutPos[1], iArrowA[1] ), iArrowB[1] ) - iY;
  1717. m_pCallout->SetBounds( iX, iY, iW+1, iH+1 );
  1718. //Msg("CALLOUT: %d %d, %d %d\n", iX,iY,iW,iH );
  1719. // Tell the callout where its points are, so it can draw the triangle (make sure the triangle is facing the camera)
  1720. if ( m_iCalloutSide == EXC_SIDE_TOP || m_iCalloutSide == EXC_SIDE_RIGHT )
  1721. {
  1722. m_pCallout->SetArrowPoints( iCalloutPos[0]-iX, iCalloutPos[1]-iY, iArrowB[0]-iX, iArrowB[1]-iY, iArrowA[0]-iX, iArrowA[1]-iY );
  1723. }
  1724. else
  1725. {
  1726. m_pCallout->SetArrowPoints( iCalloutPos[0]-iX, iCalloutPos[1]-iY, iArrowA[0]-iX, iArrowA[1]-iY, iArrowB[0]-iX, iArrowB[1]-iY );
  1727. }
  1728. }
  1729. //-----------------------------------------------------------------------------
  1730. // Purpose:
  1731. //-----------------------------------------------------------------------------
  1732. void CExplanationPopupCalloutArrow::Paint( void )
  1733. {
  1734. int x,y;
  1735. vgui::ipanel()->GetAbsPos(GetVPanel(), x,y );
  1736. CMatRenderContextPtr pRenderContext( materials );
  1737. pRenderContext->Bind( materials->FindMaterial( "vgui/callout_tail", TEXTURE_GROUP_OTHER ), NULL );
  1738. IMesh *pMesh = pRenderContext->GetDynamicMesh();
  1739. CMeshBuilder meshBuilder;
  1740. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, 1 );
  1741. meshBuilder.Color4ub( 255, 255, 255, 255 );
  1742. meshBuilder.TexCoord2f( 0, 1.0,0.5 );
  1743. meshBuilder.Position3f( x + m_iArrowA[0], y + m_iArrowA[1], 1 );
  1744. meshBuilder.AdvanceVertex();
  1745. meshBuilder.Color4ub( 255, 255, 255, 255 );
  1746. meshBuilder.TexCoord2f( 0, 0,1 );
  1747. meshBuilder.Position3f( x + m_iArrowB[0], y + m_iArrowB[1], 1 );
  1748. meshBuilder.AdvanceVertex();
  1749. meshBuilder.Color4ub( 255, 255, 255, 255 );
  1750. meshBuilder.TexCoord2f( 0, 0,0 );
  1751. meshBuilder.Position3f( x + m_iArrowC[0], y + m_iArrowC[1], 1 );
  1752. meshBuilder.AdvanceVertex();
  1753. meshBuilder.End();
  1754. pMesh->Draw();
  1755. // vgui::surface()->DrawSetColor( Color(0,255,0,255) );
  1756. // vgui::surface()->DrawLine( m_iArrowA[0], m_iArrowA[1], m_iArrowB[0], m_iArrowB[1] );
  1757. // vgui::surface()->DrawLine( m_iArrowA[0], m_iArrowA[1], m_iArrowC[0], m_iArrowC[1] );
  1758. // vgui::surface()->DrawLine( m_iArrowB[0], m_iArrowB[1], m_iArrowC[0], m_iArrowC[1] );
  1759. // vgui::surface()->DrawOutlinedRect( 0,0, GetWide(), GetTall() );
  1760. }
  1761. //-----------------------------------------------------------------------------
  1762. // Purpose:
  1763. //-----------------------------------------------------------------------------
  1764. void CExplanationPopup::ApplySettings( KeyValues *inResourceData )
  1765. {
  1766. BaseClass::ApplySettings( inResourceData );
  1767. Q_strncpy( m_szNextExplanation, inResourceData->GetString( "next_explanation", "" ), sizeof( m_szNextExplanation ) );
  1768. }
  1769. //-----------------------------------------------------------------------------
  1770. // Purpose:
  1771. //-----------------------------------------------------------------------------
  1772. void CExplanationPopup::SetPrevExplanation( const char *pszPrev )
  1773. {
  1774. m_szPrevExplanation[0] = '\0';
  1775. if ( pszPrev && pszPrev[0] )
  1776. {
  1777. Q_strncpy( m_szPrevExplanation, pszPrev, sizeof( m_szPrevExplanation ) );
  1778. }
  1779. }
  1780. //-----------------------------------------------------------------------------
  1781. // Purpose:
  1782. //-----------------------------------------------------------------------------
  1783. void CExplanationPopup::FireGameEvent( IGameEvent *event )
  1784. {
  1785. const char * type = event->GetName();
  1786. if ( Q_strcmp(type, "gameui_hidden") == 0 )
  1787. {
  1788. if ( IsVisible() )
  1789. {
  1790. Hide( 0 );
  1791. }
  1792. }
  1793. }
  1794. //-----------------------------------------------------------------------------
  1795. // Purpose:
  1796. //-----------------------------------------------------------------------------
  1797. CPanelModalStack g_ModalStack;
  1798. CPanelModalStack *TFModalStack( void )
  1799. {
  1800. return &g_ModalStack;
  1801. }
  1802. //-----------------------------------------------------------------------------
  1803. // Purpose:
  1804. //-----------------------------------------------------------------------------
  1805. void CPanelModalStack::PushModal( vgui::Panel *pDialog )
  1806. {
  1807. VPanelHandle hHandle;
  1808. hHandle.Set( pDialog->GetVPanel() );
  1809. FOR_EACH_VEC( m_pDialogs, i )
  1810. {
  1811. if ( m_pDialogs[i] == hHandle )
  1812. return;
  1813. }
  1814. m_pDialogs.AddToHead( hHandle );
  1815. vgui::input()->SetAppModalSurface( pDialog->GetVPanel() );
  1816. pDialog->RequestFocus();
  1817. pDialog->MoveToFront();
  1818. }
  1819. //-----------------------------------------------------------------------------
  1820. // Purpose:
  1821. //-----------------------------------------------------------------------------
  1822. void CPanelModalStack::PopModal( vgui::Panel *pDialog )
  1823. {
  1824. bool bFound = false;
  1825. FOR_EACH_VEC_BACK( m_pDialogs, i )
  1826. {
  1827. if ( m_pDialogs[i].Get() == pDialog->GetVPanel() )
  1828. {
  1829. PopModal( i );
  1830. bFound = true;
  1831. }
  1832. }
  1833. AssertMsg( bFound, "CPanelModalStack::PopModal() failed to find the given dialog." );
  1834. }
  1835. //-----------------------------------------------------------------------------
  1836. // Purpose:
  1837. //-----------------------------------------------------------------------------
  1838. void CPanelModalStack::PopModal( int iIdx )
  1839. {
  1840. bool bRecalcLock = false;
  1841. // Only release the modal lock if we had it
  1842. VPANEL hPanel = vgui::input()->GetAppModalSurface();
  1843. if ( !hPanel || m_pDialogs[iIdx].Get() == hPanel )
  1844. {
  1845. bRecalcLock = true;
  1846. }
  1847. m_pDialogs.Remove(iIdx);
  1848. if ( bRecalcLock )
  1849. {
  1850. if ( m_pDialogs.Count() )
  1851. {
  1852. vgui::input()->SetAppModalSurface( m_pDialogs[0] );
  1853. }
  1854. else
  1855. {
  1856. vgui::input()->SetAppModalSurface( NULL );
  1857. }
  1858. }
  1859. }
  1860. //-----------------------------------------------------------------------------
  1861. // Purpose:
  1862. //-----------------------------------------------------------------------------
  1863. void CPanelModalStack::Update( void )
  1864. {
  1865. if ( m_pDialogs.Count() <= 0 )
  1866. return;
  1867. // Don't run this logic if the game UI isn't visible
  1868. if ( !enginevgui->IsGameUIVisible() )
  1869. return;
  1870. // Safety check: If the app model surface dialog is in our list, make sure it's usable
  1871. VPANEL hPanel = vgui::input()->GetAppModalSurface();
  1872. FOR_EACH_VEC_BACK( m_pDialogs, i )
  1873. {
  1874. // Pop dialogs that didn't correctly remove themselves on delete
  1875. if ( m_pDialogs[i].Get() == 0 )
  1876. {
  1877. PopModal( i );
  1878. continue;
  1879. }
  1880. if ( m_pDialogs[i].Get() == hPanel )
  1881. {
  1882. Assert( vgui::ipanel()->IsFullyVisible(hPanel) );
  1883. // Backup hack: If our modal window is no longer visible, make it visible
  1884. if ( !vgui::ipanel()->IsFullyVisible(hPanel) )
  1885. {
  1886. vgui::ipanel()->SetVisible( hPanel, true );
  1887. vgui::ipanel()->MoveToFront( hPanel );
  1888. vgui::ipanel()->RequestFocus( hPanel );
  1889. // Make sure all our parents are visible too
  1890. VPANEL hParent = vgui::ipanel()->GetParent( hPanel );
  1891. while ( hParent != INVALID_PANEL )
  1892. {
  1893. vgui::Panel *pParentPanel = vgui::ipanel()->GetPanel(hParent, "ClientDLL");
  1894. if ( !pParentPanel )
  1895. break;
  1896. vgui::ipanel()->SetVisible( hParent, true );
  1897. hParent = vgui::ipanel()->GetParent( hParent );
  1898. }
  1899. }
  1900. }
  1901. }
  1902. }
  1903. //-----------------------------------------------------------------------------
  1904. // Purpose:
  1905. //-----------------------------------------------------------------------------
  1906. vgui::VPanelHandle CPanelModalStack::Top()
  1907. {
  1908. if ( m_pDialogs.Count() == 0 )
  1909. {
  1910. return VPanelHandle(); // Defaults to INVALID_PANEL
  1911. }
  1912. return m_pDialogs[0];
  1913. }
  1914. //-----------------------------------------------------------------------------
  1915. // Purpose:
  1916. //-----------------------------------------------------------------------------
  1917. bool CPanelModalStack::IsEmpty() const
  1918. {
  1919. return m_pDialogs.Count() == 0;
  1920. }
  1921. //-----------------------------------------------------------------------------
  1922. // Purpose:
  1923. //-----------------------------------------------------------------------------
  1924. CGenericWaitingDialog::CGenericWaitingDialog( vgui::Panel *pParent )
  1925. : BaseClass( pParent, "GenericWaitingDialog" )
  1926. , m_bAnimateEllipses(false)
  1927. , m_iNumEllipses(0)
  1928. {
  1929. if ( pParent == NULL )
  1930. {
  1931. vgui::HScheme scheme = vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), "resource/ClientScheme.res", "ClientScheme");
  1932. SetScheme(scheme);
  1933. SetProportional( true );
  1934. }
  1935. }
  1936. void CGenericWaitingDialog::ApplySchemeSettings( vgui::IScheme *pScheme )
  1937. {
  1938. BaseClass::ApplySchemeSettings( pScheme );
  1939. LoadControlSettings( GetResFile(), GetResFilePathId() );
  1940. }
  1941. void CGenericWaitingDialog::Close()
  1942. {
  1943. OnCommand( "close" );
  1944. }
  1945. void CGenericWaitingDialog::OnCommand( const char *command )
  1946. {
  1947. bool bClose = false;
  1948. if ( !Q_stricmp( command, "close" ) )
  1949. {
  1950. bClose = true;
  1951. }
  1952. else if ( !Q_stricmp( command, "user_close" ) )
  1953. {
  1954. OnUserClose();
  1955. bClose = true;
  1956. }
  1957. if ( bClose )
  1958. {
  1959. TFModalStack()->PopModal( this );
  1960. SetVisible( false );
  1961. MarkForDeletion();
  1962. return;
  1963. }
  1964. BaseClass::OnCommand( command );
  1965. }
  1966. void CGenericWaitingDialog::OnTick( void )
  1967. {
  1968. BaseClass::OnTick();
  1969. if ( !IsVisible() )
  1970. {
  1971. vgui::ivgui()->RemoveTickSignal( GetVPanel() );
  1972. }
  1973. if ( m_bAnimateEllipses )
  1974. {
  1975. m_iNumEllipses = ((m_iNumEllipses+1) % 4);
  1976. switch ( m_iNumEllipses )
  1977. {
  1978. case 3: SetDialogVariable( "ellipses", L"..." ); break;
  1979. case 2: SetDialogVariable( "ellipses", L".." ); break;
  1980. case 1: SetDialogVariable( "ellipses", L"." ); break;
  1981. default: SetDialogVariable( "ellipses", L"" ); break;
  1982. }
  1983. }
  1984. if ( m_timer.HasStarted() )
  1985. {
  1986. // @note Tom Bui: showing 0 is weird, so just show nothing...
  1987. int iSecondsRemaining = (int)m_timer.GetRemainingTime();
  1988. if ( iSecondsRemaining == 0 )
  1989. {
  1990. SetDialogVariable( "duration", "" );
  1991. }
  1992. else
  1993. {
  1994. SetDialogVariable( "duration", iSecondsRemaining );
  1995. }
  1996. if ( m_timer.IsElapsed() )
  1997. {
  1998. OnCommand( "close" );
  1999. OnTimeout();
  2000. }
  2001. }
  2002. }
  2003. void CGenericWaitingDialog::ShowStatusUpdate( bool bAnimateEllipses, bool bAllowClose, float flMaxWaitTime )
  2004. {
  2005. CExButton *pButton = dynamic_cast<CExButton*>( FindChildByName("CloseButton") );
  2006. if ( pButton )
  2007. {
  2008. pButton->SetVisible( bAllowClose );
  2009. pButton->SetEnabled( bAllowClose );
  2010. }
  2011. m_bAnimateEllipses = bAnimateEllipses;
  2012. if ( flMaxWaitTime > 0 )
  2013. {
  2014. m_timer.Start( flMaxWaitTime );
  2015. SetDialogVariable( "duration", (int)flMaxWaitTime );
  2016. }
  2017. else
  2018. {
  2019. m_timer.Invalidate();
  2020. SetDialogVariable( "duration", L"" );
  2021. }
  2022. if ( m_bAnimateEllipses )
  2023. {
  2024. m_iNumEllipses = 0;
  2025. }
  2026. if ( flMaxWaitTime > 0 || m_bAnimateEllipses )
  2027. {
  2028. vgui::ivgui()->AddTickSignal( GetVPanel(), 500 );
  2029. }
  2030. SetDialogVariable( "ellipses", L"" );
  2031. }
  2032. void CGenericWaitingDialog::OnTimeout()
  2033. {
  2034. }
  2035. void CGenericWaitingDialog::OnUserClose()
  2036. {
  2037. }
  2038. static vgui::DHANDLE< CGenericWaitingDialog > g_WaitingDialog;
  2039. void ShowWaitingDialog( CGenericWaitingDialog *pWaitingDialog, const char* pUpdateText, bool bAnimate, bool bShowCancel, float flMaxDuration )
  2040. {
  2041. CloseWaitingDialog();
  2042. if ( pWaitingDialog )
  2043. {
  2044. g_WaitingDialog = vgui::SETUP_PANEL( pWaitingDialog );
  2045. g_WaitingDialog->SetVisible( true );
  2046. g_WaitingDialog->MakePopup();
  2047. g_WaitingDialog->MoveToFront();
  2048. g_WaitingDialog->SetKeyBoardInputEnabled(true);
  2049. g_WaitingDialog->SetMouseInputEnabled(true);
  2050. TFModalStack()->PushModal( g_WaitingDialog );
  2051. if ( pUpdateText != NULL )
  2052. {
  2053. g_WaitingDialog->SetDialogVariable( "updatetext", g_pVGuiLocalize->Find( pUpdateText ) );
  2054. }
  2055. g_WaitingDialog->ShowStatusUpdate( bAnimate, bShowCancel, flMaxDuration );
  2056. }
  2057. }
  2058. void CloseWaitingDialog()
  2059. {
  2060. if ( g_WaitingDialog.Get() )
  2061. {
  2062. g_WaitingDialog->Close();
  2063. g_WaitingDialog = NULL;
  2064. }
  2065. }
  2066. //-----------------------------------------------------------------------------