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.

374 lines
11 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. //----------------------------------------------------------------------------------------
  4. #include "cbase.h"
  5. #if defined( REPLAY_ENABLED )
  6. #include "replaymessagepanel.h"
  7. #include "vgui_controls/CheckButton.h"
  8. #include "ienginevgui.h"
  9. #include "vgui_controls/PHandle.h"
  10. #include "econ/econ_controls.h"
  11. #if defined( CSTRIKE_DLL )
  12. # include "cstrike/clientmode_csnormal.h"
  13. #elif defined( TF_CLIENT_DLL )
  14. # include "tf/clientmode_tf.h"
  15. #endif
  16. // memdbgon must be the last include file in a .cpp file!!!
  17. #include <tier0/memdbgon.h>
  18. //-----------------------------------------------------------------------------
  19. #if _DEBUG
  20. CON_COMMAND( testreplaymessagepanel, "" )
  21. {
  22. CReplayMessagePanel *pPanel = new CReplayMessagePanel( "#Replay_StartRecord", replay_msgduration_misc.GetFloat(), rand()%2==0);
  23. pPanel->Show();
  24. }
  25. CON_COMMAND( testreplaymessagedlg, "" )
  26. {
  27. CReplayMessageDlg *pPanel = SETUP_PANEL( new CReplayMessageDlg( "text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text." ) );
  28. pPanel->SetVisible( true );
  29. pPanel->MakePopup();
  30. pPanel->MoveToFront();
  31. pPanel->SetKeyBoardInputEnabled( true );
  32. pPanel->SetMouseInputEnabled( true );
  33. pPanel->RequestFocus();
  34. engine->ClientCmd_Unrestricted( "gameui_hide" );
  35. }
  36. #endif
  37. //-----------------------------------------------------------------------------
  38. using namespace vgui;
  39. //-----------------------------------------------------------------------------
  40. typedef vgui::DHANDLE< CReplayMessagePanel > ReplayMessagePanelHandle_t;
  41. static CUtlVector< ReplayMessagePanelHandle_t > g_vecReplayMessagePanels;
  42. //-----------------------------------------------------------------------------
  43. ConVar replay_msgduration_startrecord( "replay_msgduration_startrecord", "6", FCVAR_DONTRECORD, "Duration for start record message.", true, 0.0f, true, 10.0f );
  44. ConVar replay_msgduration_stoprecord( "replay_msgduration_stoprecord", "6", FCVAR_DONTRECORD, "Duration for stop record message.", true, 0.0f, true, 10.0f );
  45. ConVar replay_msgduration_replaysavailable( "replay_msgduration_replaysavailable", "6", FCVAR_DONTRECORD, "Duration for replays available message.", true, 0.0f, true, 10.0f );
  46. ConVar replay_msgduration_error( "replay_msgduration_error", "6", FCVAR_DONTRECORD, "Duration for replays available message.", true, 0.0f, true, 10.0f );
  47. ConVar replay_msgduration_misc( "replay_msgduration_misc", "5", FCVAR_DONTRECORD, "Duration for misc replays messages (server errors and such).", true, 0.0f, true, 10.0f );
  48. ConVar replay_msgduration_connectrecording( "replay_msgduration_connectrecording", "8", FCVAR_DONTRECORD, "Duration for the message that pops up when you connect to a server already recording replays.", true, 0.0f, true, 15.0f );
  49. //-----------------------------------------------------------------------------
  50. CReplayMessageDlg::CReplayMessageDlg( const char *pText )
  51. : BaseClass( NULL, "ReplayMessageDlg" ),
  52. m_pOKButton( NULL ),
  53. m_pDlg( NULL ),
  54. m_pMsgLabel( NULL )
  55. {
  56. InvalidateLayout( true, true );
  57. m_pMsgLabel->SetText( pText );
  58. }
  59. CReplayMessageDlg::~CReplayMessageDlg()
  60. {
  61. }
  62. void CReplayMessageDlg::ApplySchemeSettings( IScheme *pScheme )
  63. {
  64. // Link in TF scheme
  65. extern IEngineVGui *enginevgui;
  66. vgui::HScheme pTFScheme = vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), "resource/ClientScheme.res", "ClientScheme" );
  67. SetScheme( pTFScheme );
  68. SetProportional( true );
  69. BaseClass::ApplySchemeSettings( vgui::scheme()->GetIScheme( pTFScheme ) );
  70. LoadControlSettings( "resource/ui/replaymessagedlg.res", "GAME" );
  71. m_pDlg = FindChildByName( "Dlg" );
  72. m_pOKButton = dynamic_cast< CExButton * >( m_pDlg->FindChildByName( "OKButton" ) );
  73. m_pMsgLabel = dynamic_cast< CExLabel * >( m_pDlg->FindChildByName( "TextLabel") );
  74. m_pOKButton->AddActionSignalTarget( this );
  75. }
  76. void CReplayMessageDlg::PerformLayout()
  77. {
  78. BaseClass::PerformLayout();
  79. SetWide( ScreenWidth() );
  80. SetTall( ScreenHeight() );
  81. // Center dlg on screen
  82. m_pDlg->SetPos( ( ScreenWidth() - m_pDlg->GetWide() ) / 2, ( ScreenHeight() - m_pDlg->GetTall() ) / 2 );
  83. // Position OK below text label, centered horizontally
  84. int nButtonX = XRES(13);
  85. int nButtonY = m_pDlg->GetTall() - m_pOKButton->GetTall() - YRES( 10 );
  86. m_pOKButton->SetPos( nButtonX, nButtonY );
  87. }
  88. void CReplayMessageDlg::Close()
  89. {
  90. // Hide / delete / hide game UI
  91. SetVisible( false );
  92. MarkForDeletion();
  93. engine->ClientCmd_Unrestricted( "gameui_hide" );
  94. }
  95. void CReplayMessageDlg::OnCommand( const char *pCommand )
  96. {
  97. if ( FStrEq( pCommand, "close" ) )
  98. {
  99. Close();
  100. }
  101. BaseClass::OnCommand( pCommand );
  102. }
  103. void CReplayMessageDlg::OnKeyCodeTyped( KeyCode nCode )
  104. {
  105. switch ( nCode )
  106. {
  107. case KEY_ESCAPE:
  108. case KEY_SPACE:
  109. case KEY_ENTER:
  110. Close();
  111. return;
  112. }
  113. BaseClass::OnKeyCodeTyped( nCode );
  114. }
  115. //-----------------------------------------------------------------------------
  116. int CReplayMessagePanel::InstanceCount()
  117. {
  118. return g_vecReplayMessagePanels.Count();
  119. }
  120. void CReplayMessagePanel::RemoveAll()
  121. {
  122. FOR_EACH_VEC( g_vecReplayMessagePanels, i )
  123. {
  124. CReplayMessagePanel *pCurPanel = g_vecReplayMessagePanels[ i ];
  125. pCurPanel->MarkForDeletion();
  126. }
  127. g_vecReplayMessagePanels.RemoveAll();
  128. }
  129. //-----------------------------------------------------------------------------
  130. ReplayMessagePanelHandle_t GetReplayMessagePanelHandle( CReplayMessagePanel *pPanel )
  131. {
  132. ReplayMessagePanelHandle_t hThis;
  133. hThis = pPanel;
  134. return hThis;
  135. }
  136. CReplayMessagePanel::CReplayMessagePanel( const char *pLocalizeName, float flDuration, bool bUrgent )
  137. : EditablePanel( g_pClientMode->GetViewport(), "ReplayMessagePanel" ),
  138. m_bUrgent( bUrgent )
  139. {
  140. m_flShowStartTime = 0;
  141. m_flShowDuration = flDuration;
  142. m_pMessageLabel = new CExLabel( this, "MessageLabel", pLocalizeName );
  143. m_pReplayLabel = new CExLabel( this, "ReplayLabel", "" );
  144. m_pIcon = new ImagePanel( this, "Icon" );
  145. #if defined( TF_CLIENT_DLL )
  146. const char *pBorderName = bUrgent ? "ReplayFatLineBorderRedBGOpaque" : "ReplayFatLineBorderOpaque";
  147. V_strncpy( m_szBorderName, pBorderName, sizeof( m_szBorderName ) );
  148. #endif
  149. g_vecReplayMessagePanels.AddToTail( GetReplayMessagePanelHandle( const_cast< CReplayMessagePanel * >( this ) ) );
  150. InvalidateLayout( true, true );
  151. ivgui()->AddTickSignal( GetVPanel(), 10 );
  152. }
  153. CReplayMessagePanel::~CReplayMessagePanel()
  154. {
  155. // CUtlVector<>::Find() vomits.
  156. int iFind = g_vecReplayMessagePanels.InvalidIndex();
  157. FOR_EACH_VEC( g_vecReplayMessagePanels, i )
  158. {
  159. if ( g_vecReplayMessagePanels[ i ].Get() == this )
  160. {
  161. iFind = i;
  162. }
  163. }
  164. // Remove, if found.
  165. if ( iFind != g_vecReplayMessagePanels.InvalidIndex() )
  166. {
  167. g_vecReplayMessagePanels.FastRemove( iFind );
  168. }
  169. ivgui()->RemoveTickSignal( GetVPanel() );
  170. }
  171. void CReplayMessagePanel::Show()
  172. {
  173. m_pMessageLabel->SetVisible( true );
  174. // Setup start time
  175. m_flShowStartTime = gpGlobals->curtime;
  176. m_pMessageLabel->MoveToFront();
  177. SetAlpha( 0 );
  178. }
  179. inline float LerpScale( float flIn, float flInMin, float flInMax, float flOutMin, float flOutMax )
  180. {
  181. float flDenom = flInMax - flInMin;
  182. if ( flDenom == 0.0f )
  183. return 0.0f;
  184. float t = clamp( ( flIn - flInMin ) / flDenom, 0.0f, 1.0f );
  185. return Lerp( t, flOutMin, flOutMax );
  186. }
  187. inline float SCurve( float t )
  188. {
  189. t = clamp( t, 0.0f, 1.0f );
  190. return t * t * (3 - 2*t);
  191. }
  192. void CReplayMessagePanel::OnTick()
  193. {
  194. // Hide if taking screenshot
  195. extern ConVar hud_freezecamhide;
  196. extern bool IsTakingAFreezecamScreenshot();
  197. if ( hud_freezecamhide.GetBool() && IsTakingAFreezecamScreenshot() )
  198. {
  199. SetVisible( false );
  200. return;
  201. }
  202. // Delete the panel if life exceeded
  203. const float flEndTime = m_flShowStartTime + m_flShowDuration;
  204. if ( gpGlobals->curtime >= flEndTime )
  205. {
  206. SetVisible( false );
  207. MarkForDeletion();
  208. return;
  209. }
  210. SetVisible( true );
  211. const float flFadeDuration = .4f;
  212. float flAlpha;
  213. // Fade out?
  214. if ( gpGlobals->curtime >= flEndTime - flFadeDuration )
  215. {
  216. flAlpha = LerpScale( gpGlobals->curtime, flEndTime - flFadeDuration, flEndTime, 1.0f, 0.0f );
  217. }
  218. // Fade in?
  219. else if ( gpGlobals->curtime <= m_flShowStartTime + flFadeDuration )
  220. {
  221. flAlpha = LerpScale( gpGlobals->curtime, m_flShowStartTime, m_flShowStartTime + flFadeDuration, 0.0f, 1.0f );
  222. }
  223. // Otherwise, we must be in between fade in/fade out
  224. else
  225. {
  226. flAlpha = 1.0f;
  227. }
  228. SetAlpha( 255 * SCurve( flAlpha ) );
  229. }
  230. void CReplayMessagePanel::ApplySchemeSettings( IScheme *pScheme )
  231. {
  232. BaseClass::ApplySchemeSettings( pScheme );
  233. LoadControlSettings( "resource/ui/replaymessage.res", "GAME" );
  234. #if defined( CSTRIKE_DLL )
  235. SetPaintBackgroundEnabled( true );
  236. SetPaintBorderEnabled( false );
  237. SetPaintBackgroundType( 0 );
  238. SetBgColor( pScheme->GetColor( m_bUrgent ? "DarkRed" : "DarkGray", Color( 255, 255, 255, 255 ) ) );
  239. #endif
  240. }
  241. void CReplayMessagePanel::PerformLayout()
  242. {
  243. BaseClass::PerformLayout();
  244. #if defined( TF_CLIENT_DLL )
  245. // Set the border if one was specified
  246. if ( m_szBorderName[0] )
  247. {
  248. SetBorder( scheme()->GetIScheme( GetScheme() )->GetBorder( m_szBorderName ) );
  249. }
  250. #endif
  251. // Adjust overall panel size depending on min-mode
  252. #if defined( TF_CLIENT_DLL )
  253. extern ConVar cl_hud_minmode;
  254. bool bMinMode = cl_hud_minmode.GetBool();
  255. #else
  256. bool bMinMode = false;
  257. #endif
  258. int nVerticalBuffer = bMinMode ? YRES(3) : YRES(5);
  259. int nMessageLabelY = nVerticalBuffer;
  260. int nVerticalOffsetBetweenPanels = YRES(6);
  261. // Only display replay icon and "replay" label if this is the top-most (vertically) panel
  262. // and we're not in min-mode
  263. Assert( InstanceCount() > 0 );
  264. if ( !InstanceCount() || bMinMode || g_vecReplayMessagePanels[ 0 ].Get() != this )
  265. {
  266. m_pIcon->SetTall( 0 );
  267. m_pReplayLabel->SetTall( 0 );
  268. nVerticalOffsetBetweenPanels = YRES(1);
  269. }
  270. else
  271. {
  272. m_pReplayLabel->SizeToContents();
  273. nMessageLabelY += m_pReplayLabel->GetTall();
  274. nVerticalOffsetBetweenPanels = YRES(6);
  275. }
  276. // Resize the message label to fit the text
  277. m_pMessageLabel->SizeToContents();
  278. // Adjust this panel's height to fit the label size
  279. SetTall( nMessageLabelY + m_pMessageLabel->GetTall() + nVerticalBuffer );
  280. // Set the message label's position
  281. m_pMessageLabel->SetPos( XRES(8), nMessageLabelY );
  282. // Get the bottom of the bottom-most message panel
  283. int nMaxY = 0;
  284. FOR_EACH_VEC( g_vecReplayMessagePanels, it )
  285. {
  286. CReplayMessagePanel *pPanel = g_vecReplayMessagePanels[ it ];
  287. if ( pPanel == this )
  288. continue;
  289. int nX, nY;
  290. pPanel->GetPos( nX, nY );
  291. nMaxY = MAX( nMaxY, pPanel->GetTall() + nY );
  292. }
  293. // Adjust this panel's position to be below bottom-most panel
  294. // NOTE: Intentionally using YRES() for xpos, since we want to match offsets in both x & y margins
  295. SetPos( YRES(6), nMaxY + nVerticalOffsetBetweenPanels );
  296. }
  297. //-----------------------------------------------------------------------------
  298. #endif