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.

669 lines
18 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "LoadingDialog.h"
  8. #include "EngineInterface.h"
  9. #include "IGameUIFuncs.h"
  10. #include <vgui/IInput.h>
  11. #include <vgui/ISurface.h>
  12. #include <vgui/ILocalize.h>
  13. #include <vgui/IScheme.h>
  14. #include <vgui/ISystem.h>
  15. #include <vgui_controls/ProgressBar.h>
  16. #include <vgui_controls/Label.h>
  17. #include <vgui_controls/Button.h>
  18. #include <vgui_controls/HTML.h>
  19. #include <vgui_controls/RichText.h>
  20. #include "tier0/icommandline.h"
  21. #include "GameUI_Interface.h"
  22. #include "ModInfo.h"
  23. #include "BasePanel.h"
  24. // memdbgon must be the last include file in a .cpp file!!!
  25. #include <tier0/memdbgon.h>
  26. using namespace vgui;
  27. //-----------------------------------------------------------------------------
  28. // Purpose: Constructor
  29. //-----------------------------------------------------------------------------
  30. CLoadingDialog::CLoadingDialog( vgui::Panel *parent ) : Frame(parent, "LoadingDialog")
  31. {
  32. SetDeleteSelfOnClose(true);
  33. // Use console style
  34. m_bConsoleStyle = GameUI().IsConsoleUI();
  35. if ( !m_bConsoleStyle )
  36. {
  37. SetSize( 416, 100 );
  38. SetTitle( "#GameUI_Loading", true );
  39. }
  40. // center the loading dialog, unless we have another dialog to show in the background
  41. m_bCenter = !GameUI().HasLoadingBackgroundDialog();
  42. m_bShowingSecondaryProgress = false;
  43. m_flSecondaryProgress = 0.0f;
  44. m_flLastSecondaryProgressUpdateTime = 0.0f;
  45. m_flSecondaryProgressStartTime = 0.0f;
  46. m_pProgress = new ProgressBar( this, "Progress" );
  47. m_pProgress2 = new ProgressBar( this, "Progress2" );
  48. m_pInfoLabel = new Label( this, "InfoLabel", "" );
  49. m_pCancelButton = new Button( this, "CancelButton", "#GameUI_Cancel" );
  50. m_pTimeRemainingLabel = new Label( this, "TimeRemainingLabel", "" );
  51. m_pCancelButton->SetCommand( "Cancel" );
  52. if ( ModInfo().IsSinglePlayerOnly() == false && m_bConsoleStyle == true )
  53. {
  54. m_pLoadingBackground = new Panel( this, "LoadingDialogBG" );
  55. }
  56. else
  57. {
  58. m_pLoadingBackground = NULL;
  59. }
  60. SetMinimizeButtonVisible( false );
  61. SetMaximizeButtonVisible( false );
  62. SetCloseButtonVisible( false );
  63. SetSizeable( false );
  64. SetMoveable( false );
  65. if ( m_bConsoleStyle )
  66. {
  67. m_bCenter = false;
  68. m_pProgress->SetVisible( false );
  69. m_pProgress2->SetVisible( false );
  70. m_pInfoLabel->SetVisible( false );
  71. m_pCancelButton->SetVisible( false );
  72. m_pTimeRemainingLabel->SetVisible( false );
  73. m_pCancelButton->SetVisible( false );
  74. SetMinimumSize( 0, 0 );
  75. SetTitleBarVisible( false );
  76. m_flProgressFraction = 0;
  77. }
  78. else
  79. {
  80. m_pInfoLabel->SetBounds(20, 32, 392, 24);
  81. m_pProgress->SetBounds(20, 64, 300, 24);
  82. m_pCancelButton->SetBounds(330, 64, 72, 24);
  83. m_pProgress2->SetVisible(false);
  84. }
  85. SetupControlSettings( false );
  86. }
  87. //-----------------------------------------------------------------------------
  88. // Purpose: Destructor
  89. //-----------------------------------------------------------------------------
  90. CLoadingDialog::~CLoadingDialog()
  91. {
  92. if ( input()->GetAppModalSurface() == GetVPanel() )
  93. {
  94. vgui::surface()->RestrictPaintToSinglePanel( NULL );
  95. }
  96. }
  97. void CLoadingDialog::PaintBackground()
  98. {
  99. if ( !m_bConsoleStyle )
  100. {
  101. BaseClass::PaintBackground();
  102. return;
  103. }
  104. // draw solid progress bar with curved endcaps
  105. int panelWide, panelTall;
  106. GetSize( panelWide, panelTall );
  107. int barWide, barTall;
  108. m_pProgress->GetSize( barWide, barTall );
  109. int x = ( panelWide - barWide )/2;
  110. int y = panelTall - barTall;
  111. if ( m_pLoadingBackground )
  112. {
  113. vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" );
  114. Color color = GetSchemeColor( "TanDarker", Color(255, 255, 255, 255), vgui::scheme()->GetIScheme(scheme) );
  115. m_pLoadingBackground->SetFgColor( color );
  116. m_pLoadingBackground->SetBgColor( color );
  117. m_pLoadingBackground->SetPaintBackgroundEnabled( true );
  118. }
  119. if ( ModInfo().IsSinglePlayerOnly() )
  120. {
  121. DrawBox( x, y, barWide, barTall, Color( 0, 0, 0, 255 ), 1.0f );
  122. }
  123. DrawBox( x+2, y+2, barWide-4, barTall-4, Color( 100, 100, 100, 255 ), 1.0f );
  124. barWide = m_flProgressFraction * ( barWide - 4 );
  125. if ( barWide >= 12 )
  126. {
  127. // cannot draw a curved box smaller than 12 without artifacts
  128. DrawBox( x+2, y+2, barWide, barTall-4, Color( 200, 100, 0, 255 ), 1.0f );
  129. }
  130. }
  131. //-----------------------------------------------------------------------------
  132. // Purpose: sets up dialog layout
  133. //-----------------------------------------------------------------------------
  134. void CLoadingDialog::SetupControlSettings( bool bForceShowProgressText )
  135. {
  136. m_bShowingVACInfo = false;
  137. if ( GameUI().IsConsoleUI() )
  138. {
  139. KeyValues *pControlSettings = BasePanel()->GetConsoleControlSettings()->FindKey( "LoadingDialogNoBanner.res" );
  140. LoadControlSettings( "null", NULL, pControlSettings );
  141. return;
  142. }
  143. if ( ModInfo().IsSinglePlayerOnly() && !bForceShowProgressText )
  144. {
  145. LoadControlSettings("Resource/LoadingDialogNoBannerSingle.res");
  146. }
  147. else if ( gameuifuncs->IsConnectedToVACSecureServer() )
  148. {
  149. LoadControlSettings("Resource/LoadingDialogVAC.res");
  150. m_bShowingVACInfo = true;
  151. }
  152. else
  153. {
  154. LoadControlSettings("Resource/LoadingDialogNoBanner.res");
  155. }
  156. }
  157. //-----------------------------------------------------------------------------
  158. // Purpose: Activates the loading screen, initializing and making it visible
  159. //-----------------------------------------------------------------------------
  160. void CLoadingDialog::Open()
  161. {
  162. if ( !m_bConsoleStyle )
  163. {
  164. SetTitle( "#GameUI_Loading", true );
  165. }
  166. HideOtherDialogs( true );
  167. BaseClass::Activate();
  168. if ( !m_bConsoleStyle )
  169. {
  170. m_pProgress->SetVisible( true );
  171. if ( !ModInfo().IsSinglePlayerOnly() )
  172. {
  173. m_pInfoLabel->SetVisible( true );
  174. }
  175. m_pInfoLabel->SetText("");
  176. m_pCancelButton->SetText("#GameUI_Cancel");
  177. m_pCancelButton->SetCommand("Cancel");
  178. }
  179. }
  180. //-----------------------------------------------------------------------------
  181. // Purpose: error display file
  182. //-----------------------------------------------------------------------------
  183. void CLoadingDialog::SetupControlSettingsForErrorDisplay( const char *settingsFile )
  184. {
  185. if ( m_bConsoleStyle )
  186. {
  187. return;
  188. }
  189. m_bCenter = true;
  190. SetTitle("#GameUI_Disconnected", true);
  191. m_pInfoLabel->SetText("");
  192. LoadControlSettings( settingsFile );
  193. HideOtherDialogs( true );
  194. BaseClass::Activate();
  195. m_pProgress->SetVisible(false);
  196. m_pInfoLabel->SetVisible(true);
  197. m_pCancelButton->SetText("#GameUI_Close");
  198. m_pCancelButton->SetCommand("Close");
  199. m_pInfoLabel->InvalidateLayout();
  200. }
  201. //-----------------------------------------------------------------------------
  202. // Purpose: shows or hides other top-level dialogs
  203. //-----------------------------------------------------------------------------
  204. void CLoadingDialog::HideOtherDialogs( bool bHide )
  205. {
  206. if ( bHide )
  207. {
  208. if ( GameUI().HasLoadingBackgroundDialog() )
  209. {
  210. // if we have a loading background dialog, hide any other dialogs by moving the full-screen background dialog to the
  211. // front, then moving ourselves in front of it
  212. GameUI().ShowLoadingBackgroundDialog();
  213. vgui::ipanel()->MoveToFront( GetVPanel() );
  214. vgui::input()->SetAppModalSurface( GetVPanel() );
  215. }
  216. else
  217. {
  218. // if there is no loading background dialog, use VGUI paint restrictions to hide other dialogs
  219. vgui::surface()->RestrictPaintToSinglePanel(GetVPanel());
  220. }
  221. }
  222. else
  223. {
  224. if ( GameUI().HasLoadingBackgroundDialog() )
  225. {
  226. GameUI().HideLoadingBackgroundDialog();
  227. vgui::input()->SetAppModalSurface( NULL );
  228. }
  229. else
  230. {
  231. // remove any rendering restrictions
  232. vgui::surface()->RestrictPaintToSinglePanel(NULL);
  233. }
  234. }
  235. }
  236. //-----------------------------------------------------------------------------
  237. // Purpose: Turns dialog into error display
  238. //-----------------------------------------------------------------------------
  239. void CLoadingDialog::DisplayGenericError(const char *failureReason, const char *extendedReason)
  240. {
  241. if ( m_bConsoleStyle )
  242. {
  243. return;
  244. }
  245. // In certain race conditions, DisplayGenericError can get called AFTER OnClose() has been called.
  246. // If that happens and we don't call Activate(), then it'll continue closing when we don't want it to.
  247. Activate();
  248. SetupControlSettingsForErrorDisplay("Resource/LoadingDialogError.res");
  249. if ( extendedReason && strlen( extendedReason ) > 0 )
  250. {
  251. wchar_t compositeReason[256], finalMsg[512], formatStr[256];
  252. if ( extendedReason[0] == '#' )
  253. {
  254. wcsncpy(compositeReason, g_pVGuiLocalize->Find(extendedReason), sizeof( compositeReason ) / sizeof( wchar_t ) );
  255. }
  256. else
  257. {
  258. g_pVGuiLocalize->ConvertANSIToUnicode(extendedReason, compositeReason, sizeof( compositeReason ));
  259. }
  260. if ( failureReason[0] == '#' )
  261. {
  262. wcsncpy(formatStr, g_pVGuiLocalize->Find(failureReason), sizeof( formatStr ) / sizeof( wchar_t ) );
  263. }
  264. else
  265. {
  266. g_pVGuiLocalize->ConvertANSIToUnicode(failureReason, formatStr, sizeof( formatStr ));
  267. }
  268. g_pVGuiLocalize->ConstructString(finalMsg, sizeof( finalMsg ), formatStr, 1, compositeReason);
  269. m_pInfoLabel->SetText(finalMsg);
  270. }
  271. else
  272. {
  273. m_pInfoLabel->SetText(failureReason);
  274. }
  275. int wide, tall;
  276. int x,y;
  277. m_pInfoLabel->GetContentSize( wide, tall );
  278. m_pInfoLabel->GetPos( x, y );
  279. SetTall( tall + y + 50 );
  280. int buttonX, buttonY;
  281. m_pCancelButton->GetPos( buttonX, buttonY );
  282. m_pCancelButton->SetPos( buttonX, tall + y + 6 );
  283. m_pCancelButton->RequestFocus();
  284. }
  285. //-----------------------------------------------------------------------------
  286. // Purpose: explain to the user they can't join secure servers due to a VAC ban
  287. //-----------------------------------------------------------------------------
  288. void CLoadingDialog::DisplayVACBannedError()
  289. {
  290. if ( m_bConsoleStyle )
  291. {
  292. return;
  293. }
  294. SetupControlSettingsForErrorDisplay("Resource/LoadingDialogErrorVACBanned.res");
  295. SetTitle("#VAC_ConnectionRefusedTitle", true);
  296. }
  297. //-----------------------------------------------------------------------------
  298. // Purpose: explain to the user they can't connect to public servers due to
  299. // not having a valid connection to Steam
  300. // this should only happen if they are a pirate
  301. //-----------------------------------------------------------------------------
  302. void CLoadingDialog::DisplayNoSteamConnectionError()
  303. {
  304. if ( m_bConsoleStyle )
  305. {
  306. return;
  307. }
  308. SetupControlSettingsForErrorDisplay("Resource/LoadingDialogErrorNoSteamConnection.res");
  309. }
  310. //-----------------------------------------------------------------------------
  311. // Purpose: explain to the user they got kicked from a server due to that same account
  312. // logging in from another location. This also triggers the refresh login dialog on OK
  313. // being pressed.
  314. //-----------------------------------------------------------------------------
  315. void CLoadingDialog::DisplayLoggedInElsewhereError()
  316. {
  317. if ( m_bConsoleStyle )
  318. {
  319. return;
  320. }
  321. SetupControlSettingsForErrorDisplay("Resource/LoadingDialogErrorLoggedInElsewhere.res");
  322. m_pCancelButton->SetText("#GameUI_RefreshLogin_Login");
  323. m_pCancelButton->SetCommand("Login");
  324. }
  325. //-----------------------------------------------------------------------------
  326. // Purpose: sets status info text
  327. //-----------------------------------------------------------------------------
  328. void CLoadingDialog::SetStatusText(const char *statusText)
  329. {
  330. if ( m_bConsoleStyle )
  331. {
  332. return;
  333. }
  334. m_pInfoLabel->SetText(statusText);
  335. }
  336. //-----------------------------------------------------------------------------
  337. // Purpose: returns the previous state
  338. //-----------------------------------------------------------------------------
  339. bool CLoadingDialog::SetShowProgressText( bool show )
  340. {
  341. if ( m_bConsoleStyle )
  342. {
  343. return false;
  344. }
  345. bool bret = m_pInfoLabel->IsVisible();
  346. if ( bret != show )
  347. {
  348. SetupControlSettings( show );
  349. m_pInfoLabel->SetVisible( show );
  350. }
  351. return bret;
  352. }
  353. //-----------------------------------------------------------------------------
  354. // Purpose: updates time remaining
  355. //-----------------------------------------------------------------------------
  356. void CLoadingDialog::OnThink()
  357. {
  358. BaseClass::OnThink();
  359. if ( !m_bConsoleStyle && m_bShowingSecondaryProgress )
  360. {
  361. // calculate the time remaining string
  362. wchar_t unicode[512];
  363. if (m_flSecondaryProgress >= 1.0f)
  364. {
  365. m_pTimeRemainingLabel->SetText("complete");
  366. }
  367. else if (ProgressBar::ConstructTimeRemainingString(unicode, sizeof(unicode), m_flSecondaryProgressStartTime, (float)system()->GetFrameTime(), m_flSecondaryProgress, m_flLastSecondaryProgressUpdateTime, true))
  368. {
  369. m_pTimeRemainingLabel->SetText(unicode);
  370. }
  371. else
  372. {
  373. m_pTimeRemainingLabel->SetText("");
  374. }
  375. }
  376. SetAlpha( 255 );
  377. }
  378. //-----------------------------------------------------------------------------
  379. // Purpose:
  380. //-----------------------------------------------------------------------------
  381. void CLoadingDialog::PerformLayout()
  382. {
  383. if ( m_bConsoleStyle )
  384. {
  385. // place in lower center
  386. int screenWide, screenTall;
  387. surface()->GetScreenSize( screenWide, screenTall );
  388. int wide,tall;
  389. GetSize( wide, tall );
  390. int x = 0;
  391. int y = 0;
  392. if ( ModInfo().IsSinglePlayerOnly() )
  393. {
  394. x = ( screenWide - wide ) * 0.50f;
  395. y = ( screenTall - tall ) * 0.86f;
  396. }
  397. else
  398. {
  399. x = ( screenWide - ( wide * 1.30f ) );
  400. y = ( ( screenTall * 0.875f ) );
  401. }
  402. SetPos( x, y );
  403. }
  404. else if ( m_bCenter )
  405. {
  406. MoveToCenterOfScreen();
  407. }
  408. else
  409. {
  410. // if we're not supposed to be centered, move ourselves to the lower right hand corner of the screen
  411. int x, y, screenWide, screenTall;
  412. surface()->GetWorkspaceBounds( x, y, screenWide, screenTall );
  413. int wide,tall;
  414. GetSize( wide, tall );
  415. if ( IsPC() )
  416. {
  417. x = screenWide - ( wide + 10 );
  418. y = screenTall - ( tall + 10 );
  419. }
  420. else
  421. {
  422. // Move farther in so we're title safe
  423. x = screenWide - wide - (screenWide * 0.05);
  424. y = screenTall - tall - (screenTall * 0.05);
  425. }
  426. x -= m_iAdditionalIndentX;
  427. y -= m_iAdditionalIndentY;
  428. SetPos( x, y );
  429. }
  430. BaseClass::PerformLayout();
  431. vgui::ipanel()->MoveToFront( GetVPanel() );
  432. }
  433. //-----------------------------------------------------------------------------
  434. // Purpose: returns true if the number of ticks has changed
  435. //-----------------------------------------------------------------------------
  436. bool CLoadingDialog::SetProgressPoint( float fraction )
  437. {
  438. if ( m_bConsoleStyle )
  439. {
  440. if ( fraction >= 0.99f )
  441. {
  442. // show the progress artifically completed to fill in 100%
  443. fraction = 1.0f;
  444. }
  445. fraction = clamp( fraction, 0.0f, 1.0f );
  446. if ( (int)(fraction * 25) != (int)(m_flProgressFraction * 25) )
  447. {
  448. m_flProgressFraction = fraction;
  449. return true;
  450. }
  451. return IsX360();
  452. }
  453. if ( !m_bShowingVACInfo && gameuifuncs->IsConnectedToVACSecureServer() )
  454. {
  455. SetupControlSettings( false );
  456. }
  457. int nOldDrawnSegments = m_pProgress->GetDrawnSegmentCount();
  458. m_pProgress->SetProgress( fraction );
  459. int nNewDrawSegments = m_pProgress->GetDrawnSegmentCount();
  460. return (nOldDrawnSegments != nNewDrawSegments) || IsX360();
  461. }
  462. //-----------------------------------------------------------------------------
  463. // Purpose: sets and shows the secondary progress bar
  464. //-----------------------------------------------------------------------------
  465. void CLoadingDialog::SetSecondaryProgress( float progress )
  466. {
  467. if ( m_bConsoleStyle )
  468. return;
  469. // don't show the progress if we've jumped right to completion
  470. if (!m_bShowingSecondaryProgress && progress > 0.99f)
  471. return;
  472. // if we haven't yet shown secondary progress then reconfigure the dialog
  473. if (!m_bShowingSecondaryProgress)
  474. {
  475. LoadControlSettings("Resource/LoadingDialogDualProgress.res");
  476. m_bShowingSecondaryProgress = true;
  477. m_pProgress2->SetVisible(true);
  478. m_flSecondaryProgressStartTime = (float)system()->GetFrameTime();
  479. }
  480. // if progress has increased then update the progress counters
  481. if (progress > m_flSecondaryProgress)
  482. {
  483. m_pProgress2->SetProgress(progress);
  484. m_flSecondaryProgress = progress;
  485. m_flLastSecondaryProgressUpdateTime = (float)system()->GetFrameTime();
  486. }
  487. // if progress has decreased then reset progress counters
  488. if (progress < m_flSecondaryProgress)
  489. {
  490. m_pProgress2->SetProgress(progress);
  491. m_flSecondaryProgress = progress;
  492. m_flLastSecondaryProgressUpdateTime = (float)system()->GetFrameTime();
  493. m_flSecondaryProgressStartTime = (float)system()->GetFrameTime();
  494. }
  495. }
  496. //-----------------------------------------------------------------------------
  497. // Purpose:
  498. //-----------------------------------------------------------------------------
  499. void CLoadingDialog::SetSecondaryProgressText(const char *statusText)
  500. {
  501. if ( m_bConsoleStyle )
  502. {
  503. return;
  504. }
  505. SetControlString( "SecondaryProgressLabel", statusText );
  506. }
  507. //-----------------------------------------------------------------------------
  508. // Purpose:
  509. //-----------------------------------------------------------------------------
  510. void CLoadingDialog::OnClose()
  511. {
  512. // remove any rendering restrictions
  513. HideOtherDialogs( false );
  514. BaseClass::OnClose();
  515. }
  516. //-----------------------------------------------------------------------------
  517. // Purpose: command handler
  518. //-----------------------------------------------------------------------------
  519. void CLoadingDialog::OnCommand(const char *command)
  520. {
  521. if ( !stricmp(command, "Cancel") )
  522. {
  523. // disconnect from the server
  524. engine->ClientCmd_Unrestricted("disconnect\n");
  525. // close
  526. Close();
  527. }
  528. else
  529. {
  530. BaseClass::OnCommand(command);
  531. }
  532. }
  533. void CLoadingDialog::OnKeyCodeTyped(KeyCode code)
  534. {
  535. if ( m_bConsoleStyle )
  536. {
  537. return;
  538. }
  539. if ( code == KEY_ESCAPE )
  540. {
  541. OnCommand("Cancel");
  542. }
  543. else
  544. {
  545. BaseClass::OnKeyCodeTyped(code);
  546. }
  547. }
  548. //-----------------------------------------------------------------------------
  549. // Purpose: Maps ESC to quiting loading
  550. //-----------------------------------------------------------------------------
  551. void CLoadingDialog::OnKeyCodePressed(KeyCode code)
  552. {
  553. if ( m_bConsoleStyle )
  554. {
  555. return;
  556. }
  557. ButtonCode_t nButtonCode = GetBaseButtonCode( code );
  558. if ( nButtonCode == KEY_XBUTTON_B || nButtonCode == KEY_XBUTTON_A || nButtonCode == STEAMCONTROLLER_A || nButtonCode == STEAMCONTROLLER_B )
  559. {
  560. OnCommand("Cancel");
  561. }
  562. else
  563. {
  564. BaseClass::OnKeyCodePressed(code);
  565. }
  566. }
  567. //-----------------------------------------------------------------------------
  568. // Purpose: Singleton accessor
  569. //-----------------------------------------------------------------------------
  570. extern vgui::DHANDLE<CLoadingDialog> g_hLoadingDialog;
  571. CLoadingDialog *LoadingDialog()
  572. {
  573. return g_hLoadingDialog.Get();
  574. }