source-engine/gameui/LoadingDialog.cpp

670 lines
18 KiB
C++
Raw Normal View History

2020-04-22 16:56:21 +00:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "LoadingDialog.h"
#include "EngineInterface.h"
#include "IGameUIFuncs.h"
#include <vgui/IInput.h>
#include <vgui/ISurface.h>
#include <vgui/ILocalize.h>
#include <vgui/IScheme.h>
#include <vgui/ISystem.h>
#include <vgui_controls/ProgressBar.h>
#include <vgui_controls/Label.h>
#include <vgui_controls/Button.h>
#include <vgui_controls/HTML.h>
#include <vgui_controls/RichText.h>
#include "tier0/icommandline.h"
#include "GameUI_Interface.h"
#include "ModInfo.h"
#include "BasePanel.h"
// memdbgon must be the last include file in a .cpp file!!!
#include <tier0/memdbgon.h>
using namespace vgui;
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CLoadingDialog::CLoadingDialog( vgui::Panel *parent ) : Frame(parent, "LoadingDialog")
{
SetDeleteSelfOnClose(true);
// Use console style
m_bConsoleStyle = GameUI().IsConsoleUI();
if ( !m_bConsoleStyle )
{
SetSize( 416, 100 );
SetTitle( "#GameUI_Loading", true );
}
// center the loading dialog, unless we have another dialog to show in the background
m_bCenter = !GameUI().HasLoadingBackgroundDialog();
m_bShowingSecondaryProgress = false;
m_flSecondaryProgress = 0.0f;
m_flLastSecondaryProgressUpdateTime = 0.0f;
m_flSecondaryProgressStartTime = 0.0f;
m_pProgress = new ProgressBar( this, "Progress" );
m_pProgress2 = new ProgressBar( this, "Progress2" );
m_pInfoLabel = new Label( this, "InfoLabel", "" );
m_pCancelButton = new Button( this, "CancelButton", "#GameUI_Cancel" );
m_pTimeRemainingLabel = new Label( this, "TimeRemainingLabel", "" );
m_pCancelButton->SetCommand( "Cancel" );
if ( ModInfo().IsSinglePlayerOnly() == false && m_bConsoleStyle == true )
{
m_pLoadingBackground = new Panel( this, "LoadingDialogBG" );
}
else
{
m_pLoadingBackground = NULL;
}
SetMinimizeButtonVisible( false );
SetMaximizeButtonVisible( false );
SetCloseButtonVisible( false );
SetSizeable( false );
SetMoveable( false );
if ( m_bConsoleStyle )
{
m_bCenter = false;
m_pProgress->SetVisible( false );
m_pProgress2->SetVisible( false );
m_pInfoLabel->SetVisible( false );
m_pCancelButton->SetVisible( false );
m_pTimeRemainingLabel->SetVisible( false );
m_pCancelButton->SetVisible( false );
SetMinimumSize( 0, 0 );
SetTitleBarVisible( false );
m_flProgressFraction = 0;
}
else
{
m_pInfoLabel->SetBounds(20, 32, 392, 24);
m_pProgress->SetBounds(20, 64, 300, 24);
m_pCancelButton->SetBounds(330, 64, 72, 24);
m_pProgress2->SetVisible(false);
}
SetupControlSettings( false );
}
//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
CLoadingDialog::~CLoadingDialog()
{
if ( input()->GetAppModalSurface() == GetVPanel() )
{
vgui::surface()->RestrictPaintToSinglePanel( NULL );
}
}
void CLoadingDialog::PaintBackground()
{
if ( !m_bConsoleStyle )
{
BaseClass::PaintBackground();
return;
}
// draw solid progress bar with curved endcaps
int panelWide, panelTall;
GetSize( panelWide, panelTall );
int barWide, barTall;
m_pProgress->GetSize( barWide, barTall );
int x = ( panelWide - barWide )/2;
int y = panelTall - barTall;
if ( m_pLoadingBackground )
{
vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" );
Color color = GetSchemeColor( "TanDarker", Color(255, 255, 255, 255), vgui::scheme()->GetIScheme(scheme) );
m_pLoadingBackground->SetFgColor( color );
m_pLoadingBackground->SetBgColor( color );
m_pLoadingBackground->SetPaintBackgroundEnabled( true );
}
if ( ModInfo().IsSinglePlayerOnly() )
{
DrawBox( x, y, barWide, barTall, Color( 0, 0, 0, 255 ), 1.0f );
}
DrawBox( x+2, y+2, barWide-4, barTall-4, Color( 100, 100, 100, 255 ), 1.0f );
barWide = m_flProgressFraction * ( barWide - 4 );
if ( barWide >= 12 )
{
// cannot draw a curved box smaller than 12 without artifacts
DrawBox( x+2, y+2, barWide, barTall-4, Color( 200, 100, 0, 255 ), 1.0f );
}
}
//-----------------------------------------------------------------------------
// Purpose: sets up dialog layout
//-----------------------------------------------------------------------------
void CLoadingDialog::SetupControlSettings( bool bForceShowProgressText )
{
m_bShowingVACInfo = false;
if ( GameUI().IsConsoleUI() )
{
KeyValues *pControlSettings = BasePanel()->GetConsoleControlSettings()->FindKey( "LoadingDialogNoBanner.res" );
LoadControlSettings( "null", NULL, pControlSettings );
return;
}
if ( ModInfo().IsSinglePlayerOnly() && !bForceShowProgressText )
{
LoadControlSettings("Resource/LoadingDialogNoBannerSingle.res");
}
else if ( gameuifuncs->IsConnectedToVACSecureServer() )
{
LoadControlSettings("Resource/LoadingDialogVAC.res");
m_bShowingVACInfo = true;
}
else
{
LoadControlSettings("Resource/LoadingDialogNoBanner.res");
}
}
//-----------------------------------------------------------------------------
// Purpose: Activates the loading screen, initializing and making it visible
//-----------------------------------------------------------------------------
void CLoadingDialog::Open()
{
if ( !m_bConsoleStyle )
{
SetTitle( "#GameUI_Loading", true );
}
HideOtherDialogs( true );
BaseClass::Activate();
if ( !m_bConsoleStyle )
{
m_pProgress->SetVisible( true );
if ( !ModInfo().IsSinglePlayerOnly() )
{
m_pInfoLabel->SetVisible( true );
}
m_pInfoLabel->SetText("");
m_pCancelButton->SetText("#GameUI_Cancel");
m_pCancelButton->SetCommand("Cancel");
}
}
//-----------------------------------------------------------------------------
// Purpose: error display file
//-----------------------------------------------------------------------------
void CLoadingDialog::SetupControlSettingsForErrorDisplay( const char *settingsFile )
{
if ( m_bConsoleStyle )
{
return;
}
m_bCenter = true;
SetTitle("#GameUI_Disconnected", true);
m_pInfoLabel->SetText("");
LoadControlSettings( settingsFile );
HideOtherDialogs( true );
BaseClass::Activate();
m_pProgress->SetVisible(false);
m_pInfoLabel->SetVisible(true);
m_pCancelButton->SetText("#GameUI_Close");
m_pCancelButton->SetCommand("Close");
m_pInfoLabel->InvalidateLayout();
}
//-----------------------------------------------------------------------------
// Purpose: shows or hides other top-level dialogs
//-----------------------------------------------------------------------------
void CLoadingDialog::HideOtherDialogs( bool bHide )
{
if ( bHide )
{
if ( GameUI().HasLoadingBackgroundDialog() )
{
// if we have a loading background dialog, hide any other dialogs by moving the full-screen background dialog to the
// front, then moving ourselves in front of it
GameUI().ShowLoadingBackgroundDialog();
vgui::ipanel()->MoveToFront( GetVPanel() );
vgui::input()->SetAppModalSurface( GetVPanel() );
}
else
{
// if there is no loading background dialog, use VGUI paint restrictions to hide other dialogs
vgui::surface()->RestrictPaintToSinglePanel(GetVPanel());
}
}
else
{
if ( GameUI().HasLoadingBackgroundDialog() )
{
GameUI().HideLoadingBackgroundDialog();
vgui::input()->SetAppModalSurface( NULL );
}
else
{
// remove any rendering restrictions
vgui::surface()->RestrictPaintToSinglePanel(NULL);
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Turns dialog into error display
//-----------------------------------------------------------------------------
void CLoadingDialog::DisplayGenericError(const char *failureReason, const char *extendedReason)
{
if ( m_bConsoleStyle )
{
return;
}
// In certain race conditions, DisplayGenericError can get called AFTER OnClose() has been called.
// If that happens and we don't call Activate(), then it'll continue closing when we don't want it to.
Activate();
SetupControlSettingsForErrorDisplay("Resource/LoadingDialogError.res");
if ( extendedReason && strlen( extendedReason ) > 0 )
{
wchar_t compositeReason[256], finalMsg[512], formatStr[256];
if ( extendedReason[0] == '#' )
{
wcsncpy(compositeReason, g_pVGuiLocalize->Find(extendedReason), sizeof( compositeReason ) / sizeof( wchar_t ) );
}
else
{
g_pVGuiLocalize->ConvertANSIToUnicode(extendedReason, compositeReason, sizeof( compositeReason ));
}
if ( failureReason[0] == '#' )
{
wcsncpy(formatStr, g_pVGuiLocalize->Find(failureReason), sizeof( formatStr ) / sizeof( wchar_t ) );
}
else
{
g_pVGuiLocalize->ConvertANSIToUnicode(failureReason, formatStr, sizeof( formatStr ));
}
g_pVGuiLocalize->ConstructString(finalMsg, sizeof( finalMsg ), formatStr, 1, compositeReason);
m_pInfoLabel->SetText(finalMsg);
}
else
{
m_pInfoLabel->SetText(failureReason);
}
int wide, tall;
int x,y;
m_pInfoLabel->GetContentSize( wide, tall );
m_pInfoLabel->GetPos( x, y );
SetTall( tall + y + 50 );
int buttonX, buttonY;
m_pCancelButton->GetPos( buttonX, buttonY );
m_pCancelButton->SetPos( buttonX, tall + y + 6 );
m_pCancelButton->RequestFocus();
}
//-----------------------------------------------------------------------------
// Purpose: explain to the user they can't join secure servers due to a VAC ban
//-----------------------------------------------------------------------------
void CLoadingDialog::DisplayVACBannedError()
{
if ( m_bConsoleStyle )
{
return;
}
SetupControlSettingsForErrorDisplay("Resource/LoadingDialogErrorVACBanned.res");
SetTitle("#VAC_ConnectionRefusedTitle", true);
}
//-----------------------------------------------------------------------------
// Purpose: explain to the user they can't connect to public servers due to
// not having a valid connection to Steam
// this should only happen if they are a pirate
//-----------------------------------------------------------------------------
void CLoadingDialog::DisplayNoSteamConnectionError()
{
if ( m_bConsoleStyle )
{
return;
}
SetupControlSettingsForErrorDisplay("Resource/LoadingDialogErrorNoSteamConnection.res");
}
//-----------------------------------------------------------------------------
// Purpose: explain to the user they got kicked from a server due to that same account
// logging in from another location. This also triggers the refresh login dialog on OK
// being pressed.
//-----------------------------------------------------------------------------
void CLoadingDialog::DisplayLoggedInElsewhereError()
{
if ( m_bConsoleStyle )
{
return;
}
SetupControlSettingsForErrorDisplay("Resource/LoadingDialogErrorLoggedInElsewhere.res");
m_pCancelButton->SetText("#GameUI_RefreshLogin_Login");
m_pCancelButton->SetCommand("Login");
}
//-----------------------------------------------------------------------------
// Purpose: sets status info text
//-----------------------------------------------------------------------------
void CLoadingDialog::SetStatusText(const char *statusText)
{
if ( m_bConsoleStyle )
{
return;
}
m_pInfoLabel->SetText(statusText);
}
//-----------------------------------------------------------------------------
// Purpose: returns the previous state
//-----------------------------------------------------------------------------
bool CLoadingDialog::SetShowProgressText( bool show )
{
if ( m_bConsoleStyle )
{
return false;
}
bool bret = m_pInfoLabel->IsVisible();
if ( bret != show )
{
SetupControlSettings( show );
m_pInfoLabel->SetVisible( show );
}
return bret;
}
//-----------------------------------------------------------------------------
// Purpose: updates time remaining
//-----------------------------------------------------------------------------
void CLoadingDialog::OnThink()
{
BaseClass::OnThink();
if ( !m_bConsoleStyle && m_bShowingSecondaryProgress )
{
// calculate the time remaining string
wchar_t unicode[512];
if (m_flSecondaryProgress >= 1.0f)
{
m_pTimeRemainingLabel->SetText("complete");
}
else if (ProgressBar::ConstructTimeRemainingString(unicode, sizeof(unicode), m_flSecondaryProgressStartTime, (float)system()->GetFrameTime(), m_flSecondaryProgress, m_flLastSecondaryProgressUpdateTime, true))
{
m_pTimeRemainingLabel->SetText(unicode);
}
else
{
m_pTimeRemainingLabel->SetText("");
}
}
SetAlpha( 255 );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CLoadingDialog::PerformLayout()
{
if ( m_bConsoleStyle )
{
// place in lower center
int screenWide, screenTall;
surface()->GetScreenSize( screenWide, screenTall );
int wide,tall;
GetSize( wide, tall );
int x = 0;
int y = 0;
if ( ModInfo().IsSinglePlayerOnly() )
{
x = ( screenWide - wide ) * 0.50f;
y = ( screenTall - tall ) * 0.86f;
}
else
{
x = ( screenWide - ( wide * 1.30f ) );
y = ( ( screenTall * 0.875f ) );
}
SetPos( x, y );
}
else if ( m_bCenter )
{
MoveToCenterOfScreen();
}
else
{
// if we're not supposed to be centered, move ourselves to the lower right hand corner of the screen
int x, y, screenWide, screenTall;
surface()->GetWorkspaceBounds( x, y, screenWide, screenTall );
int wide,tall;
GetSize( wide, tall );
if ( IsPC() )
{
x = screenWide - ( wide + 10 );
y = screenTall - ( tall + 10 );
}
else
{
// Move farther in so we're title safe
x = screenWide - wide - (screenWide * 0.05);
y = screenTall - tall - (screenTall * 0.05);
}
x -= m_iAdditionalIndentX;
y -= m_iAdditionalIndentY;
SetPos( x, y );
}
BaseClass::PerformLayout();
vgui::ipanel()->MoveToFront( GetVPanel() );
}
//-----------------------------------------------------------------------------
// Purpose: returns true if the number of ticks has changed
//-----------------------------------------------------------------------------
bool CLoadingDialog::SetProgressPoint( float fraction )
{
if ( m_bConsoleStyle )
{
if ( fraction >= 0.99f )
{
// show the progress artifically completed to fill in 100%
fraction = 1.0f;
}
fraction = clamp( fraction, 0.0f, 1.0f );
if ( (int)(fraction * 25) != (int)(m_flProgressFraction * 25) )
{
m_flProgressFraction = fraction;
return true;
}
return IsX360();
}
if ( !m_bShowingVACInfo && gameuifuncs->IsConnectedToVACSecureServer() )
{
SetupControlSettings( false );
}
int nOldDrawnSegments = m_pProgress->GetDrawnSegmentCount();
m_pProgress->SetProgress( fraction );
int nNewDrawSegments = m_pProgress->GetDrawnSegmentCount();
return (nOldDrawnSegments != nNewDrawSegments) || IsX360();
}
//-----------------------------------------------------------------------------
// Purpose: sets and shows the secondary progress bar
//-----------------------------------------------------------------------------
void CLoadingDialog::SetSecondaryProgress( float progress )
{
if ( m_bConsoleStyle )
return;
// don't show the progress if we've jumped right to completion
if (!m_bShowingSecondaryProgress && progress > 0.99f)
return;
// if we haven't yet shown secondary progress then reconfigure the dialog
if (!m_bShowingSecondaryProgress)
{
LoadControlSettings("Resource/LoadingDialogDualProgress.res");
m_bShowingSecondaryProgress = true;
m_pProgress2->SetVisible(true);
m_flSecondaryProgressStartTime = (float)system()->GetFrameTime();
}
// if progress has increased then update the progress counters
if (progress > m_flSecondaryProgress)
{
m_pProgress2->SetProgress(progress);
m_flSecondaryProgress = progress;
m_flLastSecondaryProgressUpdateTime = (float)system()->GetFrameTime();
}
// if progress has decreased then reset progress counters
if (progress < m_flSecondaryProgress)
{
m_pProgress2->SetProgress(progress);
m_flSecondaryProgress = progress;
m_flLastSecondaryProgressUpdateTime = (float)system()->GetFrameTime();
m_flSecondaryProgressStartTime = (float)system()->GetFrameTime();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CLoadingDialog::SetSecondaryProgressText(const char *statusText)
{
if ( m_bConsoleStyle )
{
return;
}
SetControlString( "SecondaryProgressLabel", statusText );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CLoadingDialog::OnClose()
{
// remove any rendering restrictions
HideOtherDialogs( false );
BaseClass::OnClose();
}
//-----------------------------------------------------------------------------
// Purpose: command handler
//-----------------------------------------------------------------------------
void CLoadingDialog::OnCommand(const char *command)
{
if ( !stricmp(command, "Cancel") )
{
// disconnect from the server
engine->ClientCmd_Unrestricted("disconnect\n");
// close
Close();
}
else
{
BaseClass::OnCommand(command);
}
}
void CLoadingDialog::OnKeyCodeTyped(KeyCode code)
{
if ( m_bConsoleStyle )
{
return;
}
if ( code == KEY_ESCAPE )
{
OnCommand("Cancel");
}
else
{
BaseClass::OnKeyCodeTyped(code);
}
}
//-----------------------------------------------------------------------------
// Purpose: Maps ESC to quiting loading
//-----------------------------------------------------------------------------
void CLoadingDialog::OnKeyCodePressed(KeyCode code)
{
if ( m_bConsoleStyle )
{
return;
}
ButtonCode_t nButtonCode = GetBaseButtonCode( code );
if ( nButtonCode == KEY_XBUTTON_B || nButtonCode == KEY_XBUTTON_A || nButtonCode == STEAMCONTROLLER_A || nButtonCode == STEAMCONTROLLER_B )
{
OnCommand("Cancel");
}
else
{
BaseClass::OnKeyCodePressed(code);
}
}
//-----------------------------------------------------------------------------
// Purpose: Singleton accessor
//-----------------------------------------------------------------------------
extern vgui::DHANDLE<CLoadingDialog> g_hLoadingDialog;
CLoadingDialog *LoadingDialog()
{
return g_hLoadingDialog.Get();
}