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.

790 lines
21 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "cbase.h"
  7. #include "hud.h"
  8. #include "hudelement.h"
  9. #include "hud_macros.h"
  10. #include "iclientmode.h"
  11. #include "vgui_controls/AnimationController.h"
  12. #include "vgui_controls/Label.h"
  13. #include "vgui/ILocalize.h"
  14. #include "vgui/ISurface.h"
  15. #include "text_message.h"
  16. #include "c_baseplayer.h"
  17. #include "IGameUIFuncs.h"
  18. #include "inputsystem/iinputsystem.h"
  19. // memdbgon must be the last include file in a .cpp file!!!
  20. #include "tier0/memdbgon.h"
  21. //-----------------------------------------------------------------------------
  22. // Purpose: Displays hints across the center of the screen
  23. //-----------------------------------------------------------------------------
  24. class CHudHintDisplay : public vgui::Panel, public CHudElement
  25. {
  26. DECLARE_CLASS_SIMPLE( CHudHintDisplay, vgui::Panel );
  27. public:
  28. CHudHintDisplay( const char *pElementName );
  29. void Init();
  30. void Reset();
  31. void MsgFunc_HintText( bf_read &msg );
  32. void FireGameEvent( IGameEvent * event);
  33. bool SetHintText( wchar_t *text );
  34. void LocalizeAndDisplay( const char *pszHudTxtMsg, const char *szRawString );
  35. virtual void PerformLayout();
  36. protected:
  37. virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
  38. virtual void OnThink();
  39. protected:
  40. vgui::HFont m_hFont;
  41. Color m_bgColor;
  42. vgui::Label *m_pLabel;
  43. CUtlVector<vgui::Label *> m_Labels;
  44. CPanelAnimationVarAliasType( int, m_iTextX, "text_xpos", "8", "proportional_int" );
  45. CPanelAnimationVarAliasType( int, m_iTextY, "text_ypos", "8", "proportional_int" );
  46. CPanelAnimationVarAliasType( int, m_iCenterX, "center_x", "0", "proportional_int" );
  47. CPanelAnimationVarAliasType( int, m_iCenterY, "center_y", "0", "proportional_int" );
  48. bool m_bLastLabelUpdateHack;
  49. CPanelAnimationVar( float, m_flLabelSizePercentage, "HintSize", "0" );
  50. };
  51. DECLARE_HUDELEMENT( CHudHintDisplay );
  52. DECLARE_HUD_MESSAGE( CHudHintDisplay, HintText );
  53. #define MAX_HINT_STRINGS 5
  54. //-----------------------------------------------------------------------------
  55. // Purpose: Constructor
  56. //-----------------------------------------------------------------------------
  57. CHudHintDisplay::CHudHintDisplay( const char *pElementName ) : BaseClass(NULL, "HudHintDisplay"), CHudElement( pElementName )
  58. {
  59. vgui::Panel *pParent = g_pClientMode->GetViewport();
  60. SetParent( pParent );
  61. SetVisible( false );
  62. m_pLabel = new vgui::Label( this, "HudHintDisplayLabel", "" );
  63. }
  64. //-----------------------------------------------------------------------------
  65. // Purpose:
  66. //-----------------------------------------------------------------------------
  67. void CHudHintDisplay::Init()
  68. {
  69. HOOK_HUD_MESSAGE( CHudHintDisplay, HintText );
  70. // listen for client side events
  71. ListenForGameEvent( "player_hintmessage" );
  72. }
  73. //-----------------------------------------------------------------------------
  74. // Purpose:
  75. //-----------------------------------------------------------------------------
  76. void CHudHintDisplay::Reset()
  77. {
  78. SetHintText( NULL );
  79. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "HintMessageHide" );
  80. m_bLastLabelUpdateHack = true;
  81. }
  82. //-----------------------------------------------------------------------------
  83. // Purpose:
  84. //-----------------------------------------------------------------------------
  85. void CHudHintDisplay::ApplySchemeSettings( vgui::IScheme *pScheme )
  86. {
  87. BaseClass::ApplySchemeSettings( pScheme );
  88. SetFgColor( GetSchemeColor("HintMessageFg", pScheme) );
  89. m_hFont = pScheme->GetFont( "HudHintText", true );
  90. m_pLabel->SetBgColor( GetSchemeColor("HintMessageBg", pScheme) );
  91. m_pLabel->SetPaintBackgroundType( 2 );
  92. m_pLabel->SetSize( 0, GetTall() ); // Start tiny, it'll grow.
  93. }
  94. //-----------------------------------------------------------------------------
  95. // Purpose: Sets the hint text, replacing variables as necessary
  96. //-----------------------------------------------------------------------------
  97. bool CHudHintDisplay::SetHintText( wchar_t *text )
  98. {
  99. if ( text == NULL || text[0] == L'\0' )
  100. {
  101. return false;
  102. }
  103. // clear the existing text
  104. for (int i = 0; i < m_Labels.Count(); i++)
  105. {
  106. m_Labels[i]->MarkForDeletion();
  107. }
  108. m_Labels.RemoveAll();
  109. wchar_t *p = text;
  110. while ( p )
  111. {
  112. wchar_t *line = p;
  113. wchar_t *end = wcschr( p, L'\n' );
  114. int linelengthbytes = 0;
  115. if ( end )
  116. {
  117. //*end = 0; //eek
  118. p = end+1;
  119. linelengthbytes = ( end - line ) * 2;
  120. }
  121. else
  122. {
  123. p = NULL;
  124. }
  125. // replace any key references with bound keys
  126. wchar_t buf[512];
  127. UTIL_ReplaceKeyBindings( line, linelengthbytes, buf, sizeof( buf ) );
  128. // put it in a label
  129. vgui::Label *label = vgui::SETUP_PANEL(new vgui::Label(this, NULL, buf));
  130. label->SetFont( m_hFont );
  131. label->SetPaintBackgroundEnabled( false );
  132. label->SetPaintBorderEnabled( false );
  133. label->SizeToContents();
  134. label->SetContentAlignment( vgui::Label::a_west );
  135. label->SetFgColor( GetFgColor() );
  136. m_Labels.AddToTail( vgui::SETUP_PANEL(label) );
  137. }
  138. InvalidateLayout( true );
  139. return true;
  140. }
  141. //-----------------------------------------------------------------------------
  142. // Purpose: Resizes the label
  143. //-----------------------------------------------------------------------------
  144. void CHudHintDisplay::PerformLayout()
  145. {
  146. BaseClass::PerformLayout();
  147. int i;
  148. int wide, tall;
  149. GetSize( wide, tall );
  150. // find the widest line
  151. int iDesiredLabelWide = 0;
  152. for ( i=0; i < m_Labels.Count(); ++i )
  153. {
  154. iDesiredLabelWide = MAX( iDesiredLabelWide, m_Labels[i]->GetWide() );
  155. }
  156. // find the total height
  157. int fontTall = vgui::surface()->GetFontTall( m_hFont );
  158. int labelTall = fontTall * m_Labels.Count();
  159. iDesiredLabelWide += m_iTextX*2;
  160. labelTall += m_iTextY*2;
  161. // Now clamp it to our animation size
  162. iDesiredLabelWide = (iDesiredLabelWide * m_flLabelSizePercentage);
  163. int x, y;
  164. if ( m_iCenterX < 0 )
  165. {
  166. x = 0;
  167. }
  168. else if ( m_iCenterX > 0 )
  169. {
  170. x = wide - iDesiredLabelWide;
  171. }
  172. else
  173. {
  174. x = (wide - iDesiredLabelWide) / 2;
  175. }
  176. if ( m_iCenterY > 0 )
  177. {
  178. y = 0;
  179. }
  180. else if ( m_iCenterY < 0 )
  181. {
  182. y = tall - labelTall;
  183. }
  184. else
  185. {
  186. y = (tall - labelTall) / 2;
  187. }
  188. x = MAX(x,0);
  189. y = MAX(y,0);
  190. iDesiredLabelWide = MIN(iDesiredLabelWide,wide);
  191. m_pLabel->SetBounds( x, y, iDesiredLabelWide, labelTall );
  192. // now lay out the sub-labels
  193. for ( i=0; i<m_Labels.Count(); ++i )
  194. {
  195. int xOffset = (wide - m_Labels[i]->GetWide()) * 0.5;
  196. m_Labels[i]->SetPos( xOffset, y + m_iTextY + i*fontTall );
  197. }
  198. }
  199. //-----------------------------------------------------------------------------
  200. // Purpose: Updates the label color each frame
  201. //-----------------------------------------------------------------------------
  202. void CHudHintDisplay::OnThink()
  203. {
  204. m_pLabel->SetFgColor(GetFgColor());
  205. for (int i = 0; i < m_Labels.Count(); i++)
  206. {
  207. m_Labels[i]->SetFgColor(GetFgColor());
  208. }
  209. // If our label size isn't at the extreme's, we're sliding open / closed
  210. // This is a hack to get around InvalideLayout() not getting called when
  211. // m_flLabelSizePercentage is changed via a HudAnimation.
  212. if ( ( m_flLabelSizePercentage != 0.0 && m_flLabelSizePercentage != 1.0 ) || m_bLastLabelUpdateHack )
  213. {
  214. m_bLastLabelUpdateHack = (m_flLabelSizePercentage != 0.0 && m_flLabelSizePercentage != 1.0);
  215. InvalidateLayout();
  216. }
  217. }
  218. //-----------------------------------------------------------------------------
  219. // Purpose: Activates the hint display
  220. //-----------------------------------------------------------------------------
  221. void CHudHintDisplay::MsgFunc_HintText( bf_read &msg )
  222. {
  223. // Read the string(s)
  224. char szString[255];
  225. msg.ReadString( szString, sizeof(szString) );
  226. char *tmpStr = hudtextmessage->LookupString( szString, NULL );
  227. LocalizeAndDisplay( tmpStr, szString );
  228. }
  229. //-----------------------------------------------------------------------------
  230. // Purpose: Activates the hint display upon receiving a hint
  231. //-----------------------------------------------------------------------------
  232. void CHudHintDisplay::FireGameEvent( IGameEvent * event)
  233. {
  234. const char *hintmessage = event->GetString( "hintmessage" );
  235. char *tmpStr = hudtextmessage->LookupString( hintmessage, NULL );
  236. LocalizeAndDisplay( tmpStr, hintmessage );
  237. }
  238. extern ConVar sv_hudhint_sound;
  239. ConVar cl_hudhint_sound( "cl_hudhint_sound", "1", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Disable hudhint sounds." );
  240. //-----------------------------------------------------------------------------
  241. // Purpose: Localize, display, and animate the hud element
  242. //-----------------------------------------------------------------------------
  243. void CHudHintDisplay::LocalizeAndDisplay( const char *pszHudTxtMsg, const char *szRawString )
  244. {
  245. static wchar_t szBuf[128];
  246. wchar_t *pszBuf;
  247. // init buffers & pointers
  248. szBuf[0] = 0;
  249. pszBuf = szBuf;
  250. // try to localize
  251. if ( pszHudTxtMsg )
  252. {
  253. pszBuf = g_pVGuiLocalize->Find( pszHudTxtMsg );
  254. }
  255. else
  256. {
  257. pszBuf = g_pVGuiLocalize->Find( szRawString );
  258. }
  259. if ( !pszBuf )
  260. {
  261. // use plain ASCII string
  262. g_pVGuiLocalize->ConvertANSIToUnicode( szRawString, szBuf, sizeof(szBuf) );
  263. pszBuf = szBuf;
  264. }
  265. // make it visible
  266. if ( SetHintText( pszBuf ) )
  267. {
  268. SetVisible( true );
  269. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "HintMessageShow" );
  270. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  271. if ( pLocalPlayer )
  272. {
  273. #ifndef HL2MP
  274. if ( sv_hudhint_sound.GetBool() && cl_hudhint_sound.GetBool() )
  275. {
  276. pLocalPlayer->EmitSound( "Hud.Hint" );
  277. }
  278. #endif // HL2MP
  279. if ( pLocalPlayer->Hints() )
  280. {
  281. pLocalPlayer->Hints()->PlayedAHint();
  282. }
  283. }
  284. }
  285. else
  286. {
  287. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "HintMessageHide" );
  288. }
  289. }
  290. //-----------------------------------------------------------------------------
  291. // Purpose: Displays small key-centric hints on the right hand side of the screen
  292. //-----------------------------------------------------------------------------
  293. class CHudHintKeyDisplay : public vgui::Panel, public CHudElement
  294. {
  295. DECLARE_CLASS_SIMPLE( CHudHintKeyDisplay, vgui::Panel );
  296. public:
  297. CHudHintKeyDisplay( const char *pElementName );
  298. void Init();
  299. void Reset();
  300. void MsgFunc_KeyHintText( bf_read &msg );
  301. bool ShouldDraw();
  302. bool SetHintText( const char *text );
  303. protected:
  304. virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
  305. virtual void OnThink();
  306. private:
  307. CUtlVector<vgui::Label *> m_Labels;
  308. vgui::HFont m_hSmallFont, m_hLargeFont;
  309. int m_iBaseY;
  310. CPanelAnimationVarAliasType( float, m_iTextX, "text_xpos", "8", "proportional_float" );
  311. CPanelAnimationVarAliasType( float, m_iTextY, "text_ypos", "8", "proportional_float" );
  312. CPanelAnimationVarAliasType( float, m_iTextGapX, "text_xgap", "8", "proportional_float" );
  313. CPanelAnimationVarAliasType( float, m_iTextGapY, "text_ygap", "8", "proportional_float" );
  314. CPanelAnimationVarAliasType( float, m_iYOffset, "YOffset", "0", "proportional_float" );
  315. };
  316. DECLARE_HUDELEMENT( CHudHintKeyDisplay );
  317. DECLARE_HUD_MESSAGE( CHudHintKeyDisplay, KeyHintText );
  318. //-----------------------------------------------------------------------------
  319. // Purpose: Constructor
  320. //-----------------------------------------------------------------------------
  321. CHudHintKeyDisplay::CHudHintKeyDisplay( const char *pElementName ) : BaseClass(NULL, "HudHintKeyDisplay"), CHudElement( pElementName )
  322. {
  323. vgui::Panel *pParent = g_pClientMode->GetViewport();
  324. SetParent( pParent );
  325. SetVisible( false );
  326. SetAlpha( 0 );
  327. }
  328. //-----------------------------------------------------------------------------
  329. // Purpose:
  330. //-----------------------------------------------------------------------------
  331. void CHudHintKeyDisplay::Init()
  332. {
  333. HOOK_HUD_MESSAGE( CHudHintKeyDisplay, KeyHintText );
  334. }
  335. //-----------------------------------------------------------------------------
  336. // Purpose:
  337. //-----------------------------------------------------------------------------
  338. void CHudHintKeyDisplay::Reset()
  339. {
  340. SetHintText( NULL );
  341. SetAlpha( 0 );
  342. }
  343. //-----------------------------------------------------------------------------
  344. // Purpose:
  345. //-----------------------------------------------------------------------------
  346. void CHudHintKeyDisplay::ApplySchemeSettings( vgui::IScheme *pScheme )
  347. {
  348. m_hSmallFont = pScheme->GetFont( "HudHintTextSmall", true );
  349. m_hLargeFont = pScheme->GetFont( "HudHintTextLarge", true );
  350. BaseClass::ApplySchemeSettings( pScheme );
  351. }
  352. //-----------------------------------------------------------------------------
  353. // Purpose: Save CPU cycles by letting the HUD system early cull
  354. // costly traversal. Called per frame, return true if thinking and
  355. // painting need to occur.
  356. //-----------------------------------------------------------------------------
  357. bool CHudHintKeyDisplay::ShouldDraw( void )
  358. {
  359. return ( ( GetAlpha() > 0 ) && CHudElement::ShouldDraw() );
  360. }
  361. //-----------------------------------------------------------------------------
  362. // Purpose: Updates the label color each frame
  363. //-----------------------------------------------------------------------------
  364. void CHudHintKeyDisplay::OnThink()
  365. {
  366. for (int i = 0; i < m_Labels.Count(); i++)
  367. {
  368. if ( IsX360() && ( i & 1 ) == 0 )
  369. {
  370. // Don't change the fg color for buttons (even numbered labels)
  371. m_Labels[i]->SetAlpha( GetFgColor().a() );
  372. }
  373. else
  374. {
  375. m_Labels[i]->SetFgColor(GetFgColor());
  376. }
  377. }
  378. int ox, oy;
  379. GetPos(ox, oy);
  380. SetPos( ox, m_iBaseY + m_iYOffset );
  381. }
  382. //-----------------------------------------------------------------------------
  383. // Purpose: Sets the hint text, replacing variables as necessary
  384. //-----------------------------------------------------------------------------
  385. bool CHudHintKeyDisplay::SetHintText( const char *text )
  386. {
  387. if ( text == NULL || text[0] == L'\0' )
  388. return false;
  389. // clear the existing text
  390. for (int i = 0; i < m_Labels.Count(); i++)
  391. {
  392. m_Labels[i]->MarkForDeletion();
  393. }
  394. m_Labels.RemoveAll();
  395. // look up the text string
  396. wchar_t *ws = g_pVGuiLocalize->Find( text );
  397. wchar_t wszBuf[256];
  398. if ( !ws || wcslen(ws) <= 0)
  399. {
  400. if (text[0] == '#')
  401. {
  402. // We don't want to display a localization placeholder, do we?
  403. return false;
  404. }
  405. // use plain ASCII string
  406. g_pVGuiLocalize->ConvertANSIToUnicode(text, wszBuf, sizeof(wszBuf));
  407. ws = wszBuf;
  408. }
  409. // parse out the text into a label set
  410. while ( *ws )
  411. {
  412. wchar_t token[256];
  413. bool isVar = false;
  414. // check for variables
  415. if ( *ws == '%' )
  416. {
  417. isVar = true;
  418. ++ws;
  419. }
  420. // parse out the string
  421. wchar_t *end = wcschr( ws, '%' );
  422. if ( end )
  423. {
  424. wcsncpy( token, ws, MIN( end - ws, ARRAYSIZE(token)) );
  425. token[end - ws] = L'\0'; // force null termination
  426. }
  427. else
  428. {
  429. wcsncpy( token, ws, ARRAYSIZE(token) );
  430. token[ ARRAYSIZE(token) - 1 ] = L'\0'; // force null termination
  431. }
  432. ws += wcslen( token );
  433. if ( isVar )
  434. {
  435. // move over the end of the variable
  436. ++ws;
  437. }
  438. // put it in a label
  439. vgui::Label *label = vgui::SETUP_PANEL(new vgui::Label(this, NULL, token));
  440. bool bIsBitmap = false;
  441. // modify the label if necessary
  442. if ( isVar )
  443. {
  444. label->SetFont( m_hLargeFont );
  445. // lookup key names
  446. char binding[64];
  447. g_pVGuiLocalize->ConvertUnicodeToANSI( token, binding, sizeof(binding) );
  448. //!! change some key names into better names
  449. char friendlyName[64];
  450. if ( IsX360() )
  451. {
  452. int iNumBinds = 0;
  453. char szBuff[ 512 ];
  454. wchar_t szWideBuff[ 64 ];
  455. for ( int iCode = 0; iCode < BUTTON_CODE_LAST; ++iCode )
  456. {
  457. ButtonCode_t code = static_cast<ButtonCode_t>( iCode );
  458. bool bUseThisKey = false;
  459. // Only check against bind name if we haven't already forced this binding to be used
  460. const char *pBinding = gameuifuncs->GetBindingForButtonCode( code );
  461. if ( !pBinding )
  462. continue;
  463. bUseThisKey = ( Q_stricmp( pBinding, binding ) == 0 );
  464. if ( !bUseThisKey &&
  465. ( Q_stricmp( pBinding, "+duck" ) == 0 || Q_stricmp( pBinding, "toggle_duck" ) == 0 ) &&
  466. ( Q_stricmp( binding, "+duck" ) == 0 || Q_stricmp( binding, "toggle_duck" ) == 0 ) )
  467. {
  468. // +duck and toggle_duck are interchangable
  469. bUseThisKey = true;
  470. }
  471. if ( !bUseThisKey &&
  472. ( Q_stricmp( pBinding, "+zoom" ) == 0 || Q_stricmp( pBinding, "toggle_zoom" ) == 0 ) &&
  473. ( Q_stricmp( binding, "+zoom" ) == 0 || Q_stricmp( binding, "toggle_zoom" ) == 0 ) )
  474. {
  475. // +zoom and toggle_zoom are interchangable
  476. bUseThisKey = true;
  477. }
  478. // Don't use this bind in out list
  479. if ( !bUseThisKey )
  480. continue;
  481. // Turn localized string into icon character
  482. Q_snprintf( szBuff, sizeof( szBuff ), "#GameUI_Icons_%s", g_pInputSystem->ButtonCodeToString( static_cast<ButtonCode_t>( iCode ) ) );
  483. g_pVGuiLocalize->ConstructString_safe( szWideBuff, g_pVGuiLocalize->Find( szBuff ), 0 );
  484. g_pVGuiLocalize->ConvertUnicodeToANSI( szWideBuff, szBuff, sizeof( szBuff ) );
  485. // Add this icon to our list of keys to display
  486. friendlyName[ iNumBinds ] = szBuff[ 0 ];
  487. ++iNumBinds;
  488. }
  489. friendlyName[ iNumBinds ] = '\0';
  490. if ( iNumBinds == 0 )
  491. {
  492. friendlyName[ 0 ] = '\0';
  493. label->SetFont( m_hSmallFont );
  494. label->SetText( "#GameUI_Icons_NONE" );
  495. }
  496. else
  497. {
  498. // 360 always uses bitmaps
  499. bIsBitmap = true;
  500. label->SetText( friendlyName );
  501. }
  502. }
  503. else
  504. {
  505. const char *key = engine->Key_LookupBinding( *binding == '+' ? binding + 1 : binding );
  506. if ( !key )
  507. {
  508. key = "< not bound >";
  509. }
  510. Q_snprintf( friendlyName, sizeof(friendlyName), "#%s", key );
  511. Q_strupr( friendlyName );
  512. // set the variable text - key may need to be localized (button images for example)
  513. wchar_t *locName = g_pVGuiLocalize->Find( friendlyName );
  514. if ( !locName || wcslen(locName) <= 0)
  515. {
  516. label->SetText( friendlyName + 1 );
  517. }
  518. else
  519. {
  520. // Assuming localized vars must be using a bitmap image. *May* not be the case, but since
  521. // keyboard bindings have never been localized in the past, they probably won't in the future either.
  522. bIsBitmap = true;
  523. label->SetText( locName );
  524. }
  525. }
  526. }
  527. else
  528. {
  529. label->SetFont( m_hSmallFont );
  530. }
  531. label->SetPaintBackgroundEnabled( false );
  532. label->SetPaintBorderEnabled( false );
  533. label->SizeToContents();
  534. label->SetContentAlignment( vgui::Label::a_west );
  535. if ( bIsBitmap && isVar )
  536. {
  537. // Don't change the color of the button art
  538. label->SetFgColor( Color(255,255,255,255) );
  539. }
  540. else
  541. {
  542. label->SetFgColor( GetFgColor() );
  543. }
  544. m_Labels.AddToTail( vgui::SETUP_PANEL(label) );
  545. }
  546. // Enable this small block of code to test formatting and layout of hint messages
  547. // with varying numbers of lines
  548. #define TEST_KEYHINT_DISPLAY 0
  549. #if TEST_KEYHINT_DISPLAY
  550. // clear the existing text
  551. for (int i = 0; i < m_Labels.Count(); i++)
  552. {
  553. m_Labels[i]->MarkForDeletion();
  554. }
  555. m_Labels.RemoveAll();
  556. const char* sampleText[] =
  557. {
  558. "This is a test",
  559. "of the hint system\nwith a multi-line hint",
  560. "that\ngoes\non\nfor",
  561. "several",
  562. "lines"
  563. };
  564. for ( int i = 0; i < ARRAYSIZE(sampleText); ++i)
  565. {
  566. // put it in a label
  567. vgui::Label *label = vgui::SETUP_PANEL(new vgui::Label(this, NULL, sampleText[i]));
  568. label->SetFont( m_hSmallFont );
  569. label->SetPaintBackgroundEnabled( false );
  570. label->SetPaintBorderEnabled( false );
  571. label->SizeToContents();
  572. label->SetContentAlignment( vgui::Label::a_west );
  573. label->SetFgColor( GetFgColor() );
  574. m_Labels.AddToTail( vgui::SETUP_PANEL(label) );
  575. }
  576. #endif
  577. // find the bounds we need to show
  578. int widest1 = 0, widest2 = 0;
  579. for (int i = 0; i < m_Labels.Count(); i++)
  580. {
  581. vgui::Label *label = m_Labels[i];
  582. if (i & 1)
  583. {
  584. // help text
  585. if (label->GetWide() > widest2)
  586. {
  587. widest2 = label->GetWide();
  588. }
  589. }
  590. else
  591. {
  592. // variable
  593. if (label->GetWide() > widest1)
  594. {
  595. widest1 = label->GetWide();
  596. }
  597. }
  598. }
  599. // position the labels
  600. int col1_x = m_iTextX;
  601. int col2_x = m_iTextX + widest1 + m_iTextGapX;
  602. int col_y = m_iTextY;
  603. for (int i = 0; i < m_Labels.Count(); i += 2)
  604. {
  605. int rowHeight = 0;
  606. vgui::Label *label0 = m_Labels[i];
  607. int tall0 = label0->GetTall();
  608. rowHeight = tall0;
  609. if (i + 1 < m_Labels.Count())
  610. {
  611. vgui::Label *label1 = m_Labels[i + 1];
  612. int tall1 = label1->GetTall();
  613. rowHeight = MAX(tall0, tall1);
  614. label1->SetPos( col2_x, col_y + (rowHeight - tall1) / 2 );
  615. }
  616. label0->SetPos( col1_x, col_y + (rowHeight - tall0) / 2 );
  617. col_y += rowHeight + m_iTextGapY;
  618. }
  619. // move ourselves relative to our start position
  620. int newWide = m_iTextX + col2_x + widest2;
  621. int newTall = col_y;
  622. int ox, oy;
  623. GetPos(ox, oy);
  624. if (IsRightAligned())
  625. {
  626. int oldWide = GetWide();
  627. int diff = newWide - oldWide;
  628. ox -= diff;
  629. }
  630. if (IsBottomAligned())
  631. {
  632. int oldTall = GetTall();
  633. int diff = newTall - oldTall;
  634. oy -= diff;
  635. }
  636. // set the size of the hint panel to fit
  637. SetPos( ox, oy );
  638. SetSize( newWide, newTall );
  639. m_iBaseY = oy;
  640. return true;
  641. }
  642. //-----------------------------------------------------------------------------
  643. // Purpose: Activates the hint display
  644. //-----------------------------------------------------------------------------
  645. void CHudHintKeyDisplay::MsgFunc_KeyHintText( bf_read &msg )
  646. {
  647. // how many strings do we receive ?
  648. int count = msg.ReadByte();
  649. // here we expect only one string
  650. if ( count != 1 )
  651. {
  652. DevMsg("CHudHintKeyDisplay::MsgFunc_KeyHintText: string count != 1.\n");
  653. return;
  654. }
  655. // read the string
  656. char szString[2048];
  657. msg.ReadString( szString, sizeof(szString) );
  658. // make it visible
  659. if ( SetHintText( szString ) )
  660. {
  661. SetVisible( true );
  662. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "KeyHintMessageShow" );
  663. }
  664. else
  665. {
  666. // it's being cleared, hide the panel
  667. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "KeyHintMessageHide" );
  668. }
  669. }