summaryrefslogtreecommitdiff
path: root/gameui/BasePanel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gameui/BasePanel.cpp')
-rw-r--r--gameui/BasePanel.cpp4832
1 files changed, 4832 insertions, 0 deletions
diff --git a/gameui/BasePanel.cpp b/gameui/BasePanel.cpp
new file mode 100644
index 0000000..eaabd91
--- /dev/null
+++ b/gameui/BasePanel.cpp
@@ -0,0 +1,4832 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//===========================================================================//
+
+#include <stdio.h>
+
+#include "threadtools.h"
+
+#include "BasePanel.h"
+#include "EngineInterface.h"
+#include "VGuiSystemModuleLoader.h"
+
+#include "vgui/IInput.h"
+#include "vgui/ILocalize.h"
+#include "vgui/IPanel.h"
+#include "vgui/ISurface.h"
+#include "vgui/ISystem.h"
+#include "vgui/IVGui.h"
+#include "filesystem.h"
+#include "GameConsole.h"
+#include "GameUI_Interface.h"
+#include "vgui_controls/PropertyDialog.h"
+#include "vgui_controls/PropertySheet.h"
+#include "materialsystem/materialsystem_config.h"
+#include "materialsystem/imaterialsystem.h"
+#include "sourcevr/isourcevirtualreality.h"
+
+using namespace vgui;
+
+#include "GameConsole.h"
+#include "ModInfo.h"
+
+#include "IGameUIFuncs.h"
+#include "LoadingDialog.h"
+#include "BackgroundMenuButton.h"
+#include "vgui_controls/AnimationController.h"
+#include "vgui_controls/ImagePanel.h"
+#include "vgui_controls/Label.h"
+#include "vgui_controls/Menu.h"
+#include "vgui_controls/MenuItem.h"
+#include "vgui_controls/PHandle.h"
+#include "vgui_controls/MessageBox.h"
+#include "vgui_controls/QueryBox.h"
+#include "vgui_controls/ControllerMap.h"
+#include "vgui_controls/KeyRepeat.h"
+#include "tier0/icommandline.h"
+#include "tier1/convar.h"
+#include "NewGameDialog.h"
+#include "BonusMapsDialog.h"
+#include "LoadGameDialog.h"
+#include "SaveGameDialog.h"
+#include "OptionsDialog.h"
+#include "CreateMultiplayerGameDialog.h"
+#include "ChangeGameDialog.h"
+#include "BackgroundMenuButton.h"
+#include "PlayerListDialog.h"
+#include "BenchmarkDialog.h"
+#include "LoadCommentaryDialog.h"
+#include "ControllerDialog.h"
+#include "BonusMapsDatabase.h"
+#include "engine/IEngineSound.h"
+#include "bitbuf.h"
+#include "tier1/fmtstr.h"
+#include "inputsystem/iinputsystem.h"
+#include "ixboxsystem.h"
+#include "matchmaking/matchmakingbasepanel.h"
+#include "matchmaking/achievementsdialog.h"
+#include "iachievementmgr.h"
+#include "UtlSortVector.h"
+
+#include "game/client/IGameClientExports.h"
+
+#include "OptionsSubAudio.h"
+#include "hl2orange.spa.h"
+#include "CustomTabExplanationDialog.h"
+#if defined( _X360 )
+#include "xbox/xbox_launch.h"
+#else
+#include "xbox/xboxstubs.h"
+#endif
+
+#include "../engine/imatchmaking.h"
+#include "tier1/utlstring.h"
+#include "steam/steam_api.h"
+
+#undef MessageBox // Windows helpfully #define's this to MessageBoxA, we're using vgui::MessageBox
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+#define MAIN_MENU_INDENT_X360 10
+
+ConVar vgui_message_dialog_modal( "vgui_message_dialog_modal", "1", FCVAR_ARCHIVE );
+
+extern vgui::DHANDLE<CLoadingDialog> g_hLoadingDialog;
+static CBasePanel *g_pBasePanel = NULL;
+static float g_flAnimationPadding = 0.01f;
+
+extern const char *COM_GetModDirectory( void );
+
+extern ConVar x360_audio_english;
+extern bool bSteamCommunityFriendsVersion;
+
+static vgui::DHANDLE<vgui::PropertyDialog> g_hOptionsDialog;
+
+//-----------------------------------------------------------------------------
+// Purpose: singleton accessor
+//-----------------------------------------------------------------------------
+CBasePanel *BasePanel()
+{
+ return g_pBasePanel;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: hack function to give the module loader access to the main panel handle
+// only used in VguiSystemModuleLoader
+//-----------------------------------------------------------------------------
+VPANEL GetGameUIBasePanel()
+{
+ return BasePanel()->GetVPanel();
+}
+
+CGameMenuItem::CGameMenuItem(vgui::Menu *parent, const char *name) : BaseClass(parent, name, "GameMenuItem")
+{
+ m_bRightAligned = false;
+}
+
+void CGameMenuItem::ApplySchemeSettings(IScheme *pScheme)
+{
+ BaseClass::ApplySchemeSettings(pScheme);
+
+ // make fully transparent
+ SetFgColor(GetSchemeColor("MainMenu.TextColor", pScheme));
+ SetBgColor(Color(0, 0, 0, 0));
+ SetDefaultColor(GetSchemeColor("MainMenu.TextColor", pScheme), Color(0, 0, 0, 0));
+ SetArmedColor(GetSchemeColor("MainMenu.ArmedTextColor", pScheme), Color(0, 0, 0, 0));
+ SetDepressedColor(GetSchemeColor("MainMenu.DepressedTextColor", pScheme), Color(0, 0, 0, 0));
+ SetContentAlignment(Label::a_west);
+ SetBorder(NULL);
+ SetDefaultBorder(NULL);
+ SetDepressedBorder(NULL);
+ SetKeyFocusBorder(NULL);
+
+ vgui::HFont hMainMenuFont = pScheme->GetFont( "MainMenuFont", IsProportional() );
+
+ if ( hMainMenuFont )
+ {
+ SetFont( hMainMenuFont );
+ }
+ else
+ {
+ SetFont( pScheme->GetFont( "MenuLarge", IsProportional() ) );
+ }
+ SetTextInset(0, 0);
+ SetArmedSound("UI/buttonrollover.wav");
+ SetDepressedSound("UI/buttonclick.wav");
+ SetReleasedSound("UI/buttonclickrelease.wav");
+ SetButtonActivationType(Button::ACTIVATE_ONPRESSED);
+
+ if ( GameUI().IsConsoleUI() )
+ {
+ SetArmedColor(GetSchemeColor("MainMenu.ArmedTextColor", pScheme), GetSchemeColor("Button.ArmedBgColor", pScheme));
+ SetTextInset( MAIN_MENU_INDENT_X360, 0 );
+ }
+
+ if (m_bRightAligned)
+ {
+ SetContentAlignment(Label::a_east);
+ }
+}
+
+void CGameMenuItem::PaintBackground()
+{
+ if ( !GameUI().IsConsoleUI() )
+ {
+ BaseClass::PaintBackground();
+ }
+ else
+ {
+ if ( !IsArmed() || !IsVisible() || GetParent()->GetAlpha() < 32 )
+ return;
+
+ int wide, tall;
+ GetSize( wide, tall );
+
+ DrawBoxFade( 0, 0, wide, tall, GetButtonBgColor(), 1.0f, 255, 0, true );
+ DrawBoxFade( 2, 2, wide - 4, tall - 4, Color( 0, 0, 0, 96 ), 1.0f, 255, 0, true );
+ }
+}
+
+void CGameMenuItem::SetRightAlignedText(bool state)
+{
+ m_bRightAligned = state;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: General purpose 1 of N menu
+//-----------------------------------------------------------------------------
+class CGameMenu : public vgui::Menu
+{
+public:
+ DECLARE_CLASS_SIMPLE( CGameMenu, vgui::Menu );
+
+ CGameMenu(vgui::Panel *parent, const char *name) : BaseClass(parent, name)
+ {
+ if ( GameUI().IsConsoleUI() )
+ {
+ // shows graphic button hints
+ m_pConsoleFooter = new CFooterPanel( parent, "MainMenuFooter" );
+
+ int iFixedWidth = 245;
+
+#ifdef _X360
+ // In low def we need a smaller highlight
+ XVIDEO_MODE videoMode;
+ XGetVideoMode( &videoMode );
+ if ( !videoMode.fIsHiDef )
+ {
+ iFixedWidth = 240;
+ }
+ else
+ {
+ iFixedWidth = 350;
+ }
+#endif
+
+ SetFixedWidth( iFixedWidth );
+ }
+ else
+ {
+ m_pConsoleFooter = NULL;
+ }
+
+ m_hMainMenuOverridePanel = NULL;
+ }
+
+ virtual void ApplySchemeSettings(IScheme *pScheme)
+ {
+ BaseClass::ApplySchemeSettings(pScheme);
+
+ // make fully transparent
+ SetMenuItemHeight(atoi(pScheme->GetResourceString("MainMenu.MenuItemHeight")));
+ SetBgColor(Color(0, 0, 0, 0));
+ SetBorder(NULL);
+ }
+
+ virtual void LayoutMenuBorder()
+ {
+ }
+
+ void SetMainMenuOverride( vgui::VPANEL panel )
+ {
+ m_hMainMenuOverridePanel = panel;
+
+ if ( m_hMainMenuOverridePanel )
+ {
+ // We've got an override panel. Nuke all our menu items.
+ DeleteAllItems();
+ }
+ }
+
+ virtual void SetVisible(bool state)
+ {
+ if ( m_hMainMenuOverridePanel )
+ {
+ // force to be always visible
+ ipanel()->SetVisible( m_hMainMenuOverridePanel, true );
+
+ // move us to the back instead of going invisible
+ if ( !state )
+ {
+ ipanel()->MoveToBack(m_hMainMenuOverridePanel);
+ }
+ }
+
+ // force to be always visible
+ BaseClass::SetVisible(true);
+
+ // move us to the back instead of going invisible
+ if (!state)
+ {
+ ipanel()->MoveToBack(GetVPanel());
+ }
+ }
+
+ virtual int AddMenuItem(const char *itemName, const char *itemText, const char *command, Panel *target, KeyValues *userData = NULL)
+ {
+ MenuItem *item = new CGameMenuItem(this, itemName);
+ item->AddActionSignalTarget(target);
+ item->SetCommand(command);
+ item->SetText(itemText);
+ item->SetUserData(userData);
+ return BaseClass::AddMenuItem(item);
+ }
+
+ virtual int AddMenuItem(const char *itemName, const char *itemText, KeyValues *command, Panel *target, KeyValues *userData = NULL)
+ {
+ CGameMenuItem *item = new CGameMenuItem(this, itemName);
+ item->AddActionSignalTarget(target);
+ item->SetCommand(command);
+ item->SetText(itemText);
+ item->SetRightAlignedText(true);
+ item->SetUserData(userData);
+ return BaseClass::AddMenuItem(item);
+ }
+
+ virtual void SetMenuItemBlinkingState( const char *itemName, bool state )
+ {
+ for (int i = 0; i < GetChildCount(); i++)
+ {
+ Panel *child = GetChild(i);
+ MenuItem *menuItem = dynamic_cast<MenuItem *>(child);
+ if (menuItem)
+ {
+ if ( Q_strcmp( menuItem->GetCommand()->GetString("command", ""), itemName ) == 0 )
+ {
+ menuItem->SetBlink( state );
+ }
+ }
+ }
+ InvalidateLayout();
+ }
+
+ virtual void OnSetFocus()
+ {
+ if ( m_hMainMenuOverridePanel )
+ {
+ Panel *pMainMenu = ipanel()->GetPanel( m_hMainMenuOverridePanel, "ClientDLL" );
+ if ( pMainMenu )
+ {
+ pMainMenu->PerformLayout();
+ }
+ }
+
+ BaseClass::OnSetFocus();
+ }
+
+ virtual void OnCommand(const char *command)
+ {
+ m_KeyRepeat.Reset();
+
+
+ if (!stricmp(command, "Open"))
+ {
+ if ( m_hMainMenuOverridePanel )
+ {
+ // force to be always visible
+ ipanel()->MoveToFront( m_hMainMenuOverridePanel );
+ ipanel()->RequestFocus( m_hMainMenuOverridePanel );
+ }
+ else
+ {
+ MoveToFront();
+ RequestFocus();
+ }
+ }
+ else
+ {
+ BaseClass::OnCommand(command);
+ }
+ }
+
+ virtual void OnKeyCodePressed( KeyCode code )
+ {
+ if ( IsX360() )
+ {
+ if ( GetAlpha() != 255 )
+ {
+ SetEnabled( false );
+ // inhibit key activity during transitions
+ return;
+ }
+
+ SetEnabled( true );
+
+ if ( code == KEY_XBUTTON_B || code == KEY_XBUTTON_START )
+ {
+ if ( GameUI().IsInLevel() )
+ {
+ GetParent()->OnCommand( "ResumeGame" );
+ }
+ return;
+ }
+ }
+
+ m_KeyRepeat.KeyDown( code );
+
+ int nDir = 0;
+
+ switch ( code )
+ {
+ case KEY_XBUTTON_UP:
+ case KEY_XSTICK1_UP:
+ case KEY_XSTICK2_UP:
+ case KEY_UP:
+ case STEAMCONTROLLER_DPAD_UP:
+ nDir = -1;
+ break;
+
+ case KEY_XBUTTON_DOWN:
+ case KEY_XSTICK1_DOWN:
+ case KEY_XSTICK2_DOWN:
+ case KEY_DOWN:
+ case STEAMCONTROLLER_DPAD_DOWN:
+ nDir = 1;
+ break;
+ }
+
+ if ( nDir != 0 )
+ {
+ CUtlSortVector< SortedPanel_t, CSortedPanelYLess > vecSortedButtons;
+ VguiPanelGetSortedChildButtonList( this, (void*)&vecSortedButtons );
+
+ if ( VguiPanelNavigateSortedChildButtonList( (void*)&vecSortedButtons, nDir ) != -1 )
+ {
+ // Handled!
+ return;
+ }
+ }
+ else if ( code == KEY_XBUTTON_A || code == STEAMCONTROLLER_A )
+ {
+ CUtlSortVector< SortedPanel_t, CSortedPanelYLess > vecSortedButtons;
+ VguiPanelGetSortedChildButtonList( this, (void*)&vecSortedButtons );
+
+ for ( int i = 0; i < vecSortedButtons.Count(); i++ )
+ {
+ if ( vecSortedButtons[ i ].pButton->IsArmed() )
+ {
+ vecSortedButtons[ i ].pButton->DoClick();
+ return;
+ }
+ }
+ }
+
+ BaseClass::OnKeyCodePressed( code );
+
+ // HACK: Allow F key bindings to operate even here
+ if ( IsPC() && code >= KEY_F1 && code <= KEY_F12 )
+ {
+ // See if there is a binding for the FKey
+ const char *binding = gameuifuncs->GetBindingForButtonCode( code );
+ if ( binding && binding[0] )
+ {
+ // submit the entry as a console commmand
+ char szCommand[256];
+ Q_strncpy( szCommand, binding, sizeof( szCommand ) );
+ engine->ClientCmd_Unrestricted( szCommand );
+ }
+ }
+ }
+
+ void OnKeyCodeReleased( vgui::KeyCode code )
+ {
+ m_KeyRepeat.KeyUp( code );
+
+ BaseClass::OnKeyCodeReleased( code );
+ }
+
+ void OnThink()
+ {
+ vgui::KeyCode code = m_KeyRepeat.KeyRepeated();
+ if ( code )
+ {
+ OnKeyCodeTyped( code );
+ }
+
+ BaseClass::OnThink();
+ }
+
+ virtual void OnKillFocus()
+ {
+ BaseClass::OnKillFocus();
+
+ if ( m_hMainMenuOverridePanel )
+ {
+ // force us to the rear when we lose focus (so it looks like the menu is always on the background)
+ surface()->MovePopupToBack( m_hMainMenuOverridePanel );
+ }
+ else
+ {
+ // force us to the rear when we lose focus (so it looks like the menu is always on the background)
+ surface()->MovePopupToBack(GetVPanel());
+ }
+
+ m_KeyRepeat.Reset();
+ }
+
+ void ShowFooter( bool bShow )
+ {
+ if ( m_pConsoleFooter )
+ {
+ m_pConsoleFooter->SetVisible( bShow );
+ }
+ }
+
+ void UpdateMenuItemState( bool isInGame, bool isMultiplayer, bool isInReplay, bool isVREnabled, bool isVRActive )
+ {
+ bool isSteam = IsPC() && ( CommandLine()->FindParm("-steam") != 0 );
+ bool bIsConsoleUI = GameUI().IsConsoleUI();
+
+ // disabled save button if we're not in a game
+ for (int i = 0; i < GetChildCount(); i++)
+ {
+ Panel *child = GetChild(i);
+ MenuItem *menuItem = dynamic_cast<MenuItem *>(child);
+ if (menuItem)
+ {
+ bool shouldBeVisible = true;
+ // filter the visibility
+ KeyValues *kv = menuItem->GetUserData();
+ if (!kv)
+ continue;
+
+ if (!isInGame && kv->GetInt("OnlyInGame") )
+ {
+ shouldBeVisible = false;
+ }
+ if (!isInReplay && kv->GetInt("OnlyInReplay") )
+ {
+ shouldBeVisible = false;
+ }
+ else if (!isVREnabled && kv->GetInt("OnlyWhenVREnabled") )
+ {
+ shouldBeVisible = false;
+ }
+ else if ( ( !isVRActive || ShouldForceVRActive() ) && kv->GetInt( "OnlyWhenVRActive" ) )
+ {
+ shouldBeVisible = false;
+ }
+ else if (isVRActive && kv->GetInt("OnlyWhenVRInactive") )
+ {
+ shouldBeVisible = false;
+ }
+ else if (isMultiplayer && kv->GetInt("notmulti"))
+ {
+ shouldBeVisible = false;
+ }
+ else if (isInGame && !isMultiplayer && kv->GetInt("notsingle"))
+ {
+ shouldBeVisible = false;
+ }
+ else if (isSteam && kv->GetInt("notsteam"))
+ {
+ shouldBeVisible = false;
+ }
+ else if ( !bIsConsoleUI && kv->GetInt( "ConsoleOnly" ) )
+ {
+ shouldBeVisible = false;
+ }
+
+ // If we're playing back a replay, hide everything else
+ if ( isInReplay && !kv->GetInt("OnlyInReplay") )
+ {
+ shouldBeVisible = false;
+ }
+
+ menuItem->SetVisible( shouldBeVisible );
+ }
+ }
+
+ if ( !isInGame )
+ {
+ // Sort them into their original order
+ for ( int j = 0; j < GetChildCount() - 2; j++ )
+ {
+ MoveMenuItem( j, j + 1 );
+ }
+ }
+ else
+ {
+ // Sort them into their in game order
+ for ( int i = 0; i < GetChildCount(); i++ )
+ {
+ for ( int j = i; j < GetChildCount() - 2; j++ )
+ {
+ int iID1 = GetMenuID( j );
+ int iID2 = GetMenuID( j + 1 );
+
+ MenuItem *menuItem1 = GetMenuItem( iID1 );
+ MenuItem *menuItem2 = GetMenuItem( iID2 );
+
+ KeyValues *kv1 = menuItem1->GetUserData();
+ KeyValues *kv2 = menuItem2->GetUserData();
+
+ if ( kv1->GetInt("InGameOrder") > kv2->GetInt("InGameOrder") )
+ MoveMenuItem( iID2, iID1 );
+ }
+ }
+ }
+
+ InvalidateLayout();
+
+ if ( m_pConsoleFooter )
+ {
+ // update the console footer
+ const char *pHelpName;
+ if ( !isInGame )
+ pHelpName = "MainMenu";
+ else
+ pHelpName = "GameMenu";
+
+ if ( !m_pConsoleFooter->GetHelpName() || V_stricmp( pHelpName, m_pConsoleFooter->GetHelpName() ) )
+ {
+ // game menu must re-establish its own help once it becomes re-active
+ m_pConsoleFooter->SetHelpNameAndReset( pHelpName );
+ m_pConsoleFooter->AddNewButtonLabel( "#GameUI_Action", "#GameUI_Icons_A_BUTTON" );
+ if ( isInGame )
+ {
+ m_pConsoleFooter->AddNewButtonLabel( "#GameUI_Close", "#GameUI_Icons_B_BUTTON" );
+ }
+ }
+ }
+ }
+
+ MESSAGE_FUNC_INT( OnCursorEnteredMenuItem, "CursorEnteredMenuItem", VPanel);
+
+private:
+ CFooterPanel *m_pConsoleFooter;
+ vgui::CKeyRepeatHandler m_KeyRepeat;
+ vgui::VPANEL m_hMainMenuOverridePanel;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Respond to cursor entering a menuItem.
+//-----------------------------------------------------------------------------
+void CGameMenu::OnCursorEnteredMenuItem(int VPanel)
+{
+ VPANEL menuItem = (VPANEL)VPanel;
+ MenuItem *item = static_cast<MenuItem *>(ipanel()->GetPanel(menuItem, GetModuleName()));
+ KeyValues *pCommand = item->GetCommand();
+ if ( !pCommand->GetFirstSubKey() )
+ return;
+ const char *pszCmd = pCommand->GetFirstSubKey()->GetString();
+ if ( !pszCmd || !pszCmd[0] )
+ return;
+
+ BaseClass::OnCursorEnteredMenuItem( VPanel );
+}
+
+static CBackgroundMenuButton* CreateMenuButton( CBasePanel *parent, const char *panelName, const wchar_t *panelText )
+{
+ CBackgroundMenuButton *pButton = new CBackgroundMenuButton( parent, panelName );
+ pButton->SetProportional(true);
+ pButton->SetCommand("OpenGameMenu");
+ pButton->SetText(panelText);
+
+ return pButton;
+}
+
+bool g_bIsCreatingNewGameMenuForPreFetching = false;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CBasePanel::CBasePanel() : Panel(NULL, "BaseGameUIPanel")
+{
+ g_pBasePanel = this;
+ m_bLevelLoading = false;
+ m_eBackgroundState = BACKGROUND_INITIAL;
+ m_flTransitionStartTime = 0.0f;
+ m_flTransitionEndTime = 0.0f;
+ m_flFrameFadeInTime = 0.5f;
+ m_bRenderingBackgroundTransition = false;
+ m_bFadingInMenus = false;
+ m_bEverActivated = false;
+ m_iGameMenuInset = 24;
+ m_bPlatformMenuInitialized = false;
+ m_bHaveDarkenedBackground = false;
+ m_bHaveDarkenedTitleText = true;
+ m_bForceTitleTextUpdate = true;
+ m_BackdropColor = Color(0, 0, 0, 128);
+ m_pConsoleAnimationController = NULL;
+ m_pConsoleControlSettings = NULL;
+ m_bCopyFrameBuffer = false;
+ m_bUseRenderTargetImage = false;
+ m_ExitingFrameCount = 0;
+ m_bXUIVisible = false;
+ m_bUseMatchmaking = false;
+ m_bRestartFromInvite = false;
+ m_bRestartSameGame = false;
+ m_bUserRefusedSignIn = false;
+ m_bUserRefusedStorageDevice = false;
+ m_bWaitingForUserSignIn = false;
+ m_bWaitingForStorageDeviceHandle = false;
+ m_bNeedStorageDeviceHandle = false;
+ m_bStorageBladeShown = false;
+ m_iStorageID = XBX_INVALID_STORAGE_ID;
+ m_pAsyncJob = NULL;
+ m_pStorageDeviceValidatedNotify = NULL;
+
+ m_iRenderTargetImageID = -1;
+ m_iBackgroundImageID = -1;
+ m_iProductImageID = -1;
+ m_iLoadingImageID = -1;
+
+ if ( GameUI().IsConsoleUI() )
+ {
+ m_pConsoleAnimationController = new AnimationController( this );
+ m_pConsoleAnimationController->SetScriptFile( GetVPanel(), "scripts/GameUIAnimations.txt" );
+ m_pConsoleAnimationController->SetAutoReloadScript( IsDebug() );
+
+ m_pConsoleControlSettings = new KeyValues( "XboxDialogs.res" );
+ if ( !m_pConsoleControlSettings->LoadFromFile( g_pFullFileSystem, "resource/UI/XboxDialogs.res", "GAME" ) )
+ {
+ Error( "Failed to load UI control settings!\n" );
+ }
+ else
+ {
+ m_pConsoleControlSettings->ProcessResolutionKeys( surface()->GetResolutionKey() );
+ }
+
+#ifdef _X360
+ x360_audio_english.SetValue( XboxLaunch()->GetForceEnglish() );
+#endif
+ }
+
+ m_pGameMenuButtons.AddToTail( CreateMenuButton( this, "GameMenuButton", ModInfo().GetGameTitle() ) );
+ m_pGameMenuButtons.AddToTail( CreateMenuButton( this, "GameMenuButton2", ModInfo().GetGameTitle2() ) );
+#ifdef CS_BETA
+ if ( !ModInfo().NoCrosshair() ) // hack to not show the BETA for HL2 or HL1Port
+ {
+ m_pGameMenuButtons.AddToTail( CreateMenuButton( this, "BetaButton", L"BETA" ) );
+ }
+#endif // CS_BETA
+
+ m_pGameMenu = NULL;
+ m_pGameLogo = NULL;
+ m_hMainMenuOverridePanel = NULL;
+
+ if ( SteamClient() )
+ {
+ HSteamPipe steamPipe = SteamClient()->CreateSteamPipe();
+ ISteamUtils *pUtils = SteamClient()->GetISteamUtils( steamPipe, "SteamUtils002" );
+ if ( pUtils )
+ {
+ bSteamCommunityFriendsVersion = true;
+ }
+
+ SteamClient()->BReleaseSteamPipe( steamPipe );
+ }
+
+ CreateGameMenu();
+ CreateGameLogo();
+
+ // Bonus maps menu blinks if something has been unlocked since the player last opened the menu
+ // This is saved as persistant data, and here is where we check for that
+ CheckBonusBlinkState();
+
+ // start the menus fully transparent
+ SetMenuAlpha( 0 );
+
+ if ( GameUI().IsConsoleUI() )
+ {
+ // do any costly resource prefetching now....
+ // force the new dialog to get all of its chapter pics
+ g_bIsCreatingNewGameMenuForPreFetching = true;
+ m_hNewGameDialog = new CNewGameDialog( this, false );
+ m_hNewGameDialog->MarkForDeletion();
+ g_bIsCreatingNewGameMenuForPreFetching = false;
+
+ m_hOptionsDialog_Xbox = new COptionsDialogXbox( this );
+ m_hOptionsDialog_Xbox->MarkForDeletion();
+
+ m_hControllerDialog = new CControllerDialog( this );
+ m_hControllerDialog->MarkForDeletion();
+
+ ArmFirstMenuItem();
+ m_pConsoleAnimationController->StartAnimationSequence( "InitializeUILayout" );
+ }
+
+ // Record data used for rich presence updates
+ if ( IsX360() )
+ {
+ // Get our active mod directory name
+ const char *pGameName = CommandLine()->ParmValue( "-game", "hl2" );;
+
+ // Set the game we're playing
+ m_iGameID = CONTEXT_GAME_GAME_HALF_LIFE_2;
+ m_bSinglePlayer = true;
+ if ( Q_stristr( pGameName, "episodic" ) )
+ {
+ m_iGameID = CONTEXT_GAME_GAME_EPISODE_ONE;
+ }
+ else if ( Q_stristr( pGameName, "ep2" ) )
+ {
+ m_iGameID = CONTEXT_GAME_GAME_EPISODE_TWO;
+ }
+ else if ( Q_stristr( pGameName, "portal" ) )
+ {
+ m_iGameID = CONTEXT_GAME_GAME_PORTAL;
+ }
+ else if ( Q_stristr( pGameName, "tf" ) )
+ {
+ m_iGameID = CONTEXT_GAME_GAME_TEAM_FORTRESS;
+ m_bSinglePlayer = false;
+ }
+
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Xbox 360 - Get the console UI keyvalues to pass to LoadControlSettings()
+//-----------------------------------------------------------------------------
+KeyValues *CBasePanel::GetConsoleControlSettings( void )
+{
+ return m_pConsoleControlSettings;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Causes the first menu item to be armed
+//-----------------------------------------------------------------------------
+void CBasePanel::ArmFirstMenuItem( void )
+{
+ UpdateGameMenus();
+
+ // Arm the first item in the menu
+ for ( int i = 0; i < m_pGameMenu->GetItemCount(); ++i )
+ {
+ if ( m_pGameMenu->GetMenuItem( i )->IsVisible() )
+ {
+ m_pGameMenu->SetCurrentlyHighlightedItem( i );
+ break;
+ }
+ }
+}
+
+CBasePanel::~CBasePanel()
+{
+ g_pBasePanel = NULL;
+
+ if ( vgui::surface() )
+ {
+ if ( m_iRenderTargetImageID != -1 )
+ {
+ vgui::surface()->DestroyTextureID( m_iRenderTargetImageID );
+ m_iRenderTargetImageID = -1;
+ }
+
+ if ( m_iBackgroundImageID != -1 )
+ {
+ vgui::surface()->DestroyTextureID( m_iBackgroundImageID );
+ m_iBackgroundImageID = -1;
+ }
+
+ if ( m_iProductImageID != -1 )
+ {
+ vgui::surface()->DestroyTextureID( m_iProductImageID );
+ m_iProductImageID = -1;
+ }
+
+ if ( m_iLoadingImageID != -1 )
+ {
+ vgui::surface()->DestroyTextureID( m_iLoadingImageID );
+ m_iLoadingImageID = -1;
+ }
+ }
+}
+
+static const char *g_rgValidCommands[] =
+{
+ "OpenGameMenu",
+ "OpenPlayerListDialog",
+ "OpenNewGameDialog",
+ "OpenLoadGameDialog",
+ "OpenSaveGameDialog",
+ "OpenCustomMapsDialog",
+ "OpenOptionsDialog",
+ "OpenBenchmarkDialog",
+ "OpenServerBrowser",
+ "OpenFriendsDialog",
+ "OpenLoadDemoDialog",
+ "OpenCreateMultiplayerGameDialog",
+ "OpenChangeGameDialog",
+ "OpenLoadCommentaryDialog",
+ "Quit",
+ "QuitNoConfirm",
+ "ResumeGame",
+ "Disconnect",
+};
+
+static void CC_GameMenuCommand( const CCommand &args )
+{
+ int c = args.ArgC();
+ if ( c < 2 )
+ {
+ Msg( "Usage: gamemenucommand <commandname>\n" );
+ return;
+ }
+
+ if ( !g_pBasePanel )
+ {
+ return;
+ }
+
+ vgui::ivgui()->PostMessage( g_pBasePanel->GetVPanel(), new KeyValues("Command", "command", args[1] ), NULL);
+}
+
+static int CC_GameMenuCompletionFunc( char const *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] )
+{
+ char const *cmdname = "gamemenucommand";
+
+ char *substring = (char *)partial;
+ if ( Q_strstr( partial, cmdname ) )
+ {
+ substring = (char *)partial + strlen( cmdname ) + 1;
+ }
+
+ int checklen = Q_strlen( substring );
+
+ CUtlRBTree< CUtlString > symbols( 0, 0, UtlStringLessFunc );
+
+ int i;
+ int c = ARRAYSIZE( g_rgValidCommands );
+ for ( i = 0; i < c; ++i )
+ {
+ if ( Q_strnicmp( g_rgValidCommands[ i ], substring, checklen ) )
+ continue;
+
+ CUtlString str;
+ str = g_rgValidCommands[ i ];
+
+ symbols.Insert( str );
+
+ // Too many
+ if ( symbols.Count() >= COMMAND_COMPLETION_MAXITEMS )
+ break;
+ }
+
+ // Now fill in the results
+ int slot = 0;
+ for ( i = symbols.FirstInorder(); i != symbols.InvalidIndex(); i = symbols.NextInorder( i ) )
+ {
+ char const *name = symbols[ i ].String();
+
+ char buf[ 512 ];
+ Q_strncpy( buf, name, sizeof( buf ) );
+ Q_strlower( buf );
+
+ Q_snprintf( commands[ slot++ ], COMMAND_COMPLETION_ITEM_LENGTH, "%s %s",
+ cmdname, buf );
+ }
+
+ return slot;
+}
+
+static ConCommand gamemenucommand( "gamemenucommand", CC_GameMenuCommand, "Issue game menu command.", 0, CC_GameMenuCompletionFunc );
+
+//-----------------------------------------------------------------------------
+// Purpose: paints the main background image
+//-----------------------------------------------------------------------------
+void CBasePanel::PaintBackground()
+{
+ if ( !GameUI().IsInLevel() || g_hLoadingDialog.Get() || m_ExitingFrameCount )
+ {
+ // not in the game or loading dialog active or exiting, draw the ui background
+ DrawBackgroundImage();
+ }
+ else if ( IsX360() )
+ {
+ // only valid during loading from level to level
+ m_bUseRenderTargetImage = false;
+ }
+
+ if ( m_flBackgroundFillAlpha )
+ {
+ int swide, stall;
+ surface()->GetScreenSize(swide, stall);
+ surface()->DrawSetColor(0, 0, 0, m_flBackgroundFillAlpha);
+ surface()->DrawFilledRect(0, 0, swide, stall);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Updates which background state we should be in.
+//
+// NOTE: These states change at funny times and overlap. They CANNOT be
+// used to demarcate exact transitions.
+//-----------------------------------------------------------------------------
+void CBasePanel::UpdateBackgroundState()
+{
+ if ( m_ExitingFrameCount )
+ {
+ // trumps all, an exiting state must own the screen image
+ // cannot be stopped
+ SetBackgroundRenderState( BACKGROUND_EXITING );
+ }
+ else if ( GameUI().IsInLevel() )
+ {
+ SetBackgroundRenderState( BACKGROUND_LEVEL );
+ }
+ else if ( GameUI().IsInBackgroundLevel() && !m_bLevelLoading )
+ {
+ // 360 guarantees a progress bar
+ // level loading is truly completed when the progress bar is gone, then transition to main menu
+ if ( IsPC() || ( IsX360() && !g_hLoadingDialog.Get() ) )
+ {
+ SetBackgroundRenderState( BACKGROUND_MAINMENU );
+ }
+ }
+ else if ( m_bLevelLoading )
+ {
+ SetBackgroundRenderState( BACKGROUND_LOADING );
+ }
+ else if ( m_bEverActivated && m_bPlatformMenuInitialized )
+ {
+ SetBackgroundRenderState( BACKGROUND_DISCONNECTED );
+ }
+
+ if ( GameUI().IsConsoleUI() )
+ {
+ if ( !m_ExitingFrameCount && !m_bLevelLoading && !g_hLoadingDialog.Get() && GameUI().IsInLevel() )
+ {
+ // paused
+ if ( m_flBackgroundFillAlpha == 0.0f )
+ m_flBackgroundFillAlpha = 120.0f;
+ }
+ else
+ {
+ m_flBackgroundFillAlpha = 0;
+ }
+
+ // console ui has completely different menu/dialog/fill/fading behavior
+ return;
+ }
+
+ // don't evaluate the rest until we've initialized the menus
+ if ( !m_bPlatformMenuInitialized )
+ return;
+
+ // check for background fill
+ // fill over the top if we have any dialogs up
+ int i;
+ bool bHaveActiveDialogs = false;
+ bool bIsInLevel = GameUI().IsInLevel();
+ for ( i = 0; i < GetChildCount(); ++i )
+ {
+ VPANEL child = ipanel()->GetChild( GetVPanel(), i );
+ if ( child
+ && ipanel()->IsVisible( child )
+ && ipanel()->IsPopup( child )
+ && child != m_pGameMenu->GetVPanel() )
+ {
+ bHaveActiveDialogs = true;
+ }
+ }
+ // see if the base gameui panel has dialogs hanging off it (engine stuff, console, bug reporter)
+ VPANEL parent = GetVParent();
+ for ( i = 0; i < ipanel()->GetChildCount( parent ); ++i )
+ {
+ VPANEL child = ipanel()->GetChild( parent, i );
+ if ( child
+ && ipanel()->IsVisible( child )
+ && ipanel()->IsPopup( child )
+ && child != GetVPanel() )
+ {
+ bHaveActiveDialogs = true;
+ }
+ }
+
+ // check to see if we need to fade in the background fill
+ bool bNeedDarkenedBackground = (bHaveActiveDialogs || bIsInLevel);
+ if ( m_bHaveDarkenedBackground != bNeedDarkenedBackground )
+ {
+ // fade in faster than we fade out
+ float targetAlpha, duration;
+ if ( bNeedDarkenedBackground )
+ {
+ // fade in background tint
+ targetAlpha = m_BackdropColor[3];
+ duration = m_flFrameFadeInTime;
+ }
+ else
+ {
+ // fade out background tint
+ targetAlpha = 0.0f;
+ duration = 2.0f;
+ }
+
+ m_bHaveDarkenedBackground = bNeedDarkenedBackground;
+ vgui::GetAnimationController()->RunAnimationCommand( this, "m_flBackgroundFillAlpha", targetAlpha, 0.0f, duration, AnimationController::INTERPOLATOR_LINEAR );
+ }
+
+ // check to see if the game title should be dimmed
+ // don't transition on level change
+ if ( m_bLevelLoading )
+ return;
+
+ bool bNeedDarkenedTitleText = bHaveActiveDialogs;
+ if (m_bHaveDarkenedTitleText != bNeedDarkenedTitleText || m_bForceTitleTextUpdate)
+ {
+ float targetTitleAlpha, duration;
+ if (bHaveActiveDialogs)
+ {
+ // fade out title text
+ duration = m_flFrameFadeInTime;
+ targetTitleAlpha = 32.0f;
+ }
+ else
+ {
+ // fade in title text
+ duration = 2.0f;
+ targetTitleAlpha = 255.0f;
+ }
+
+ if ( m_pGameLogo )
+ {
+ vgui::GetAnimationController()->RunAnimationCommand( m_pGameLogo, "alpha", targetTitleAlpha, 0.0f, duration, AnimationController::INTERPOLATOR_LINEAR );
+ }
+
+ // Msg( "animating title (%d => %d at time %.2f)\n", m_pGameMenuButton->GetAlpha(), (int)targetTitleAlpha, engine->Time());
+ for ( i=0; i<m_pGameMenuButtons.Count(); ++i )
+ {
+ vgui::GetAnimationController()->RunAnimationCommand( m_pGameMenuButtons[i], "alpha", targetTitleAlpha, 0.0f, duration, AnimationController::INTERPOLATOR_LINEAR );
+ }
+ m_bHaveDarkenedTitleText = bNeedDarkenedTitleText;
+ m_bForceTitleTextUpdate = false;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets how the game background should render
+//-----------------------------------------------------------------------------
+void CBasePanel::SetBackgroundRenderState(EBackgroundState state)
+{
+ if ( state == m_eBackgroundState )
+ {
+ return;
+ }
+
+ // apply state change transition
+ float frametime = engine->Time();
+
+ if ( m_eBackgroundState == BACKGROUND_INITIAL && ( state == BACKGROUND_DISCONNECTED || state == BACKGROUND_MAINMENU ) )
+ {
+ ConVar* dev_loadtime_mainmenu = cvar->FindVar( "dev_loadtime_mainmenu" );
+ if (dev_loadtime_mainmenu) {
+ dev_loadtime_mainmenu->SetValue( frametime );
+ }
+ }
+
+
+ m_bRenderingBackgroundTransition = false;
+ m_bFadingInMenus = false;
+
+ CMatchmakingBasePanel *pPanel = GetMatchmakingBasePanel();
+
+ if ( pPanel )
+ {
+ if ( state == BACKGROUND_LOADING )
+ {
+ pPanel->SetVisible( false );
+ }
+ else
+ {
+ pPanel->SetVisible( true );
+ }
+ }
+
+ if ( state == BACKGROUND_EXITING )
+ {
+ // hide the menus
+ m_bCopyFrameBuffer = false;
+ }
+ else if ( state == BACKGROUND_DISCONNECTED || state == BACKGROUND_MAINMENU )
+ {
+ // menu fading
+ // make the menus visible
+ m_bFadingInMenus = true;
+ m_flFadeMenuStartTime = frametime;
+ m_flFadeMenuEndTime = frametime + 3.0f;
+
+ if ( state == BACKGROUND_MAINMENU )
+ {
+ // fade background into main menu
+ m_bRenderingBackgroundTransition = true;
+ m_flTransitionStartTime = frametime;
+ m_flTransitionEndTime = frametime + 3.0f;
+ }
+ }
+ else if ( state == BACKGROUND_LOADING )
+ {
+ if ( GameUI().IsConsoleUI() )
+ {
+ RunAnimationWithCallback( this, "InstantHideMainMenu", new KeyValues( "LoadMap" ) );
+ }
+
+ // hide the menus
+ SetMenuAlpha( 0 );
+ }
+ else if ( state == BACKGROUND_LEVEL )
+ {
+ // show the menus
+ SetMenuAlpha( 255 );
+ }
+
+ m_eBackgroundState = state;
+}
+
+void CBasePanel::StartExitingProcess()
+{
+ // must let a non trivial number of screen swaps occur to stabilize image
+ // ui runs in a constrained state, while shutdown is occurring
+ m_flTransitionStartTime = engine->Time();
+ m_flTransitionEndTime = m_flTransitionStartTime + 0.5f;
+ m_ExitingFrameCount = 30;
+ g_pInputSystem->DetachFromWindow();
+
+ CMatchmakingBasePanel *pPanel = GetMatchmakingBasePanel();
+ if ( pPanel )
+ {
+ pPanel->CloseAllDialogs( false );
+ }
+
+ engine->StartXboxExitingProcess();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Size should only change on first vgui frame after startup
+//-----------------------------------------------------------------------------
+void CBasePanel::OnSizeChanged( int newWide, int newTall )
+{
+ // Recenter message dialogs
+ m_MessageDialogHandler.PositionDialogs( newWide, newTall );
+
+ if ( m_hMatchmakingBasePanel.Get() )
+ {
+ m_hMatchmakingBasePanel->SetBounds( 0, 0, newWide, newTall );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: notifications
+//-----------------------------------------------------------------------------
+void CBasePanel::OnLevelLoadingStarted()
+{
+ m_bLevelLoading = true;
+
+ m_pGameMenu->ShowFooter( false );
+
+ if ( m_hMatchmakingBasePanel.Get() )
+ {
+ m_hMatchmakingBasePanel->OnCommand( "LevelLoadingStarted" );
+ }
+
+ if ( IsX360() && m_eBackgroundState == BACKGROUND_LEVEL )
+ {
+ // already in a level going to another level
+ // frame buffer is about to be cleared, copy it off for ui backing purposes
+ m_bCopyFrameBuffer = true;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: notification
+//-----------------------------------------------------------------------------
+void CBasePanel::OnLevelLoadingFinished()
+{
+ m_bLevelLoading = false;
+
+ if ( m_hMatchmakingBasePanel.Get() )
+ {
+ m_hMatchmakingBasePanel->OnCommand( "LevelLoadingFinished" );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Draws the background image.
+//-----------------------------------------------------------------------------
+void CBasePanel::DrawBackgroundImage()
+{
+ if ( IsX360() && m_bCopyFrameBuffer )
+ {
+ // force the engine to do an image capture ONCE into this image's render target
+ char filename[MAX_PATH];
+ surface()->DrawGetTextureFile( m_iRenderTargetImageID, filename, sizeof( filename ) );
+ engine->CopyFrameBufferToMaterial( filename );
+ m_bCopyFrameBuffer = false;
+ m_bUseRenderTargetImage = true;
+ }
+
+ int wide, tall;
+ GetSize( wide, tall );
+
+ float frametime = engine->Time();
+
+ // a background transition has a running map underneath it, so fade image out
+ // otherwise, there is no map and the background image stays opaque
+ int alpha = 255;
+ if ( m_bRenderingBackgroundTransition )
+ {
+ // goes from [255..0]
+ alpha = (m_flTransitionEndTime - frametime) / (m_flTransitionEndTime - m_flTransitionStartTime) * 255;
+ alpha = clamp( alpha, 0, 255 );
+ }
+
+ // an exiting process needs to opaquely cover everything
+ if ( m_ExitingFrameCount )
+ {
+ // goes from [0..255]
+ alpha = (m_flTransitionEndTime - frametime) / (m_flTransitionEndTime - m_flTransitionStartTime) * 255;
+ alpha = 255 - clamp( alpha, 0, 255 );
+ }
+
+ int iImageID = m_iBackgroundImageID;
+ if ( IsX360() )
+ {
+ if ( m_ExitingFrameCount )
+ {
+ if ( !m_bRestartSameGame )
+ {
+ iImageID = m_iProductImageID;
+ }
+ }
+ else if ( m_bUseRenderTargetImage )
+ {
+ // the render target image must be opaque, the alpha channel contents are unknown
+ // it is strictly an opaque background image and never used as an overlay
+ iImageID = m_iRenderTargetImageID;
+ alpha = 255;
+ }
+ }
+
+ surface()->DrawSetColor( 255, 255, 255, alpha );
+ surface()->DrawSetTexture( iImageID );
+ surface()->DrawTexturedRect( 0, 0, wide, tall );
+
+ if ( IsX360() && m_ExitingFrameCount )
+ {
+ // Make invisible when going back to appchooser
+ m_pGameMenu->CGameMenu::BaseClass::SetVisible( false );
+
+ IScheme *pScheme = vgui::scheme()->GetIScheme( vgui::scheme()->GetScheme( "SourceScheme" ) );
+ HFont hFont = pScheme->GetFont( "ChapterTitle" );
+ wchar_t *pString = g_pVGuiLocalize->Find( "#GameUI_Loading" );
+ int textWide, textTall;
+ surface()->GetTextSize( hFont, pString, textWide, textTall );
+ surface()->DrawSetTextPos( ( wide - textWide )/2, tall * 0.50f );
+ surface()->DrawSetTextFont( hFont );
+ surface()->DrawSetTextColor( 255, 255, 255, alpha );
+ surface()->DrawPrintText( pString, wcslen( pString ) );
+ }
+
+ // 360 always use the progress bar, TCR Requirement, and never this loading plaque
+ if ( IsPC() && ( m_bRenderingBackgroundTransition || m_eBackgroundState == BACKGROUND_LOADING ) )
+ {
+ // draw the loading image over the top
+ surface()->DrawSetColor(255, 255, 255, alpha);
+ surface()->DrawSetTexture(m_iLoadingImageID);
+ int twide, ttall;
+ surface()->DrawGetTextureSize(m_iLoadingImageID, twide, ttall);
+ surface()->DrawTexturedRect(wide - twide, tall - ttall, wide, tall);
+ }
+
+ // update the menu alpha
+ if ( m_bFadingInMenus )
+ {
+ if ( GameUI().IsConsoleUI() )
+ {
+ m_pConsoleAnimationController->StartAnimationSequence( "OpenMainMenu" );
+ m_bFadingInMenus = false;
+ }
+ else
+ {
+ // goes from [0..255]
+ alpha = (frametime - m_flFadeMenuStartTime) / (m_flFadeMenuEndTime - m_flFadeMenuStartTime) * 255;
+ alpha = clamp( alpha, 0, 255 );
+ m_pGameMenu->SetAlpha( alpha );
+ if ( alpha == 255 )
+ {
+ m_bFadingInMenus = false;
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::CreateGameMenu()
+{
+ // load settings from config file
+ KeyValues *datafile = new KeyValues("GameMenu");
+ datafile->UsesEscapeSequences( true ); // VGUI uses escape sequences
+ if (datafile->LoadFromFile( g_pFullFileSystem, "Resource/GameMenu.res" ) )
+ {
+ m_pGameMenu = RecursiveLoadGameMenu(datafile);
+ }
+
+ if ( !m_pGameMenu )
+ {
+ Error( "Could not load file Resource/GameMenu.res" );
+ }
+ else
+ {
+ // start invisible
+ SETUP_PANEL( m_pGameMenu );
+ m_pGameMenu->SetAlpha( 0 );
+ }
+
+ datafile->deleteThis();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::CreateGameLogo()
+{
+ if ( ModInfo().UseGameLogo() )
+ {
+ m_pGameLogo = new CMainMenuGameLogo( this, "GameLogo" );
+
+ if ( m_pGameLogo )
+ {
+ SETUP_PANEL( m_pGameLogo );
+ m_pGameLogo->InvalidateLayout( true, true );
+
+ // start invisible
+ m_pGameLogo->SetAlpha( 0 );
+ }
+ }
+ else
+ {
+ m_pGameLogo = NULL;
+ }
+}
+
+void CBasePanel::CheckBonusBlinkState()
+{
+#ifdef _X360
+ // On 360 if we have a storage device at this point and try to read the bonus data it can't find the bonus file!
+ return;
+#endif
+
+ if ( BonusMapsDatabase()->GetBlink() )
+ {
+ if ( GameUI().IsConsoleUI() )
+ SetMenuItemBlinkingState( "OpenNewGameDialog", true ); // Consoles integrate bonus maps menu into the new game menu
+ else
+ SetMenuItemBlinkingState( "OpenBonusMapsDialog", true );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Checks to see if menu items need to be enabled/disabled
+//-----------------------------------------------------------------------------
+void CBasePanel::UpdateGameMenus()
+{
+ // check our current state
+ bool isInGame = GameUI().IsInLevel();
+ bool isMulti = isInGame && (engine->GetMaxClients() > 1);
+ bool isInReplay = GameUI().IsInReplay();
+ bool isVREnabled = materials->GetCurrentConfigForVideoCard().m_nVRModeAdapter == materials->GetCurrentAdapter();
+ bool isVRActive = UseVR();
+
+ // iterate all the menu items
+ m_pGameMenu->UpdateMenuItemState( isInGame, isMulti, isInReplay, isVREnabled, isVRActive );
+
+ if ( m_hMainMenuOverridePanel )
+ {
+ vgui::ivgui()->PostMessage( m_hMainMenuOverridePanel, new KeyValues( "UpdateMenu" ), NULL );
+ }
+
+ // position the menu
+ InvalidateLayout();
+ m_pGameMenu->SetVisible( true );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets up the game menu from the keyvalues
+// the game menu is hierarchial, so this is recursive
+//-----------------------------------------------------------------------------
+CGameMenu *CBasePanel::RecursiveLoadGameMenu(KeyValues *datafile)
+{
+ CGameMenu *menu = new CGameMenu(this, datafile->GetName());
+
+ // loop through all the data adding items to the menu
+ for (KeyValues *dat = datafile->GetFirstSubKey(); dat != NULL; dat = dat->GetNextKey())
+ {
+ const char *label = dat->GetString("label", "<unknown>");
+ const char *cmd = dat->GetString("command", NULL);
+ const char *name = dat->GetString("name", label);
+
+ if ( cmd && !Q_stricmp( cmd, "OpenFriendsDialog" ) && bSteamCommunityFriendsVersion )
+ continue;
+
+ menu->AddMenuItem(name, label, cmd, this, dat);
+ }
+
+ return menu;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: update the taskbar a frame
+//-----------------------------------------------------------------------------
+void CBasePanel::RunFrame()
+{
+ InvalidateLayout();
+ vgui::GetAnimationController()->UpdateAnimations( engine->Time() );
+
+ if ( GameUI().IsConsoleUI() )
+ {
+ // run the console ui animations
+ m_pConsoleAnimationController->UpdateAnimations( engine->Time() );
+
+ if ( IsX360() && m_ExitingFrameCount && engine->Time() >= m_flTransitionEndTime )
+ {
+ if ( m_ExitingFrameCount > 1 )
+ {
+ m_ExitingFrameCount--;
+ if ( m_ExitingFrameCount == 1 )
+ {
+ // enough frames have transpired, send the single shot quit command
+ // If we kicked off this event from an invite, we need to properly setup the restart to account for that
+ if ( m_bRestartFromInvite )
+ {
+ engine->ClientCmd_Unrestricted( "quit_x360 invite" );
+ }
+ else if ( m_bRestartSameGame )
+ {
+ engine->ClientCmd_Unrestricted( "quit_x360 restart" );
+ }
+ else
+ {
+ // quits to appchooser
+ engine->ClientCmd_Unrestricted( "quit_x360\n" );
+ }
+ }
+ }
+ }
+ }
+
+ UpdateBackgroundState();
+
+ if ( !m_bPlatformMenuInitialized )
+ {
+ // check to see if the platform is ready to load yet
+ if ( IsX360() || g_VModuleLoader.IsPlatformReady() )
+ {
+ m_bPlatformMenuInitialized = true;
+ }
+ }
+
+ // Check to see if a pending async task has already finished
+ if ( m_pAsyncJob && !m_pAsyncJob->m_hThreadHandle )
+ {
+ m_pAsyncJob->Completed();
+ delete m_pAsyncJob;
+ m_pAsyncJob = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Tells XBox Live our user is in the current game's menu
+//-----------------------------------------------------------------------------
+void CBasePanel::UpdateRichPresenceInfo()
+{
+#if defined( _X360 )
+ // For all other users logged into this console (not primary), set to idle to satisfy cert
+ for( uint i = 0; i < XUSER_MAX_COUNT; ++i )
+ {
+ XUSER_SIGNIN_STATE State = XUserGetSigninState( i );
+
+ if( State != eXUserSigninState_NotSignedIn )
+ {
+ if ( i != XBX_GetPrimaryUserId() )
+ {
+ // Set rich presence as 'idle' for users logged in that can't participate in orange box.
+ if ( !xboxsystem->UserSetContext( i, X_CONTEXT_PRESENCE, CONTEXT_PRESENCE_IDLE, true ) )
+ {
+ Warning( "BasePanel: UserSetContext failed.\n" );
+ }
+ }
+ }
+ }
+
+ if ( !GameUI().IsInLevel() )
+ {
+ if ( !xboxsystem->UserSetContext( XBX_GetPrimaryUserId(), CONTEXT_GAME, m_iGameID, true ) )
+ {
+ Warning( "BasePanel: UserSetContext failed.\n" );
+ }
+ if ( !xboxsystem->UserSetContext( XBX_GetPrimaryUserId(), X_CONTEXT_PRESENCE, CONTEXT_PRESENCE_MENU, true ) )
+ {
+ Warning( "BasePanel: UserSetContext failed.\n" );
+ }
+ if ( m_bSinglePlayer )
+ {
+ if ( !xboxsystem->UserSetContext( XBX_GetPrimaryUserId(), X_CONTEXT_GAME_MODE, CONTEXT_GAME_MODE_SINGLEPLAYER, true ) )
+ {
+ Warning( "BasePanel: UserSetContext failed.\n" );
+ }
+ }
+ }
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Lays out the position of the taskbar
+//-----------------------------------------------------------------------------
+void CBasePanel::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ // Get the screen size
+ int wide, tall;
+ vgui::surface()->GetScreenSize(wide, tall);
+
+ // Get the size of the menu
+ int menuWide, menuTall;
+ m_pGameMenu->GetSize( menuWide, menuTall );
+
+ int idealMenuY = m_iGameMenuPos.y;
+ if ( idealMenuY + menuTall + m_iGameMenuInset > tall )
+ {
+ idealMenuY = tall - menuTall - m_iGameMenuInset;
+ }
+
+ int yDiff = idealMenuY - m_iGameMenuPos.y;
+
+ for ( int i=0; i<m_pGameMenuButtons.Count(); ++i )
+ {
+ // Get the size of the logo text
+ //int textWide, textTall;
+ m_pGameMenuButtons[i]->SizeToContents();
+ //vgui::surface()->GetTextSize( m_pGameMenuButtons[i]->GetFont(), ModInfo().GetGameTitle(), textWide, textTall );
+
+ // place menu buttons above middle of screen
+ m_pGameMenuButtons[i]->SetPos(m_iGameTitlePos[i].x, m_iGameTitlePos[i].y + yDiff);
+ //m_pGameMenuButtons[i]->SetSize(textWide + 4, textTall + 4);
+ }
+
+ if ( m_pGameLogo )
+ {
+ // move the logo to sit right on top of the menu
+ m_pGameLogo->SetPos( m_iGameMenuPos.x + m_pGameLogo->GetOffsetX(), idealMenuY - m_pGameLogo->GetTall() + m_pGameLogo->GetOffsetY() );
+ }
+
+ // position self along middle of screen
+ if ( GameUI().IsConsoleUI() )
+ {
+ int posx, posy;
+ m_pGameMenu->GetPos( posx, posy );
+ m_iGameMenuPos.x = posx;
+ }
+ m_pGameMenu->SetPos(m_iGameMenuPos.x, idealMenuY);
+
+ UpdateGameMenus();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Loads scheme information
+//-----------------------------------------------------------------------------
+void CBasePanel::ApplySchemeSettings(IScheme *pScheme)
+{
+ int i;
+ BaseClass::ApplySchemeSettings(pScheme);
+
+ m_iGameMenuInset = atoi(pScheme->GetResourceString("MainMenu.Inset"));
+ m_iGameMenuInset *= 2;
+
+ IScheme *pClientScheme = vgui::scheme()->GetIScheme( vgui::scheme()->GetScheme( "ClientScheme" ) );
+ CUtlVector< Color > buttonColor;
+ if ( pClientScheme )
+ {
+ m_iGameTitlePos.RemoveAll();
+ for ( i=0; i<m_pGameMenuButtons.Count(); ++i )
+ {
+ m_pGameMenuButtons[i]->SetFont(pClientScheme->GetFont("ClientTitleFont", true));
+ m_iGameTitlePos.AddToTail( coord() );
+ m_iGameTitlePos[i].x = atoi(pClientScheme->GetResourceString( CFmtStr( "Main.Title%d.X", i+1 ) ) );
+ m_iGameTitlePos[i].x = scheme()->GetProportionalScaledValue( m_iGameTitlePos[i].x );
+ m_iGameTitlePos[i].y = atoi(pClientScheme->GetResourceString( CFmtStr( "Main.Title%d.Y", i+1 ) ) );
+ m_iGameTitlePos[i].y = scheme()->GetProportionalScaledValue( m_iGameTitlePos[i].y );
+
+ if ( GameUI().IsConsoleUI() )
+ m_iGameTitlePos[i].x += MAIN_MENU_INDENT_X360;
+
+ buttonColor.AddToTail( pClientScheme->GetColor( CFmtStr( "Main.Title%d.Color", i+1 ), Color(255, 255, 255, 255)) );
+ }
+#ifdef CS_BETA
+ if ( !ModInfo().NoCrosshair() ) // hack to not show the BETA for HL2 or HL1Port
+ {
+ m_pGameMenuButtons[m_pGameMenuButtons.Count()-1]->SetFont(pClientScheme->GetFont("BetaFont", true));
+ }
+#endif // CS_BETA
+
+ m_iGameMenuPos.x = atoi(pClientScheme->GetResourceString("Main.Menu.X"));
+ m_iGameMenuPos.x = scheme()->GetProportionalScaledValue( m_iGameMenuPos.x );
+ m_iGameMenuPos.y = atoi(pClientScheme->GetResourceString("Main.Menu.Y"));
+ m_iGameMenuPos.y = scheme()->GetProportionalScaledValue( m_iGameMenuPos.y );
+
+ m_iGameMenuInset = atoi(pClientScheme->GetResourceString("Main.BottomBorder"));
+ m_iGameMenuInset = scheme()->GetProportionalScaledValue( m_iGameMenuInset );
+ }
+ else
+ {
+ for ( i=0; i<m_pGameMenuButtons.Count(); ++i )
+ {
+ m_pGameMenuButtons[i]->SetFont(pScheme->GetFont("TitleFont"));
+ buttonColor.AddToTail( Color( 255, 255, 255, 255 ) );
+ }
+ }
+
+ for ( i=0; i<m_pGameMenuButtons.Count(); ++i )
+ {
+ m_pGameMenuButtons[i]->SetDefaultColor(buttonColor[i], Color(0, 0, 0, 0));
+ m_pGameMenuButtons[i]->SetArmedColor(buttonColor[i], Color(0, 0, 0, 0));
+ m_pGameMenuButtons[i]->SetDepressedColor(buttonColor[i], Color(0, 0, 0, 0));
+ }
+
+ m_flFrameFadeInTime = atof(pScheme->GetResourceString("Frame.TransitionEffectTime"));
+
+ // work out current focus - find the topmost panel
+ SetBgColor(Color(0, 0, 0, 0));
+
+ m_BackdropColor = pScheme->GetColor("mainmenu.backdrop", Color(0, 0, 0, 128));
+
+ char filename[MAX_PATH];
+ if ( IsX360() )
+ {
+ // 360 uses FullFrameFB1 RT for map to map transitioning
+ if ( m_iRenderTargetImageID == -1 )
+ {
+ m_iRenderTargetImageID = surface()->CreateNewTextureID();
+ surface()->DrawSetTextureFile( m_iRenderTargetImageID, "console/rt_background", false, false );
+ }
+ }
+
+ int screenWide, screenTall;
+ surface()->GetScreenSize( screenWide, screenTall );
+ float aspectRatio = (float)screenWide/(float)screenTall;
+ bool bIsWidescreen = aspectRatio >= 1.5999f;
+
+ // work out which background image to use
+ if ( IsPC() || !IsX360() )
+ {
+ // pc uses blurry backgrounds based on the background level
+ char background[MAX_PATH];
+ engine->GetMainMenuBackgroundName( background, sizeof(background) );
+ Q_snprintf( filename, sizeof( filename ), "console/%s%s", background, ( bIsWidescreen ? "_widescreen" : "" ) );
+ }
+ else
+ {
+ // 360 uses hi-res game specific backgrounds
+ char gameName[MAX_PATH];
+ const char *pGameDir = engine->GetGameDirectory();
+ V_FileBase( pGameDir, gameName, sizeof( gameName ) );
+ V_snprintf( filename, sizeof( filename ), "vgui/appchooser/background_%s%s", gameName, ( bIsWidescreen ? "_widescreen" : "" ) );
+ }
+
+ if ( m_iBackgroundImageID == -1 )
+ {
+ m_iBackgroundImageID = surface()->CreateNewTextureID();
+ }
+ surface()->DrawSetTextureFile( m_iBackgroundImageID, filename, false, false );
+
+ if ( IsX360() )
+ {
+ // 360 uses a product image during application exit
+ V_snprintf( filename, sizeof( filename ), "vgui/appchooser/background_orange%s", ( bIsWidescreen ? "_widescreen" : "" ) );
+
+ if ( m_iProductImageID == -1 )
+ {
+ m_iProductImageID = surface()->CreateNewTextureID();
+ }
+ surface()->DrawSetTextureFile( m_iProductImageID, filename, false, false );
+ }
+
+ if ( IsPC() )
+ {
+ // load the loading icon
+ if ( m_iLoadingImageID == -1 )
+ {
+ m_iLoadingImageID = surface()->CreateNewTextureID();
+ surface()->DrawSetTextureFile( m_iLoadingImageID, "Console/startup_loading", false, false );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: message handler for platform menu; activates the selected module
+//-----------------------------------------------------------------------------
+void CBasePanel::OnActivateModule(int moduleIndex)
+{
+ g_VModuleLoader.ActivateModule(moduleIndex);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Animates menus on gameUI being shown
+//-----------------------------------------------------------------------------
+void CBasePanel::OnGameUIActivated()
+{
+ // If the load failed, we're going to bail out here
+ if ( engine->MapLoadFailed() )
+ {
+ // Don't display this again until it happens again
+ engine->SetMapLoadFailed( false );
+ ShowMessageDialog( MD_LOAD_FAILED_WARNING );
+ }
+
+
+ if ( !m_bEverActivated )
+ {
+ // Layout the first time to avoid focus issues (setting menus visible will grab focus)
+ UpdateGameMenus();
+ m_bEverActivated = true;
+
+#if defined( _X360 )
+
+ // Open all active containers if we have a valid storage device
+ if ( XBX_GetPrimaryUserId() != XBX_INVALID_USER_ID && XBX_GetStorageDeviceId() != XBX_INVALID_STORAGE_ID && XBX_GetStorageDeviceId() != XBX_STORAGE_DECLINED )
+ {
+ // Open user settings and save game container here
+ uint nRet = engine->OnStorageDeviceAttached();
+ if ( nRet != ERROR_SUCCESS )
+ {
+ // Invalidate the device
+ XBX_SetStorageDeviceId( XBX_INVALID_STORAGE_ID );
+
+ // FIXME: We don't know which device failed!
+ // Pop a dialog explaining that the user's data is corrupt
+ BasePanel()->ShowMessageDialog( MD_STORAGE_DEVICES_CORRUPT );
+ }
+ }
+
+ // determine if we're starting up because of a cross-game invite
+ int fLaunchFlags = XboxLaunch()->GetLaunchFlags();
+ if ( fLaunchFlags & LF_INVITERESTART )
+ {
+ XNKID nSessionID;
+ XboxLaunch()->GetInviteSessionID( &nSessionID );
+ matchmaking->JoinInviteSessionByID( nSessionID );
+ }
+#endif
+
+ // Brute force check to open tf matchmaking ui.
+ if ( GameUI().IsConsoleUI() )
+ {
+ const char *pGame = engine->GetGameDirectory();
+ if ( !Q_stricmp( Q_UnqualifiedFileName( pGame ), "tf" ) )
+ {
+ m_bUseMatchmaking = true;
+ RunMenuCommand( "OpenMatchmakingBasePanel" );
+ }
+ }
+ }
+
+ if ( GameUI().IsConsoleUI() )
+ {
+ ArmFirstMenuItem();
+ }
+ if ( GameUI().IsInLevel() )
+ {
+ if ( !m_bUseMatchmaking )
+ {
+ OnCommand( "OpenPauseMenu" );
+ }
+ else
+ {
+ RunMenuCommand( "OpenMatchmakingBasePanel" );
+ }
+
+ if ( m_hAchievementsDialog.Get() )
+ {
+ // Achievement dialog refreshes it's data if the player looks at the pause menu
+ m_hAchievementsDialog->OnCommand( "OnGameUIActivated" );
+ }
+ }
+ else // not the pause menu, update presence
+ {
+ if ( IsX360() )
+ {
+ UpdateRichPresenceInfo();
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: executes a menu command
+//-----------------------------------------------------------------------------
+void CBasePanel::RunMenuCommand(const char *command)
+{
+ if ( !Q_stricmp( command, "OpenGameMenu" ) )
+ {
+ if ( m_pGameMenu )
+ {
+ PostMessage( m_pGameMenu, new KeyValues("Command", "command", "Open") );
+ }
+ }
+ else if ( !Q_stricmp( command, "OpenPlayerListDialog" ) )
+ {
+ OnOpenPlayerListDialog();
+ }
+ else if ( !Q_stricmp( command, "OpenNewGameDialog" ) )
+ {
+ OnOpenNewGameDialog();
+ }
+ else if ( !Q_stricmp( command, "OpenLoadGameDialog" ) )
+ {
+ if ( !GameUI().IsConsoleUI() )
+ {
+ OnOpenLoadGameDialog();
+ }
+ else
+ {
+ OnOpenLoadGameDialog_Xbox();
+ }
+ }
+ else if ( !Q_stricmp( command, "OpenSaveGameDialog" ) )
+ {
+ if ( !GameUI().IsConsoleUI() )
+ {
+ OnOpenSaveGameDialog();
+ }
+ else
+ {
+ OnOpenSaveGameDialog_Xbox();
+ }
+ }
+ else if ( !Q_stricmp( command, "OpenBonusMapsDialog" ) )
+ {
+ OnOpenBonusMapsDialog();
+ }
+ else if ( !Q_stricmp( command, "OpenOptionsDialog" ) )
+ {
+ if ( !GameUI().IsConsoleUI() )
+ {
+ OnOpenOptionsDialog();
+ }
+ else
+ {
+ OnOpenOptionsDialog_Xbox();
+ }
+ }
+ else if ( !Q_stricmp( command, "OpenControllerDialog" ) )
+ {
+ if ( GameUI().IsConsoleUI() )
+ {
+ OnOpenControllerDialog();
+ }
+ }
+ else if ( !Q_stricmp( command, "OpenBenchmarkDialog" ) )
+ {
+ OnOpenBenchmarkDialog();
+ }
+ else if ( !Q_stricmp( command, "OpenServerBrowser" ) )
+ {
+ OnOpenServerBrowser();
+ }
+ else if ( !Q_stricmp( command, "OpenFriendsDialog" ) )
+ {
+ OnOpenFriendsDialog();
+ }
+ else if ( !Q_stricmp( command, "OpenLoadDemoDialog" ) )
+ {
+ OnOpenDemoDialog();
+ }
+ else if ( !Q_stricmp( command, "OpenCreateMultiplayerGameDialog" ) )
+ {
+ OnOpenCreateMultiplayerGameDialog();
+ }
+ else if ( !Q_stricmp( command, "OpenChangeGameDialog" ) )
+ {
+ OnOpenChangeGameDialog();
+ }
+ else if ( !Q_stricmp( command, "OpenLoadCommentaryDialog" ) )
+ {
+ OnOpenLoadCommentaryDialog();
+ }
+ else if ( !Q_stricmp( command, "OpenLoadSingleplayerCommentaryDialog" ) )
+ {
+ OpenLoadSingleplayerCommentaryDialog();
+ }
+ else if ( !Q_stricmp( command, "OpenMatchmakingBasePanel" ) )
+ {
+ OnOpenMatchmakingBasePanel();
+ }
+ else if ( !Q_stricmp( command, "OpenAchievementsDialog" ) )
+ {
+ if ( IsPC() )
+ {
+ if ( !steamapicontext->SteamUser() || !steamapicontext->SteamUser()->BLoggedOn() )
+ {
+ vgui::MessageBox *pMessageBox = new vgui::MessageBox("#GameUI_Achievements_SteamRequired_Title", "#GameUI_Achievements_SteamRequired_Message");
+ pMessageBox->DoModal();
+ return;
+ }
+ OnOpenAchievementsDialog();
+ }
+ else
+ {
+ OnOpenAchievementsDialog_Xbox();
+ }
+ }
+ //=============================================================================
+ // HPE_BEGIN:
+ // [dwenger] Use cs-specific achievements dialog
+ //=============================================================================
+
+ else if ( !Q_stricmp( command, "OpenCSAchievementsDialog" ) )
+ {
+ if ( IsPC() )
+ {
+ if ( !steamapicontext->SteamUser() || !steamapicontext->SteamUser()->BLoggedOn() )
+ {
+ vgui::MessageBox *pMessageBox = new vgui::MessageBox("#GameUI_Achievements_SteamRequired_Title", "#GameUI_Achievements_SteamRequired_Message", this );
+ pMessageBox->DoModal();
+ return;
+ }
+
+ OnOpenCSAchievementsDialog();
+ }
+ }
+ //=============================================================================
+ // HPE_END
+ //=============================================================================
+
+ else if ( !Q_stricmp( command, "AchievementsDialogClosing" ) )
+ {
+ if ( IsX360() )
+ {
+ if ( m_hAchievementsDialog.Get() )
+ {
+ m_hAchievementsDialog->Close();
+ }
+ }
+ }
+ else if ( !Q_stricmp( command, "Quit" ) )
+ {
+ OnOpenQuitConfirmationDialog();
+ }
+ else if ( !Q_stricmp( command, "QuitNoConfirm" ) )
+ {
+ if ( IsX360() )
+ {
+ // start the shutdown process
+ StartExitingProcess();
+ }
+ else
+ {
+ //=============================================================================
+ // HPE_BEGIN:
+ // [dwenger] Shut down achievements panel
+ //=============================================================================
+
+ if ( GameClientExports() )
+ {
+ GameClientExports()->ShutdownAchievementPanel();
+ }
+
+ //=============================================================================
+ // HPE_END
+ //=============================================================================
+
+ // hide everything while we quit
+ SetVisible( false );
+ vgui::surface()->RestrictPaintToSinglePanel( GetVPanel() );
+ engine->ClientCmd_Unrestricted( "quit\n" );
+ }
+ }
+ else if ( !Q_stricmp( command, "QuitRestartNoConfirm" ) )
+ {
+ if ( IsX360() )
+ {
+ // start the shutdown process
+ m_bRestartSameGame = true;
+ StartExitingProcess();
+ }
+ }
+ else if ( !Q_stricmp( command, "ResumeGame" ) )
+ {
+ GameUI().HideGameUI();
+ }
+ else if ( !Q_stricmp( command, "Disconnect" ) )
+ {
+ if ( IsX360() )
+ {
+ OnOpenDisconnectConfirmationDialog();
+ }
+ else
+ {
+ engine->ClientCmd_Unrestricted( "disconnect" );
+ }
+ }
+ else if ( !Q_stricmp( command, "DisconnectNoConfirm" ) )
+ {
+ ConVarRef commentary( "commentary" );
+ if ( commentary.IsValid() && commentary.GetBool() )
+ {
+ engine->ClientCmd_Unrestricted( "disconnect" );
+
+ CMatchmakingBasePanel *pBase = GetMatchmakingBasePanel();
+ if ( pBase )
+ {
+ pBase->CloseAllDialogs( false );
+ pBase->OnCommand( "OpenWelcomeDialog" );
+ }
+ }
+ else
+ {
+ // Leave our current session, if we have one
+ matchmaking->KickPlayerFromSession( 0 );
+ }
+ }
+ else if ( !Q_stricmp( command, "ReleaseModalWindow" ) )
+ {
+ vgui::surface()->RestrictPaintToSinglePanel(NULL);
+ }
+ else if ( Q_stristr( command, "engine " ) )
+ {
+ const char *engineCMD = strstr( command, "engine " ) + strlen( "engine " );
+ if ( strlen( engineCMD ) > 0 )
+ {
+ engine->ClientCmd_Unrestricted( const_cast<char *>( engineCMD ) );
+ }
+ }
+ else if ( !Q_stricmp( command, "ShowSigninUI" ) )
+ {
+ m_bWaitingForUserSignIn = true;
+ xboxsystem->ShowSigninUI( 1, 0 ); // One user, no special flags
+ }
+ else if ( !Q_stricmp( command, "ShowDeviceSelector" ) )
+ {
+ OnChangeStorageDevice();
+ }
+ else if ( !Q_stricmp( command, "SignInDenied" ) )
+ {
+ // The user doesn't care, so re-send the command they wanted and mark that we want to skip checking
+ m_bUserRefusedSignIn = true;
+ if ( m_strPostPromptCommand.IsEmpty() == false )
+ {
+ OnCommand( m_strPostPromptCommand );
+ }
+ }
+ else if ( !Q_stricmp( command, "RequiredSignInDenied" ) )
+ {
+ m_strPostPromptCommand = "";
+ }
+ else if ( !Q_stricmp( command, "RequiredStorageDenied" ) )
+ {
+ m_strPostPromptCommand = "";
+ }
+ else if ( !Q_stricmp( command, "StorageDeviceDenied" ) )
+ {
+ // The user doesn't care, so re-send the command they wanted and mark that we want to skip checking
+ m_bUserRefusedStorageDevice = true;
+ IssuePostPromptCommand();
+
+ // Set us as declined
+ XBX_SetStorageDeviceId( XBX_STORAGE_DECLINED );
+ m_iStorageID = XBX_INVALID_STORAGE_ID;
+
+ if ( m_pStorageDeviceValidatedNotify )
+ {
+ *m_pStorageDeviceValidatedNotify = 2;
+ m_pStorageDeviceValidatedNotify = NULL;
+ }
+ }
+ else if ( !Q_stricmp( command, "clear_storage_deviceID" ) )
+ {
+ XBX_SetStorageDeviceId( XBX_STORAGE_DECLINED );
+ }
+ else if ( !Q_stricmp( command, "RestartWithNewLanguage" ) )
+ {
+ if ( !IsX360() )
+ {
+ char szSteamURL[50];
+
+ // hide everything while we quit
+ SetVisible( false );
+ vgui::surface()->RestrictPaintToSinglePanel( GetVPanel() );
+ engine->ClientCmd_Unrestricted( "quit\n" );
+
+ // Construct Steam URL. Pattern is steam://run/<appid>/<language>. (e.g. Ep1 In French ==> steam://run/380/french)
+ V_snprintf( szSteamURL, sizeof(szSteamURL), "steam://run/%d/%s", engine->GetAppID(), COptionsSubAudio::GetUpdatedAudioLanguage() );
+
+ // Set Steam URL for re-launch in registry. Launcher will check this registry key and exec it in order to re-load the game in the proper language
+#if defined( WIN32 ) && !defined( _X360 )
+ HKEY hKey;
+
+ if ( IsPC() && RegOpenKeyEx( HKEY_CURRENT_USER, "Software\\Valve\\Source", NULL, KEY_WRITE, &hKey) == ERROR_SUCCESS )
+ {
+ RegSetValueEx( hKey, "Relaunch URL", 0, REG_SZ, (const unsigned char *)szSteamURL, sizeof( szSteamURL ) );
+
+ RegCloseKey(hKey);
+ }
+#elif defined( OSX ) || defined( LINUX )
+ FILE *fp = fopen( "/tmp/hl2_relaunch", "w+" );
+ if ( fp )
+ {
+ fprintf( fp, "%s\n", szSteamURL );
+ }
+ fclose( fp );
+#elif defined( _X360 )
+#else
+#error
+#endif
+ }
+ }
+ else
+ {
+ BaseClass::OnCommand( command);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Queue a command to be run when XUI Closes
+//-----------------------------------------------------------------------------
+void CBasePanel::QueueCommand( const char *pCommand )
+{
+ if ( m_bXUIVisible )
+ {
+ m_CommandQueue.AddToTail( CUtlString( pCommand ) );
+ }
+ else
+ {
+ OnCommand( pCommand );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Run all the commands in the queue
+//-----------------------------------------------------------------------------
+void CBasePanel::RunQueuedCommands()
+{
+ for ( int i = 0; i < m_CommandQueue.Count(); ++i )
+ {
+ OnCommand( m_CommandQueue[i] );
+ }
+ ClearQueuedCommands();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Clear all queued commands
+//-----------------------------------------------------------------------------
+void CBasePanel::ClearQueuedCommands()
+{
+ m_CommandQueue.Purge();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Whether this command should cause us to prompt the user if they're not signed in and do not have a storage device
+//-----------------------------------------------------------------------------
+bool CBasePanel::IsPromptableCommand( const char *command )
+{
+ // Blech!
+ if ( !Q_stricmp( command, "OpenNewGameDialog" ) ||
+ !Q_stricmp( command, "OpenLoadGameDialog" ) ||
+ !Q_stricmp( command, "OpenSaveGameDialog" ) ||
+ !Q_stricmp( command, "OpenBonusMapsDialog" ) ||
+ !Q_stricmp( command, "OpenOptionsDialog" ) ||
+ !Q_stricmp( command, "OpenControllerDialog" ) ||
+ !Q_stricmp( command, "OpenLoadCommentaryDialog" ) ||
+ !Q_stricmp( command, "OpenLoadSingleplayerCommentaryDialog" ) ||
+ !Q_stricmp( command, "OpenAchievementsDialog" ) ||
+
+ //=============================================================================
+ // HPE_BEGIN:
+ // [dwenger] Use cs-specific achievements dialog
+ //=============================================================================
+
+ !Q_stricmp( command, "OpenCSAchievementsDialog" ) )
+
+ //=============================================================================
+ // HPE_END
+ //=============================================================================
+
+ {
+ return true;
+ }
+
+ return false;
+}
+
+#ifdef _WIN32
+//-------------------------
+// Purpose: Job wrapper
+//-------------------------
+static unsigned PanelJobWrapperFn( void *pvContext )
+{
+ CBasePanel::CAsyncJobContext *pAsync = reinterpret_cast< CBasePanel::CAsyncJobContext * >( pvContext );
+
+ float const flTimeStart = Plat_FloatTime();
+
+ pAsync->ExecuteAsync();
+
+ float const flElapsedTime = Plat_FloatTime() - flTimeStart;
+
+ if ( flElapsedTime < pAsync->m_flLeastExecuteTime )
+ {
+ ThreadSleep( ( pAsync->m_flLeastExecuteTime - flElapsedTime ) * 1000 );
+ }
+
+ ReleaseThreadHandle( ( ThreadHandle_t ) pAsync->m_hThreadHandle );
+ pAsync->m_hThreadHandle = NULL;
+
+ return 0;
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// Purpose: Enqueues a job function to be called on a separate thread
+//-----------------------------------------------------------------------------
+void CBasePanel::ExecuteAsync( CAsyncJobContext *pAsync )
+{
+ Assert( !m_pAsyncJob );
+ Assert( pAsync && !pAsync->m_hThreadHandle );
+ m_pAsyncJob = pAsync;
+
+#ifdef _WIN32
+ ThreadHandle_t hHandle = CreateSimpleThread( PanelJobWrapperFn, reinterpret_cast< void * >( pAsync ) );
+ pAsync->m_hThreadHandle = hHandle;
+
+#ifdef _X360
+ ThreadSetAffinity( hHandle, XBOX_PROCESSOR_3 );
+#endif
+
+#else
+ pAsync->ExecuteAsync();
+#endif
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Whether this command requires the user be signed in
+//-----------------------------------------------------------------------------
+bool CBasePanel::CommandRequiresSignIn( const char *command )
+{
+ // Blech again!
+ if ( !Q_stricmp( command, "OpenAchievementsDialog" ) ||
+
+ //=============================================================================
+ // HPE_BEGIN:
+ // [dwenger] Use cs-specific achievements dialog
+ //=============================================================================
+
+ !Q_stricmp( command, "OpenCSAchievementsDialog" ) ||
+
+ //=============================================================================
+ // HPE_END
+ //=============================================================================
+
+ !Q_stricmp( command, "OpenLoadGameDialog" ) ||
+ !Q_stricmp( command, "OpenSaveGameDialog" ) ||
+ !Q_stricmp( command, "OpenRankingsDialog" ) )
+ return true;
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Whether the command requires the user to have a valid storage device
+//-----------------------------------------------------------------------------
+bool CBasePanel::CommandRequiresStorageDevice( const char *command )
+{
+ // Anything which touches the storage device must prompt
+ if ( !Q_stricmp( command, "OpenSaveGameDialog" ) ||
+ !Q_stricmp( command, "OpenLoadGameDialog" ) )
+ return true;
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Whether the command requires the user to have a valid profile selected
+//-----------------------------------------------------------------------------
+bool CBasePanel::CommandRespectsSignInDenied( const char *command )
+{
+ // Anything which touches the user profile must prompt
+ if ( !Q_stricmp( command, "OpenOptionsDialog" ) ||
+ !Q_stricmp( command, "OpenControllerDialog" ) )
+ return true;
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: A storage device has been connected, update our settings and anything else
+//-----------------------------------------------------------------------------
+
+class CAsyncCtxOnDeviceAttached : public CBasePanel::CAsyncJobContext
+{
+public:
+ CAsyncCtxOnDeviceAttached();
+ ~CAsyncCtxOnDeviceAttached();
+ virtual void ExecuteAsync();
+ virtual void Completed();
+ uint GetContainerOpenResult( void ) { return m_ContainerOpenResult; }
+
+private:
+ uint m_ContainerOpenResult;
+};
+
+CAsyncCtxOnDeviceAttached::CAsyncCtxOnDeviceAttached() :
+ CBasePanel::CAsyncJobContext( 3.0f ), // Storage device info for at least 3 seconds
+ m_ContainerOpenResult( ERROR_SUCCESS )
+{
+ BasePanel()->ShowMessageDialog( MD_CHECKING_STORAGE_DEVICE );
+}
+
+CAsyncCtxOnDeviceAttached::~CAsyncCtxOnDeviceAttached()
+{
+ BasePanel()->CloseMessageDialog( 0 );
+}
+
+void CAsyncCtxOnDeviceAttached::ExecuteAsync()
+{
+ // Asynchronously do the tasks that don't interact with the command buffer
+
+ // Open user settings and save game container here
+ m_ContainerOpenResult = engine->OnStorageDeviceAttached();
+ if ( m_ContainerOpenResult != ERROR_SUCCESS )
+ return;
+
+ // Make the QOS system initialized for multiplayer games
+ if ( !ModInfo().IsSinglePlayerOnly() )
+ {
+#if defined( _X360 )
+ ( void ) matchmaking->GetQosWithLIVE();
+#endif
+ }
+}
+
+void CAsyncCtxOnDeviceAttached::Completed()
+{
+ BasePanel()->OnCompletedAsyncDeviceAttached( this );
+}
+
+
+void CBasePanel::OnDeviceAttached( void )
+{
+ ExecuteAsync( new CAsyncCtxOnDeviceAttached );
+}
+
+void CBasePanel::OnCompletedAsyncDeviceAttached( CAsyncCtxOnDeviceAttached *job )
+{
+ uint nRet = job->GetContainerOpenResult();
+ if ( nRet != ERROR_SUCCESS )
+ {
+ // Invalidate the device
+ XBX_SetStorageDeviceId( XBX_INVALID_STORAGE_ID );
+
+ // FIXME: We don't know which device failed!
+ // Pop a dialog explaining that the user's data is corrupt
+ BasePanel()->ShowMessageDialog( MD_STORAGE_DEVICES_CORRUPT );
+ }
+
+ // First part of the device checking completed asynchronously,
+ // perform the rest of duties that require to run on main thread.
+ engine->ReadConfiguration();
+ engine->ExecuteClientCmd( "refreshplayerstats" );
+
+ BonusMapsDatabase()->ReadBonusMapSaveData();
+
+ if ( m_hSaveGameDialog_Xbox.Get() )
+ {
+ m_hSaveGameDialog_Xbox->OnCommand( "RefreshSaveGames" );
+ }
+ if ( m_hLoadGameDialog_Xbox.Get() )
+ {
+ m_hLoadGameDialog_Xbox->OnCommand( "RefreshSaveGames" );
+ }
+ if ( m_hOptionsDialog_Xbox.Get() )
+ {
+ m_hOptionsDialog_Xbox->OnCommand( "RefreshOptions" );
+ }
+ if ( m_pStorageDeviceValidatedNotify )
+ {
+ *m_pStorageDeviceValidatedNotify = 1;
+ m_pStorageDeviceValidatedNotify = NULL;
+ }
+
+ // Finish their command
+ IssuePostPromptCommand();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: FIXME: Only TF takes this path...
+//-----------------------------------------------------------------------------
+bool CBasePanel::ValidateStorageDevice( void )
+{
+ if ( m_bUserRefusedStorageDevice == false )
+ {
+#if defined( _X360 )
+ if ( XBX_GetStorageDeviceId() == XBX_INVALID_STORAGE_ID )
+ {
+ // Try to discover content on the user's storage devices
+ DWORD nFoundDevice = xboxsystem->DiscoverUserData( XBX_GetPrimaryUserId(), COM_GetModDirectory() );
+ if ( nFoundDevice == XBX_INVALID_STORAGE_ID )
+ {
+ // They don't have a device, so ask for one
+ ShowMessageDialog( MD_PROMPT_STORAGE_DEVICE );
+ return false;
+ }
+ else
+ {
+ // Take this device
+ XBX_SetStorageDeviceId( nFoundDevice );
+ OnDeviceAttached();
+ }
+ // Fall through
+ }
+#endif
+ }
+ return true;
+}
+
+bool CBasePanel::ValidateStorageDevice( int *pStorageDeviceValidated )
+{
+ if ( m_pStorageDeviceValidatedNotify )
+ {
+ if ( pStorageDeviceValidated != m_pStorageDeviceValidatedNotify )
+ {
+ *m_pStorageDeviceValidatedNotify = -1;
+ m_pStorageDeviceValidatedNotify = NULL;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ if ( pStorageDeviceValidated )
+ {
+ if ( HandleStorageDeviceRequest( "" ) )
+ return true;
+
+ m_pStorageDeviceValidatedNotify = pStorageDeviceValidated;
+ return false;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Monitor commands for certain necessary cases
+// Input : *command - What menu command we're policing
+//-----------------------------------------------------------------------------
+bool CBasePanel::HandleSignInRequest( const char *command )
+{
+#ifdef _X360
+ // If we have a post-prompt command, we're coming back into the call from that prompt
+ bool bQueuedCall = ( m_strPostPromptCommand.IsEmpty() == false );
+
+ XUSER_SIGNIN_INFO info;
+ bool bValidUser = ( XUserGetSigninInfo( XBX_GetPrimaryUserId(), 0, &info ) == ERROR_SUCCESS );
+
+ if ( bValidUser )
+ return true;
+
+ // Queued command means we're returning from a prompt or blade
+ if ( bQueuedCall )
+ {
+ // Blade has returned with nothing
+ if ( m_bUserRefusedSignIn )
+ return true;
+
+ // User has not denied the storage device, so ask
+ ShowMessageDialog( MD_PROMPT_SIGNIN );
+ m_strPostPromptCommand = command;
+
+ // Do not run command
+ return false;
+ }
+ else
+ {
+ // If the user refused the sign-in and we respect that on this command, we're done
+ if ( m_bUserRefusedSignIn && CommandRespectsSignInDenied( command ) )
+ return true;
+
+ // If the message is required first, then do that instead
+ if ( CommandRequiresSignIn( command ) )
+ {
+ ShowMessageDialog( MD_PROMPT_SIGNIN_REQUIRED );
+ m_strPostPromptCommand = command;
+ return false;
+ }
+
+ // Pop a blade out
+ xboxsystem->ShowSigninUI( 1, 0 );
+ m_strPostPromptCommand = command;
+ m_bWaitingForUserSignIn = true;
+ m_bUserRefusedSignIn = false;
+ return false;
+ }
+#endif // _X360
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *command -
+//-----------------------------------------------------------------------------
+bool CBasePanel::HandleStorageDeviceRequest( const char *command )
+{
+ // If we don't have a valid sign-in, then we do nothing!
+ if ( m_bUserRefusedSignIn )
+ return true;
+
+ // If we have a valid storage device, there's nothing to prompt for
+ if ( XBX_GetStorageDeviceId() != XBX_INVALID_STORAGE_ID && XBX_GetStorageDeviceId() != XBX_STORAGE_DECLINED )
+ return true;
+
+ // If we have a post-prompt command, we're coming back into the call from that prompt
+ bool bQueuedCall = ( m_strPostPromptCommand.IsEmpty() == false );
+
+ // Are we returning from a prompt?
+ if ( bQueuedCall && m_bStorageBladeShown )
+ {
+ // User has declined
+ if ( m_bUserRefusedStorageDevice )
+ return true;
+
+ // Prompt them
+ ShowMessageDialog( MD_PROMPT_STORAGE_DEVICE );
+ m_strPostPromptCommand = command;
+
+ // Do not run the command
+ return false;
+ }
+ else
+ {
+ // If the user refused the sign-in and we respect that on this command, we're done
+ if ( m_bUserRefusedStorageDevice && CommandRespectsSignInDenied( command ) )
+ return true;
+
+#if 0 // This attempts to find user data, but may not be cert-worthy even though it's a bit nicer for the user
+ // Attempt to automatically find a device
+ DWORD nFoundDevice = xboxsystem->DiscoverUserData( XBX_GetPrimaryUserId(), COM_GetModDirectory() );
+ if ( nFoundDevice != XBX_INVALID_STORAGE_ID )
+ {
+ // Take this device
+ XBX_SetStorageDeviceId( nFoundDevice );
+ OnDeviceAttached();
+ return true;
+ }
+#endif //
+
+ // If the message is required first, then do that instead
+ if ( CommandRequiresStorageDevice( command ) )
+ {
+ ShowMessageDialog( MD_PROMPT_STORAGE_DEVICE_REQUIRED );
+ m_strPostPromptCommand = command;
+ return false;
+ }
+
+ // This is a misnomer of the first order!
+ OnChangeStorageDevice();
+ m_strPostPromptCommand = command;
+ m_bStorageBladeShown = true;
+ m_bUserRefusedStorageDevice = false;
+ return false;
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Clear the command we've queued once it has succeeded in being called
+//-----------------------------------------------------------------------------
+void CBasePanel::ClearPostPromptCommand( const char *pCompletedCommand )
+{
+ if ( !Q_stricmp( m_strPostPromptCommand, pCompletedCommand ) )
+ {
+ // All commands are executed, so stop holding this
+ m_strPostPromptCommand = "";
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Issue our queued command to either the base panel or the matchmaking panel
+//-----------------------------------------------------------------------------
+void CBasePanel::IssuePostPromptCommand( void )
+{
+ // The device is valid, so launch any pending commands
+ if ( m_strPostPromptCommand.IsEmpty() == false )
+ {
+ if ( m_bSinglePlayer )
+ {
+ OnCommand( m_strPostPromptCommand );
+ }
+ else
+ {
+ CMatchmakingBasePanel *pMatchMaker = GetMatchmakingBasePanel();
+ if ( pMatchMaker )
+ {
+ pMatchMaker->OnCommand( m_strPostPromptCommand );
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: message handler for menu selections
+//-----------------------------------------------------------------------------
+void CBasePanel::OnCommand( const char *command )
+{
+ if ( GameUI().IsConsoleUI() )
+ {
+#if defined( _X360 )
+
+ // See if this is a command we need to intercept
+ if ( IsPromptableCommand( command ) )
+ {
+ // Handle the sign in case
+ if ( HandleSignInRequest( command ) == false )
+ return;
+
+ // Handle storage
+ if ( HandleStorageDeviceRequest( command ) == false )
+ return;
+
+ // If we fall through, we'll need to track this again
+ m_bStorageBladeShown = false;
+
+ // Fall through
+ }
+#endif // _X360
+
+ RunAnimationWithCallback( this, command, new KeyValues( "RunMenuCommand", "command", command ) );
+
+ // Clear our pending command if we just executed it
+ ClearPostPromptCommand( command );
+ }
+ else
+ {
+ RunMenuCommand( command );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: runs an animation sequence, then calls a message mapped function
+// when the animation is complete.
+//-----------------------------------------------------------------------------
+void CBasePanel::RunAnimationWithCallback( vgui::Panel *parent, const char *animName, KeyValues *msgFunc )
+{
+ if ( !m_pConsoleAnimationController )
+ return;
+
+ m_pConsoleAnimationController->StartAnimationSequence( animName );
+ float sequenceLength = m_pConsoleAnimationController->GetAnimationSequenceLength( animName );
+ if ( sequenceLength )
+ {
+ sequenceLength += g_flAnimationPadding;
+ }
+ if ( parent && msgFunc )
+ {
+ PostMessage( parent, msgFunc, sequenceLength );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: trinary choice query "save & quit", "quit", "cancel"
+//-----------------------------------------------------------------------------
+class CSaveBeforeQuitQueryDialog : public vgui::Frame
+{
+ DECLARE_CLASS_SIMPLE( CSaveBeforeQuitQueryDialog, vgui::Frame );
+public:
+ CSaveBeforeQuitQueryDialog(vgui::Panel *parent, const char *name) : BaseClass(parent, name)
+ {
+ LoadControlSettings("resource/SaveBeforeQuitDialog.res");
+ SetDeleteSelfOnClose(true);
+ SetSizeable(false);
+ }
+
+ void DoModal()
+ {
+ BaseClass::Activate();
+ input()->SetAppModalSurface(GetVPanel());
+ MoveToCenterOfScreen();
+ vgui::surface()->RestrictPaintToSinglePanel(GetVPanel());
+
+ GameUI().PreventEngineHideGameUI();
+ }
+
+ void OnKeyCodeTyped(KeyCode code)
+ {
+ // ESC cancels
+ if ( code == KEY_ESCAPE )
+ {
+ Close();
+ }
+ else
+ {
+ BaseClass::OnKeyCodeTyped(code);
+ }
+ }
+
+ void OnKeyCodePressed(KeyCode code)
+ {
+ // ESC cancels
+ if ( code == KEY_XBUTTON_B || code == STEAMCONTROLLER_B || code == STEAMCONTROLLER_START )
+ {
+ Close();
+ }
+ else if ( code == KEY_XBUTTON_A || code == STEAMCONTROLLER_A )
+ {
+ OnCommand( "SaveAndQuit" );
+ }
+ else if ( code == KEY_XBUTTON_X || code == STEAMCONTROLLER_X )
+ {
+ OnCommand( "Quit" );
+ }
+ else
+ {
+ BaseClass::OnKeyCodePressed(code);
+ }
+ }
+
+ virtual void OnCommand(const char *command)
+ {
+ if (!Q_stricmp(command, "Quit"))
+ {
+ PostMessage(GetVParent(), new KeyValues("Command", "command", "QuitNoConfirm"));
+ }
+ else if (!Q_stricmp(command, "SaveAndQuit"))
+ {
+ // find a new name to save
+ char saveName[128];
+ CSaveGameDialog::FindSaveSlot( saveName, sizeof(saveName) );
+ if ( saveName[ 0 ] )
+ {
+ // save the game
+ char sz[ 256 ];
+ Q_snprintf(sz, sizeof( sz ), "save %s\n", saveName );
+ engine->ClientCmd_Unrestricted( sz );
+ }
+
+ // quit
+ PostMessage(GetVParent(), new KeyValues("Command", "command", "QuitNoConfirm"));
+ }
+ else if (!Q_stricmp(command, "Cancel"))
+ {
+ Close();
+ }
+ else
+ {
+ BaseClass::OnCommand(command);
+ }
+ }
+
+ virtual void OnClose()
+ {
+ BaseClass::OnClose();
+ vgui::surface()->RestrictPaintToSinglePanel(NULL);
+ GameUI().AllowEngineHideGameUI();
+ }
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: simple querybox that accepts escape
+//-----------------------------------------------------------------------------
+class CQuitQueryBox : public vgui::QueryBox
+{
+ DECLARE_CLASS_SIMPLE( CQuitQueryBox, vgui::QueryBox );
+public:
+ CQuitQueryBox(const char *title, const char *info, Panel *parent) : BaseClass( title, info, parent )
+ {
+ }
+
+ void DoModal( Frame* pFrameOver )
+ {
+ BaseClass::DoModal( pFrameOver );
+ vgui::surface()->RestrictPaintToSinglePanel(GetVPanel());
+ GameUI().PreventEngineHideGameUI();
+ }
+
+ void OnKeyCodeTyped(KeyCode code)
+ {
+ // ESC cancels
+ if (code == KEY_ESCAPE)
+ {
+ Close();
+ }
+ else
+ {
+ BaseClass::OnKeyCodeTyped(code);
+ }
+ }
+
+ void OnKeyCodePressed(KeyCode code)
+ {
+ // ESC cancels
+ if (code == KEY_XBUTTON_B || code == STEAMCONTROLLER_B)
+ {
+ Close();
+ }
+ else
+ {
+ BaseClass::OnKeyCodePressed(code);
+ }
+ }
+
+ virtual void OnClose()
+ {
+ BaseClass::OnClose();
+ vgui::surface()->RestrictPaintToSinglePanel(NULL);
+ GameUI().AllowEngineHideGameUI();
+ }
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: asks user how they feel about quiting
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenQuitConfirmationDialog()
+{
+ if ( GameUI().IsConsoleUI() )
+ {
+ if ( !GameUI().HasSavedThisMenuSession() && GameUI().IsInLevel() && engine->GetMaxClients() == 1 )
+ {
+ // single player, progress will be lost...
+ ShowMessageDialog( MD_SAVE_BEFORE_QUIT );
+ }
+ else
+ {
+ if ( m_bUseMatchmaking )
+ {
+ ShowMessageDialog( MD_QUIT_CONFIRMATION_TF );
+ }
+ else
+ {
+ ShowMessageDialog( MD_QUIT_CONFIRMATION );
+ }
+ }
+ return;
+ }
+
+
+ if ( GameUI().IsInLevel() && engine->GetMaxClients() == 1 )
+ {
+ // prompt for saving current game before quiting
+ CSaveBeforeQuitQueryDialog *box = new CSaveBeforeQuitQueryDialog(this, "SaveBeforeQuitQueryDialog");
+ box->DoModal();
+ }
+ else
+ {
+ // simple ok/cancel prompt
+ QueryBox *box = new CQuitQueryBox("#GameUI_QuitConfirmationTitle", "#GameUI_QuitConfirmationText", this);
+ box->SetOKButtonText("#GameUI_Quit");
+ box->SetOKCommand(new KeyValues("Command", "command", "QuitNoConfirm"));
+ box->SetCancelCommand(new KeyValues("Command", "command", "ReleaseModalWindow"));
+ box->AddActionSignalTarget(this);
+ box->DoModal();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: asks user how they feel about disconnecting
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenDisconnectConfirmationDialog()
+{
+ // THis is for disconnecting from a multiplayer server
+ Assert( m_bUseMatchmaking );
+ Assert( IsX360() );
+
+ if ( GameUI().IsConsoleUI() && GameUI().IsInLevel() )
+ {
+ if ( engine->GetLocalPlayer() == 1 )
+ {
+ ShowMessageDialog( MD_DISCONNECT_CONFIRMATION_HOST );
+ }
+ else
+ {
+ ShowMessageDialog( MD_DISCONNECT_CONFIRMATION );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenNewGameDialog(const char *chapter )
+{
+ if ( !m_hNewGameDialog.Get() )
+ {
+ m_hNewGameDialog = new CNewGameDialog(this, false);
+ PositionDialog( m_hNewGameDialog );
+ }
+
+ if ( chapter )
+ {
+ ((CNewGameDialog *)m_hNewGameDialog.Get())->SetSelectedChapter(chapter);
+ }
+
+ ((CNewGameDialog *)m_hNewGameDialog.Get())->SetCommentaryMode( false );
+ m_hNewGameDialog->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenBonusMapsDialog( void )
+{
+ if ( !m_hBonusMapsDialog.Get() )
+ {
+ m_hBonusMapsDialog = new CBonusMapsDialog(this);
+ PositionDialog( m_hBonusMapsDialog );
+ }
+
+ m_hBonusMapsDialog->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenLoadGameDialog()
+{
+ if ( !m_hLoadGameDialog.Get() )
+ {
+ m_hLoadGameDialog = new CLoadGameDialog(this);
+ PositionDialog( m_hLoadGameDialog );
+ }
+ m_hLoadGameDialog->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenLoadGameDialog_Xbox()
+{
+ if ( !m_hLoadGameDialog_Xbox.Get() )
+ {
+ m_hLoadGameDialog_Xbox = new CLoadGameDialogXbox(this);
+ PositionDialog( m_hLoadGameDialog_Xbox );
+ }
+ m_hLoadGameDialog_Xbox->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenSaveGameDialog()
+{
+ if ( !m_hSaveGameDialog.Get() )
+ {
+ m_hSaveGameDialog = new CSaveGameDialog(this);
+ PositionDialog( m_hSaveGameDialog );
+ }
+ m_hSaveGameDialog->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenSaveGameDialog_Xbox()
+{
+ if ( !m_hSaveGameDialog_Xbox.Get() )
+ {
+ m_hSaveGameDialog_Xbox = new CSaveGameDialogXbox(this);
+ PositionDialog( m_hSaveGameDialog_Xbox );
+ }
+ m_hSaveGameDialog_Xbox->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenOptionsDialog()
+{
+ if ( !m_hOptionsDialog.Get() )
+ {
+ m_hOptionsDialog = new COptionsDialog(this);
+ g_hOptionsDialog = m_hOptionsDialog;
+ PositionDialog( m_hOptionsDialog );
+ }
+
+ m_hOptionsDialog->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenOptionsDialog_Xbox()
+{
+ if ( !m_hOptionsDialog_Xbox.Get() )
+ {
+ m_hOptionsDialog_Xbox = new COptionsDialogXbox( this );
+ PositionDialog( m_hOptionsDialog_Xbox );
+ }
+
+ m_hOptionsDialog_Xbox->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: forces any changed options dialog settings to be applied immediately, if it's open
+//-----------------------------------------------------------------------------
+void CBasePanel::ApplyOptionsDialogSettings()
+{
+ if (m_hOptionsDialog.Get())
+ {
+ m_hOptionsDialog->ApplyChanges();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenControllerDialog()
+{
+ if ( !m_hControllerDialog.Get() )
+ {
+ m_hControllerDialog = new CControllerDialog( this );
+ PositionDialog( m_hControllerDialog );
+ }
+
+ m_hControllerDialog->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenBenchmarkDialog()
+{
+ if (!m_hBenchmarkDialog.Get())
+ {
+ m_hBenchmarkDialog = new CBenchmarkDialog(this, "BenchmarkDialog");
+ PositionDialog( m_hBenchmarkDialog );
+ }
+ m_hBenchmarkDialog->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenServerBrowser()
+{
+ g_VModuleLoader.ActivateModule("Servers");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenFriendsDialog()
+{
+ g_VModuleLoader.ActivateModule("Friends");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenDemoDialog()
+{
+/* if ( !m_hDemoPlayerDialog.Get() )
+ {
+ m_hDemoPlayerDialog = new CDemoPlayerDialog(this);
+ PositionDialog( m_hDemoPlayerDialog );
+ }
+ m_hDemoPlayerDialog->Activate();*/
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenCreateMultiplayerGameDialog()
+{
+ if (!m_hCreateMultiplayerGameDialog.Get())
+ {
+ m_hCreateMultiplayerGameDialog = new CCreateMultiplayerGameDialog(this);
+ PositionDialog(m_hCreateMultiplayerGameDialog);
+ }
+ m_hCreateMultiplayerGameDialog->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenChangeGameDialog()
+{
+#ifdef POSIX
+ // Alfred says this is old legacy code that allowed you to walk through looking for
+ // gameinfos and switch and it's not needed anymore. So I'm killing this assert...
+#else
+ if (!m_hChangeGameDialog.Get())
+ {
+ m_hChangeGameDialog = new CChangeGameDialog(this);
+ PositionDialog(m_hChangeGameDialog);
+ }
+ m_hChangeGameDialog->Activate();
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenPlayerListDialog()
+{
+ if (!m_hPlayerListDialog.Get())
+ {
+ m_hPlayerListDialog = new CPlayerListDialog(this);
+ PositionDialog(m_hPlayerListDialog);
+ }
+ m_hPlayerListDialog->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenLoadCommentaryDialog()
+{
+ if (!m_hPlayerListDialog.Get())
+ {
+ m_hLoadCommentaryDialog = new CLoadCommentaryDialog(this);
+ PositionDialog(m_hLoadCommentaryDialog);
+ }
+ m_hLoadCommentaryDialog->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OpenLoadSingleplayerCommentaryDialog()
+{
+ if ( !m_hNewGameDialog.Get() )
+ {
+ m_hNewGameDialog = new CNewGameDialog(this,true);
+ PositionDialog( m_hNewGameDialog );
+ }
+
+ ((CNewGameDialog *)m_hNewGameDialog.Get())->SetCommentaryMode( true );
+ m_hNewGameDialog->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenAchievementsDialog()
+{
+ if (!m_hAchievementsDialog.Get())
+ {
+ m_hAchievementsDialog = new CAchievementsDialog( this );
+ PositionDialog(m_hAchievementsDialog);
+ }
+ m_hAchievementsDialog->Activate();
+}
+
+//=============================================================================
+// HPE_BEGIN:
+// [dwenger] Use cs-specific achievements dialog
+//=============================================================================
+
+void CBasePanel::OnOpenCSAchievementsDialog()
+{
+ if ( GameClientExports() )
+ {
+ int screenWide = 0;
+ int screenHeight = 0;
+ engine->GetScreenSize( screenWide, screenHeight );
+
+ // [smessick] For lower resolutions, open the Steam achievements instead of the CSS achievements screen.
+ if ( screenWide < GameClientExports()->GetAchievementsPanelMinWidth() )
+ {
+ ISteamFriends *friends = steamapicontext->SteamFriends();
+ if ( friends )
+ {
+ friends->ActivateGameOverlay( "Achievements" );
+ }
+ }
+ else
+ {
+ // Display the CSS achievements screen.
+ GameClientExports()->CreateAchievementsPanel( this );
+ GameClientExports()->DisplayAchievementPanel();
+ }
+ }
+}
+
+//=============================================================================
+// HPE_END
+//=============================================================================
+
+void CBasePanel::OnOpenAchievementsDialog_Xbox()
+{
+ if (!m_hAchievementsDialog.Get())
+ {
+ m_hAchievementsDialog = new CAchievementsDialog_XBox( this );
+ PositionDialog(m_hAchievementsDialog);
+ }
+ m_hAchievementsDialog->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenMatchmakingBasePanel()
+{
+ if (!m_hMatchmakingBasePanel.Get())
+ {
+ m_hMatchmakingBasePanel = new CMatchmakingBasePanel( this );
+ int x, y, wide, tall;
+ GetBounds( x, y, wide, tall );
+ m_hMatchmakingBasePanel->SetBounds( x, y, wide, tall );
+ }
+
+ if ( m_pGameLogo )
+ {
+ m_pGameLogo->SetVisible( false );
+ }
+
+ // Hide the standard game menu
+ for ( int i = 0; i < m_pGameMenuButtons.Count(); ++i )
+ {
+ m_pGameMenuButtons[i]->SetVisible( false );
+ }
+
+ // Hide the BasePanel's button footer
+ m_pGameMenu->ShowFooter( false );
+
+ m_hMatchmakingBasePanel->SetVisible( true );
+
+ m_hMatchmakingBasePanel->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Helper function for this common operation
+//-----------------------------------------------------------------------------
+CMatchmakingBasePanel *CBasePanel::GetMatchmakingBasePanel()
+{
+ CMatchmakingBasePanel *pBase = NULL;
+ if ( m_bUseMatchmaking )
+ {
+ pBase = dynamic_cast< CMatchmakingBasePanel* >( m_hMatchmakingBasePanel.Get() );
+ }
+ return pBase;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: moves the game menu button to the right place on the taskbar
+//-----------------------------------------------------------------------------
+void CBasePanel::PositionDialog(vgui::PHandle dlg)
+{
+ if (!dlg.Get())
+ return;
+
+ int x, y, ww, wt, wide, tall;
+ vgui::surface()->GetWorkspaceBounds( x, y, ww, wt );
+ dlg->GetSize(wide, tall);
+
+ // Center it, keeping requested size
+ dlg->SetPos(x + ((ww - wide) / 2), y + ((wt - tall) / 2));
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Add an Xbox 360 message dialog to a dialog stack
+//-----------------------------------------------------------------------------
+void CBasePanel::ShowMessageDialog( const uint nType, vgui::Panel *pOwner )
+{
+ if ( pOwner == NULL )
+ {
+ pOwner = this;
+ }
+
+ m_MessageDialogHandler.ShowMessageDialog( nType, pOwner );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Add an Xbox 360 message dialog to a dialog stack
+//-----------------------------------------------------------------------------
+void CBasePanel::CloseMessageDialog( const uint nType )
+{
+ m_MessageDialogHandler.CloseMessageDialog( nType );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Matchmaking notification from engine
+//-----------------------------------------------------------------------------
+void CBasePanel::SessionNotification( const int notification, const int param )
+{
+ // This is a job for the matchmaking panel
+ CMatchmakingBasePanel *pBase = GetMatchmakingBasePanel();
+ if ( pBase )
+ {
+ pBase->SessionNotification( notification, param );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: System notification from engine
+//-----------------------------------------------------------------------------
+void CBasePanel::SystemNotification( const int notification )
+{
+ CMatchmakingBasePanel *pBase = GetMatchmakingBasePanel();
+ if ( pBase )
+ {
+ pBase->SystemNotification( notification );
+ }
+
+ if ( notification == SYSTEMNOTIFY_USER_SIGNEDIN )
+ {
+#if defined( _X360 )
+ // See if it was the active user who signed in
+ uint state = XUserGetSigninState( XBX_GetPrimaryUserId() );
+ if ( state != eXUserSigninState_NotSignedIn )
+ {
+ // Reset a bunch of state
+ m_bUserRefusedSignIn = false;
+ m_bUserRefusedStorageDevice = false;
+ m_bStorageBladeShown = false;
+ }
+ UpdateRichPresenceInfo();
+ engine->GetAchievementMgr()->DownloadUserData();
+ engine->GetAchievementMgr()->EnsureGlobalStateLoaded();
+#endif
+ }
+ else if ( notification == SYSTEMNOTIFY_USER_SIGNEDOUT )
+ {
+#if defined( _X360 )
+ // See if it was the active user who signed out
+ uint state = XUserGetSigninState( XBX_GetPrimaryUserId() );
+ if ( state != eXUserSigninState_NotSignedIn )
+ {
+ return;
+ }
+
+ // Invalidate their storage ID
+ engine->OnStorageDeviceDetached();
+ m_bUserRefusedStorageDevice = false;
+ m_bUserRefusedSignIn = false;
+ m_iStorageID = XBX_INVALID_STORAGE_ID;
+ engine->GetAchievementMgr()->InitializeAchievements();
+ m_MessageDialogHandler.CloseAllMessageDialogs();
+
+#endif
+ if ( GameUI().IsInLevel() )
+ {
+ if ( m_pGameLogo )
+ {
+ m_pGameLogo->SetVisible( false );
+ }
+
+ // Hide the standard game menu
+ for ( int i = 0; i < m_pGameMenuButtons.Count(); ++i )
+ {
+ m_pGameMenuButtons[i]->SetVisible( false );
+ }
+
+ // Hide the BasePanel's button footer
+ m_pGameMenu->ShowFooter( false );
+
+ QueueCommand( "QuitNoConfirm" );
+ }
+ else
+ {
+ CloseBaseDialogs();
+ }
+
+ OnCommand( "OpenMainMenu" );
+ }
+ else if ( notification == SYSTEMNOTIFY_STORAGEDEVICES_CHANGED )
+ {
+ if ( m_hSaveGameDialog_Xbox.Get() )
+ m_hSaveGameDialog_Xbox->OnCommand( "RefreshSaveGames" );
+ if ( m_hLoadGameDialog_Xbox.Get() )
+ m_hLoadGameDialog_Xbox->OnCommand( "RefreshSaveGames" );
+
+ // FIXME: This code is incorrect, they do NOT need a storage device, it is only recommended that they do
+ if ( GameUI().IsInLevel() )
+ {
+ // They wanted to use a storage device and are already playing!
+ // They need a storage device now or we're quitting the game!
+ m_bNeedStorageDeviceHandle = true;
+ ShowMessageDialog( MD_STORAGE_DEVICES_NEEDED, this );
+ }
+ else
+ {
+ ShowMessageDialog( MD_STORAGE_DEVICES_CHANGED, this );
+ }
+ }
+ else if ( notification == SYSTEMNOTIFY_XUIOPENING )
+ {
+ m_bXUIVisible = true;
+ }
+ else if ( notification == SYSTEMNOTIFY_XUICLOSED )
+ {
+ m_bXUIVisible = false;
+
+ if ( m_bWaitingForStorageDeviceHandle )
+ {
+ DWORD ret = xboxsystem->GetOverlappedResult( m_hStorageDeviceChangeHandle, NULL, true );
+ if ( ret != ERROR_IO_INCOMPLETE )
+ {
+ // Done waiting
+ xboxsystem->ReleaseAsyncHandle( m_hStorageDeviceChangeHandle );
+
+ m_bWaitingForStorageDeviceHandle = false;
+
+ // If we selected something, validate it
+ if ( m_iStorageID != XBX_INVALID_STORAGE_ID )
+ {
+ // Check to see if there is enough room on this storage device
+ if ( xboxsystem->DeviceCapacityAdequate( m_iStorageID, COM_GetModDirectory() ) == false )
+ {
+ ShowMessageDialog( MD_STORAGE_DEVICES_TOO_FULL, this );
+ m_bStorageBladeShown = false; // Show the blade again next time
+ m_strPostPromptCommand = ""; // Clear the buffer, we can't return
+ }
+ else
+ {
+ m_bNeedStorageDeviceHandle = false;
+
+ // Set the storage device
+ XBX_SetStorageDeviceId( m_iStorageID );
+ OnDeviceAttached();
+ }
+ }
+ else
+ {
+ if ( m_pStorageDeviceValidatedNotify )
+ {
+ *m_pStorageDeviceValidatedNotify = 2;
+ m_pStorageDeviceValidatedNotify = NULL;
+ }
+ else if ( m_bNeedStorageDeviceHandle )
+ {
+ // They didn't select a storage device!
+ // Remind them that they must pick one or the game will shut down
+ ShowMessageDialog( MD_STORAGE_DEVICES_NEEDED, this );
+ }
+ else
+ {
+ // Start off the command we queued up
+ IssuePostPromptCommand();
+ }
+ }
+ }
+ }
+
+ // If we're waiting for the user to sign in, and check if they selected a usable profile
+ if ( m_bWaitingForUserSignIn )
+ {
+ // Done waiting
+ m_bWaitingForUserSignIn = false;
+ m_bUserRefusedSignIn = false;
+
+ // The UI has closed, so go off and revalidate the state
+ if ( m_strPostPromptCommand.IsEmpty() == false )
+ {
+ // Run the command again
+ OnCommand( m_strPostPromptCommand );
+ }
+ }
+
+ RunQueuedCommands();
+ }
+ else if ( notification == SYSTEMNOTIFY_INVITE_SHUTDOWN )
+ {
+ // Quit the current game without confirmation
+ m_bRestartFromInvite = true;
+ m_bXUIVisible = true;
+ OnCommand( "QuitNoConfirm" );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Matchmaking notification that a player's info has changed
+//-----------------------------------------------------------------------------
+void CBasePanel::UpdatePlayerInfo( uint64 nPlayerId, const char *pName, int nTeam, byte cVoiceState, int nPlayersNeeded, bool bHost )
+{
+ CMatchmakingBasePanel *pBase = GetMatchmakingBasePanel();
+ if ( pBase )
+ {
+ pBase->UpdatePlayerInfo( nPlayerId, pName, nTeam, cVoiceState, nPlayersNeeded, bHost );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Matchmaking notification to add a session to the browser
+//-----------------------------------------------------------------------------
+void CBasePanel::SessionSearchResult( int searchIdx, void *pHostData, XSESSION_SEARCHRESULT *pResult, int ping )
+{
+ CMatchmakingBasePanel *pBase = GetMatchmakingBasePanel();
+ if ( pBase )
+ {
+ pBase->SessionSearchResult( searchIdx, pHostData, pResult, ping );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnChangeStorageDevice( void )
+{
+ if ( m_bWaitingForStorageDeviceHandle == false )
+ {
+ m_bWaitingForStorageDeviceHandle = true;
+ m_hStorageDeviceChangeHandle = xboxsystem->CreateAsyncHandle();
+ m_iStorageID = XBX_INVALID_STORAGE_ID;
+ xboxsystem->ShowDeviceSelector( true, &m_iStorageID, &m_hStorageDeviceChangeHandle );
+ }
+}
+
+void CBasePanel::OnCreditsFinished( void )
+{
+ if ( !IsX360() )
+ {
+ // valid for 360 only
+ Assert( 0 );
+ return;
+ }
+
+ bool bExitToAppChooser = false;
+ if ( bExitToAppChooser )
+ {
+ // unknown state from engine, force to a compliant exiting state
+ // causes an complete exit out of the game back to the app launcher
+ SetVisible( true );
+ m_pGameMenu->SetAlpha( 0 );
+ StartExitingProcess();
+ }
+ else
+ {
+ // expecting to transition from the credits back to the background map
+ // prevent any possibility of using the last transition image
+ m_bUseRenderTargetImage = false;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnGameUIHidden()
+{
+ if ( m_hOptionsDialog.Get() )
+ {
+ PostMessage( m_hOptionsDialog.Get(), new KeyValues( "GameUIHidden" ) );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets the alpha of the menu panels
+//-----------------------------------------------------------------------------
+void CBasePanel::SetMenuAlpha(int alpha)
+{
+ if ( GameUI().IsConsoleUI() )
+ {
+ // handled by animation, not code
+ return;
+ }
+
+ m_pGameMenu->SetAlpha(alpha);
+
+ if ( m_pGameLogo )
+ {
+ m_pGameLogo->SetAlpha( alpha );
+ }
+
+ for ( int i=0; i<m_pGameMenuButtons.Count(); ++i )
+ {
+ m_pGameMenuButtons[i]->SetAlpha(alpha);
+ }
+ m_bForceTitleTextUpdate = true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int CBasePanel::GetMenuAlpha( void )
+{
+ return m_pGameMenu->GetAlpha();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::SetMainMenuOverride( vgui::VPANEL panel )
+{
+ m_hMainMenuOverridePanel = panel;
+
+ if ( m_pGameMenu )
+ {
+ m_pGameMenu->SetMainMenuOverride( panel );
+ }
+
+ if ( m_hMainMenuOverridePanel )
+ {
+ // Parent it to this panel
+ ipanel()->SetParent( m_hMainMenuOverridePanel, GetVPanel() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: starts the game
+//-----------------------------------------------------------------------------
+void CBasePanel::FadeToBlackAndRunEngineCommand( const char *engineCommand )
+{
+ KeyValues *pKV = new KeyValues( "RunEngineCommand", "command", engineCommand );
+
+ // execute immediately, with no delay
+ PostMessage( this, pKV, 0 );
+}
+
+void CBasePanel::SetMenuItemBlinkingState( const char *itemName, bool state )
+{
+ for (int i = 0; i < GetChildCount(); i++)
+ {
+ Panel *child = GetChild(i);
+ CGameMenu *pGameMenu = dynamic_cast<CGameMenu *>(child);
+ if ( pGameMenu )
+ {
+ pGameMenu->SetMenuItemBlinkingState( itemName, state );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: runs an engine command, used for delays
+//-----------------------------------------------------------------------------
+void CBasePanel::RunEngineCommand(const char *command)
+{
+ engine->ClientCmd_Unrestricted(command);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: runs an animation to close a dialog and cleans up after close
+//-----------------------------------------------------------------------------
+void CBasePanel::RunCloseAnimation( const char *animName )
+{
+ RunAnimationWithCallback( this, animName, new KeyValues( "FinishDialogClose" ) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: cleans up after a menu closes
+//-----------------------------------------------------------------------------
+void CBasePanel::FinishDialogClose( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: xbox UI panel that displays button icons and help text for all menus
+//-----------------------------------------------------------------------------
+CFooterPanel::CFooterPanel( Panel *parent, const char *panelName ) : BaseClass( parent, panelName )
+{
+ SetVisible( true );
+ SetAlpha( 0 );
+ m_pHelpName = NULL;
+
+ m_pSizingLabel = new vgui::Label( this, "SizingLabel", "" );
+ m_pSizingLabel->SetVisible( false );
+
+ m_nButtonGap = 32;
+ m_nButtonGapDefault = 32;
+ m_ButtonPinRight = 100;
+ m_FooterTall = 80;
+
+ int wide, tall;
+ surface()->GetScreenSize(wide, tall);
+
+ if ( tall <= 480 )
+ {
+ m_FooterTall = 60;
+ }
+
+ m_ButtonOffsetFromTop = 0;
+ m_ButtonSeparator = 4;
+ m_TextAdjust = 0;
+
+ m_bPaintBackground = false;
+ m_bCenterHorizontal = false;
+
+ m_szButtonFont[0] = '\0';
+ m_szTextFont[0] = '\0';
+ m_szFGColor[0] = '\0';
+ m_szBGColor[0] = '\0';
+}
+
+CFooterPanel::~CFooterPanel()
+{
+ SetHelpNameAndReset( NULL );
+
+ delete m_pSizingLabel;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: apply scheme settings
+//-----------------------------------------------------------------------------
+void CFooterPanel::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ m_hButtonFont = pScheme->GetFont( ( m_szButtonFont[0] != '\0' ) ? m_szButtonFont : "GameUIButtons" );
+ m_hTextFont = pScheme->GetFont( ( m_szTextFont[0] != '\0' ) ? m_szTextFont : "MenuLarge" );
+
+ SetFgColor( pScheme->GetColor( m_szFGColor, Color( 255, 255, 255, 255 ) ) );
+ SetBgColor( pScheme->GetColor( m_szBGColor, Color( 0, 0, 0, 255 ) ) );
+
+ int x, y, w, h;
+ GetParent()->GetBounds( x, y, w, h );
+ SetBounds( x, h - m_FooterTall, w, m_FooterTall );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: apply settings
+//-----------------------------------------------------------------------------
+void CFooterPanel::ApplySettings( KeyValues *inResourceData )
+{
+ BaseClass::ApplySettings( inResourceData );
+
+ // gap between hints
+ m_nButtonGap = inResourceData->GetInt( "buttongap", 32 );
+ m_nButtonGapDefault = m_nButtonGap;
+ m_ButtonPinRight = inResourceData->GetInt( "button_pin_right", 100 );
+ m_FooterTall = inResourceData->GetInt( "tall", 80 );
+ m_ButtonOffsetFromTop = inResourceData->GetInt( "buttonoffsety", 0 );
+ m_ButtonSeparator = inResourceData->GetInt( "button_separator", 4 );
+ m_TextAdjust = inResourceData->GetInt( "textadjust", 0 );
+
+ m_bCenterHorizontal = ( inResourceData->GetInt( "center", 0 ) == 1 );
+ m_bPaintBackground = ( inResourceData->GetInt( "paintbackground", 0 ) == 1 );
+
+ // fonts for text and button
+ Q_strncpy( m_szTextFont, inResourceData->GetString( "fonttext", "MenuLarge" ), sizeof( m_szTextFont ) );
+ Q_strncpy( m_szButtonFont, inResourceData->GetString( "fontbutton", "GameUIButtons" ), sizeof( m_szButtonFont ) );
+
+ // fg and bg colors
+ Q_strncpy( m_szFGColor, inResourceData->GetString( "fgcolor", "White" ), sizeof( m_szFGColor ) );
+ Q_strncpy( m_szBGColor, inResourceData->GetString( "bgcolor", "Black" ), sizeof( m_szBGColor ) );
+
+ for ( KeyValues *pButton = inResourceData->GetFirstSubKey(); pButton != NULL; pButton = pButton->GetNextKey() )
+ {
+ const char *pName = pButton->GetName();
+
+ if ( !Q_stricmp( pName, "button" ) )
+ {
+ // Add a button to the footer
+ const char *pText = pButton->GetString( "text", "NULL" );
+ const char *pIcon = pButton->GetString( "icon", "NULL" );
+ AddNewButtonLabel( pText, pIcon );
+ }
+ }
+
+ InvalidateLayout( false, true ); // force ApplySchemeSettings to run
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: adds button icons and help text to the footer panel when activating a menu
+//-----------------------------------------------------------------------------
+void CFooterPanel::AddButtonsFromMap( vgui::Frame *pMenu )
+{
+ SetHelpNameAndReset( pMenu->GetName() );
+
+ CControllerMap *pMap = dynamic_cast<CControllerMap*>( pMenu->FindChildByName( "ControllerMap" ) );
+ if ( pMap )
+ {
+ int buttonCt = pMap->NumButtons();
+ for ( int i = 0; i < buttonCt; ++i )
+ {
+ const char *pText = pMap->GetBindingText( i );
+ if ( pText )
+ {
+ AddNewButtonLabel( pText, pMap->GetBindingIcon( i ) );
+ }
+ }
+ }
+}
+
+void CFooterPanel::SetStandardDialogButtons()
+{
+ SetHelpNameAndReset( "Dialog" );
+ AddNewButtonLabel( "#GameUI_Action", "#GameUI_Icons_A_BUTTON" );
+ AddNewButtonLabel( "#GameUI_Close", "#GameUI_Icons_B_BUTTON" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Caller must tag the button layout. May support reserved names
+// to provide stock help layouts trivially.
+//-----------------------------------------------------------------------------
+void CFooterPanel::SetHelpNameAndReset( const char *pName )
+{
+ if ( m_pHelpName )
+ {
+ free( m_pHelpName );
+ m_pHelpName = NULL;
+ }
+
+ if ( pName )
+ {
+ m_pHelpName = strdup( pName );
+ }
+
+ ClearButtons();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Caller must tag the button layout
+//-----------------------------------------------------------------------------
+const char *CFooterPanel::GetHelpName()
+{
+ return m_pHelpName;
+}
+
+void CFooterPanel::ClearButtons( void )
+{
+ m_ButtonLabels.PurgeAndDeleteElements();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: creates a new button label with icon and text
+//-----------------------------------------------------------------------------
+void CFooterPanel::AddNewButtonLabel( const char *text, const char *icon )
+{
+ ButtonLabel_t *button = new ButtonLabel_t;
+
+ Q_strncpy( button->name, text, MAX_PATH );
+ button->bVisible = true;
+
+ // Button icons are a single character
+ wchar_t *pIcon = g_pVGuiLocalize->Find( icon );
+ if ( pIcon )
+ {
+ button->icon[0] = pIcon[0];
+ button->icon[1] = '\0';
+ }
+ else
+ {
+ button->icon[0] = '\0';
+ }
+
+ // Set the help text
+ wchar_t *pText = g_pVGuiLocalize->Find( text );
+ if ( pText )
+ {
+ wcsncpy( button->text, pText, wcslen( pText ) + 1 );
+ }
+ else
+ {
+ button->text[0] = '\0';
+ }
+
+ m_ButtonLabels.AddToTail( button );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Shows/Hides a button label
+//-----------------------------------------------------------------------------
+void CFooterPanel::ShowButtonLabel( const char *name, bool show )
+{
+ for ( int i = 0; i < m_ButtonLabels.Count(); ++i )
+ {
+ if ( !Q_stricmp( m_ButtonLabels[ i ]->name, name ) )
+ {
+ m_ButtonLabels[ i ]->bVisible = show;
+ break;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Changes a button's text
+//-----------------------------------------------------------------------------
+void CFooterPanel::SetButtonText( const char *buttonName, const char *text )
+{
+ for ( int i = 0; i < m_ButtonLabels.Count(); ++i )
+ {
+ if ( !Q_stricmp( m_ButtonLabels[ i ]->name, buttonName ) )
+ {
+ wchar_t *wtext = g_pVGuiLocalize->Find( text );
+ if ( text )
+ {
+ wcsncpy( m_ButtonLabels[ i ]->text, wtext, wcslen( wtext ) + 1 );
+ }
+ else
+ {
+ m_ButtonLabels[ i ]->text[ 0 ] = '\0';
+ }
+ break;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Footer panel background rendering
+//-----------------------------------------------------------------------------
+void CFooterPanel::PaintBackground( void )
+{
+ if ( !m_bPaintBackground )
+ return;
+
+ BaseClass::PaintBackground();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Footer panel rendering
+//-----------------------------------------------------------------------------
+void CFooterPanel::Paint( void )
+{
+ // inset from right edge
+ int wide = GetWide();
+ int right = wide - m_ButtonPinRight;
+
+ // center the text within the button
+ int buttonHeight = vgui::surface()->GetFontTall( m_hButtonFont );
+ int fontHeight = vgui::surface()->GetFontTall( m_hTextFont );
+ int textY = ( buttonHeight - fontHeight )/2 + m_TextAdjust;
+
+ if ( textY < 0 )
+ {
+ textY = 0;
+ }
+
+ int y = m_ButtonOffsetFromTop;
+
+ if ( !m_bCenterHorizontal )
+ {
+ // draw the buttons, right to left
+ int x = right;
+
+ for ( int i = 0; i < m_ButtonLabels.Count(); ++i )
+ {
+ ButtonLabel_t *pButton = m_ButtonLabels[i];
+ if ( !pButton->bVisible )
+ continue;
+
+ // Get the string length
+ m_pSizingLabel->SetFont( m_hTextFont );
+ m_pSizingLabel->SetText( pButton->text );
+ m_pSizingLabel->SizeToContents();
+
+ int iTextWidth = m_pSizingLabel->GetWide();
+
+ if ( iTextWidth == 0 )
+ x += m_nButtonGap; // There's no text, so remove the gap between buttons
+ else
+ x -= iTextWidth;
+
+ // Draw the string
+ vgui::surface()->DrawSetTextFont( m_hTextFont );
+ vgui::surface()->DrawSetTextColor( GetFgColor() );
+ vgui::surface()->DrawSetTextPos( x, y + textY );
+ vgui::surface()->DrawPrintText( pButton->text, wcslen( pButton->text ) );
+
+ // Draw the button
+ // back up button width and a little extra to leave a gap between button and text
+ x -= ( vgui::surface()->GetCharacterWidth( m_hButtonFont, pButton->icon[0] ) + m_ButtonSeparator );
+ vgui::surface()->DrawSetTextFont( m_hButtonFont );
+ vgui::surface()->DrawSetTextColor( 255, 255, 255, 255 );
+ vgui::surface()->DrawSetTextPos( x, y );
+ vgui::surface()->DrawPrintText( pButton->icon, 1 );
+
+ // back up to next string
+ x -= m_nButtonGap;
+ }
+ }
+ else
+ {
+ // center the buttons (as a group)
+ int x = wide / 2;
+ int totalWidth = 0;
+ int i = 0;
+ int nButtonCount = 0;
+
+ // need to loop through and figure out how wide our buttons and text are (with gaps between) so we can offset from the center
+ for ( i = 0; i < m_ButtonLabels.Count(); ++i )
+ {
+ ButtonLabel_t *pButton = m_ButtonLabels[i];
+ if ( !pButton->bVisible )
+ continue;
+
+ // Get the string length
+ m_pSizingLabel->SetFont( m_hTextFont );
+ m_pSizingLabel->SetText( pButton->text );
+ m_pSizingLabel->SizeToContents();
+
+ totalWidth += vgui::surface()->GetCharacterWidth( m_hButtonFont, pButton->icon[0] );
+ totalWidth += m_ButtonSeparator;
+ totalWidth += m_pSizingLabel->GetWide();
+
+ nButtonCount++; // keep track of how many active buttons we'll be drawing
+ }
+
+ totalWidth += ( nButtonCount - 1 ) * m_nButtonGap; // add in the gaps between the buttons
+ x -= ( totalWidth / 2 );
+
+ for ( i = 0; i < m_ButtonLabels.Count(); ++i )
+ {
+ ButtonLabel_t *pButton = m_ButtonLabels[i];
+ if ( !pButton->bVisible )
+ continue;
+
+ // Get the string length
+ m_pSizingLabel->SetFont( m_hTextFont );
+ m_pSizingLabel->SetText( pButton->text );
+ m_pSizingLabel->SizeToContents();
+
+ int iTextWidth = m_pSizingLabel->GetWide();
+
+ // Draw the icon
+ vgui::surface()->DrawSetTextFont( m_hButtonFont );
+ vgui::surface()->DrawSetTextColor( 255, 255, 255, 255 );
+ vgui::surface()->DrawSetTextPos( x, y );
+ vgui::surface()->DrawPrintText( pButton->icon, 1 );
+ x += vgui::surface()->GetCharacterWidth( m_hButtonFont, pButton->icon[0] ) + m_ButtonSeparator;
+
+ // Draw the string
+ vgui::surface()->DrawSetTextFont( m_hTextFont );
+ vgui::surface()->DrawSetTextColor( GetFgColor() );
+ vgui::surface()->DrawSetTextPos( x, y + textY );
+ vgui::surface()->DrawPrintText( pButton->text, wcslen( pButton->text ) );
+
+ x += iTextWidth + m_nButtonGap;
+ }
+ }
+}
+
+DECLARE_BUILD_FACTORY( CFooterPanel );
+
+#ifdef _X360
+//-----------------------------------------------------------------------------
+// Purpose: Reload the resource files on the Xbox 360
+//-----------------------------------------------------------------------------
+void CBasePanel::Reload_Resources( const CCommand &args )
+{
+ m_pConsoleControlSettings->Clear();
+ if ( m_pConsoleControlSettings->LoadFromFile( g_pFullFileSystem, "resource/UI/XboxDialogs.res" ) )
+ {
+ m_pConsoleControlSettings->ProcessResolutionKeys( surface()->GetResolutionKey() );
+ }
+}
+#endif
+
+
+// X360TBD: Move into a separate module when completed
+CMessageDialogHandler::CMessageDialogHandler()
+{
+ m_iDialogStackTop = -1;
+}
+void CMessageDialogHandler::ShowMessageDialog( int nType, vgui::Panel *pOwner )
+{
+ int iSimpleFrame = 0;
+ if ( ModInfo().IsSinglePlayerOnly() )
+ {
+ iSimpleFrame = MD_SIMPLEFRAME;
+ }
+
+ switch( nType )
+ {
+ case MD_SEARCHING_FOR_GAMES:
+ CreateMessageDialog( MD_CANCEL|MD_RESTRICTPAINT,
+ NULL,
+ "#TF_Dlg_SearchingForGames",
+ NULL,
+ "CancelOperation",
+ pOwner,
+ true );
+ break;
+
+ case MD_CREATING_GAME:
+ CreateMessageDialog( MD_RESTRICTPAINT,
+ NULL,
+ "#TF_Dlg_CreatingGame",
+ NULL,
+ NULL,
+ pOwner,
+ true );
+ break;
+
+ case MD_SESSION_SEARCH_FAILED:
+ CreateMessageDialog( MD_YESNO|MD_RESTRICTPAINT,
+ NULL,
+ "#TF_Dlg_NoGamesFound",
+ "ShowSessionOptionsDialog",
+ "ReturnToMainMenu",
+ pOwner );
+ break;
+
+ case MD_SESSION_CREATE_FAILED:
+ CreateMessageDialog( MD_OK,
+ NULL,
+ "#TF_Dlg_CreateFailed",
+ "ReturnToMainMenu",
+ NULL,
+ pOwner );
+ break;
+
+ case MD_SESSION_CONNECTING:
+ CreateMessageDialog( 0,
+ NULL,
+ "#TF_Dlg_Connecting",
+ NULL,
+ NULL,
+ pOwner,
+ true );
+ break;
+
+ case MD_SESSION_CONNECT_NOTAVAILABLE:
+ CreateMessageDialog( MD_OK,
+ NULL,
+ "#TF_Dlg_JoinRefused",
+ "ReturnToMainMenu",
+ NULL,
+ pOwner );
+ break;
+
+ case MD_SESSION_CONNECT_SESSIONFULL:
+ CreateMessageDialog( MD_OK,
+ NULL,
+ "#TF_Dlg_GameFull",
+ "ReturnToMainMenu",
+ NULL,
+ pOwner );
+ break;
+
+ case MD_SESSION_CONNECT_FAILED:
+ CreateMessageDialog( MD_OK,
+ NULL,
+ "#TF_Dlg_JoinFailed",
+ "ReturnToMainMenu",
+ NULL,
+ pOwner );
+ break;
+
+ case MD_LOST_HOST:
+ CreateMessageDialog( MD_OK|MD_RESTRICTPAINT,
+ NULL,
+ "#TF_Dlg_LostHost",
+ "ReturnToMainMenu",
+ NULL,
+ pOwner );
+ break;
+
+ case MD_LOST_SERVER:
+ CreateMessageDialog( MD_OK|MD_RESTRICTPAINT,
+ NULL,
+ "#TF_Dlg_LostServer",
+ "ReturnToMainMenu",
+ NULL,
+ pOwner );
+ break;
+
+ case MD_MODIFYING_SESSION:
+ CreateMessageDialog( MD_RESTRICTPAINT,
+ NULL,
+ "#TF_Dlg_ModifyingSession",
+ NULL,
+ NULL,
+ pOwner,
+ true );
+ break;
+
+ case MD_SAVE_BEFORE_QUIT:
+ CreateMessageDialog( MD_YESNO|iSimpleFrame|MD_RESTRICTPAINT,
+ "#GameUI_QuitConfirmationTitle",
+ "#GameUI_Console_QuitWarning",
+ "QuitNoConfirm",
+ "CloseQuitDialog_OpenMainMenu",
+ pOwner );
+ break;
+
+ case MD_QUIT_CONFIRMATION:
+ CreateMessageDialog( MD_YESNO|iSimpleFrame|MD_RESTRICTPAINT,
+ "#GameUI_QuitConfirmationTitle",
+ "#GameUI_QuitConfirmationText",
+ "QuitNoConfirm",
+ "CloseQuitDialog_OpenMainMenu",
+ pOwner );
+ break;
+
+ case MD_QUIT_CONFIRMATION_TF:
+ CreateMessageDialog( MD_YESNO|MD_RESTRICTPAINT,
+ "#GameUI_QuitConfirmationTitle",
+ "#GameUI_QuitConfirmationText",
+ "QuitNoConfirm",
+ "CloseQuitDialog_OpenMatchmakingMenu",
+ pOwner );
+ break;
+
+ case MD_DISCONNECT_CONFIRMATION:
+ CreateMessageDialog( MD_YESNO|MD_RESTRICTPAINT,
+ "",
+ "#GameUI_DisconnectConfirmationText",
+ "DisconnectNoConfirm",
+ "close_dialog",
+ pOwner );
+ break;
+
+ case MD_DISCONNECT_CONFIRMATION_HOST:
+ CreateMessageDialog( MD_YESNO|MD_RESTRICTPAINT,
+ "",
+ "#GameUI_DisconnectHostConfirmationText",
+ "DisconnectNoConfirm",
+ "close_dialog",
+ pOwner );
+ break;
+
+ case MD_KICK_CONFIRMATION:
+ CreateMessageDialog( MD_YESNO,
+ "",
+ "#TF_Dlg_ConfirmKick",
+ "KickPlayer",
+ "close_dialog",
+ pOwner );
+ break;
+
+ case MD_CLIENT_KICKED:
+ CreateMessageDialog( MD_OK|MD_RESTRICTPAINT,
+ "",
+ "#TF_Dlg_ClientKicked",
+ "close_dialog",
+ NULL,
+ pOwner );
+ break;
+
+ case MD_EXIT_SESSION_CONFIRMATION:
+ CreateMessageDialog( MD_YESNO,
+ "",
+ "#TF_Dlg_ExitSessionText",
+ "ReturnToMainMenu",
+ "close_dialog",
+ pOwner );
+ break;
+
+ case MD_STORAGE_DEVICES_NEEDED:
+ CreateMessageDialog( MD_YESNO|MD_WARNING|MD_COMMANDAFTERCLOSE|iSimpleFrame|MD_RESTRICTPAINT,
+ "#GameUI_Console_StorageRemovedTitle",
+ "#GameUI_Console_StorageNeededBody",
+ "ShowDeviceSelector",
+ "QuitNoConfirm",
+ pOwner );
+ break;
+
+ case MD_STORAGE_DEVICES_CHANGED:
+ CreateMessageDialog( MD_YESNO|MD_WARNING|MD_COMMANDAFTERCLOSE|iSimpleFrame|MD_RESTRICTPAINT,
+ "#GameUI_Console_StorageRemovedTitle",
+ "#GameUI_Console_StorageRemovedBody",
+ "ShowDeviceSelector",
+ "clear_storage_deviceID",
+ pOwner );
+ break;
+
+ case MD_STORAGE_DEVICES_TOO_FULL:
+ CreateMessageDialog( MD_YESNO|MD_WARNING|MD_COMMANDAFTERCLOSE|iSimpleFrame|MD_RESTRICTPAINT,
+ "#GameUI_Console_StorageTooFullTitle",
+ "#GameUI_Console_StorageTooFullBody",
+ "ShowDeviceSelector",
+ "StorageDeviceDenied",
+ pOwner );
+ break;
+
+ case MD_PROMPT_STORAGE_DEVICE:
+ CreateMessageDialog( MD_YESNO|MD_WARNING|MD_COMMANDAFTERCLOSE|iSimpleFrame|MD_RESTRICTPAINT,
+ "#GameUI_Console_NoStorageDeviceSelectedTitle",
+ "#GameUI_Console_NoStorageDeviceSelectedBody",
+ "ShowDeviceSelector",
+ "StorageDeviceDenied",
+ pOwner );
+ break;
+
+ case MD_PROMPT_STORAGE_DEVICE_REQUIRED:
+ CreateMessageDialog( MD_YESNO|MD_WARNING|MD_COMMANDAFTERCLOSE|MD_SIMPLEFRAME,
+ "#GameUI_Console_NoStorageDeviceSelectedTitle",
+ "#GameUI_Console_StorageDeviceRequiredBody",
+ "ShowDeviceSelector",
+ "RequiredStorageDenied",
+ pOwner );
+ break;
+
+ case MD_PROMPT_SIGNIN:
+ CreateMessageDialog( MD_YESNO|MD_WARNING|MD_COMMANDAFTERCLOSE|iSimpleFrame,
+ "#GameUI_Console_NoUserProfileSelectedTitle",
+ "#GameUI_Console_NoUserProfileSelectedBody",
+ "ShowSignInUI",
+ "SignInDenied",
+ pOwner );
+ break;
+
+ case MD_PROMPT_SIGNIN_REQUIRED:
+ CreateMessageDialog( MD_YESNO|MD_WARNING|MD_COMMANDAFTERCLOSE|iSimpleFrame,
+ "#GameUI_Console_NoUserProfileSelectedTitle",
+ "#GameUI_Console_UserProfileRequiredBody",
+ "ShowSignInUI",
+ "RequiredSignInDenied",
+ pOwner );
+ break;
+
+ case MD_NOT_ONLINE_ENABLED:
+ CreateMessageDialog( MD_YESNO|MD_WARNING,
+ "",
+ "#TF_Dlg_NotOnlineEnabled",
+ "ShowSigninUI",
+ "close_dialog",
+ pOwner );
+ break;
+
+ case MD_NOT_ONLINE_SIGNEDIN:
+ CreateMessageDialog( MD_YESNO|MD_WARNING,
+ "",
+ "#TF_Dlg_NotOnlineSignedIn",
+ "ShowSigninUI",
+ "close_dialog",
+ pOwner );
+ break;
+
+ case MD_DEFAULT_CONTROLS_CONFIRM:
+ CreateMessageDialog( MD_YESNO|MD_WARNING|iSimpleFrame|MD_RESTRICTPAINT,
+ "#GameUI_RestoreDefaults",
+ "#GameUI_ControllerSettingsText",
+ "DefaultControls",
+ "close_dialog",
+ pOwner );
+ break;
+
+ case MD_AUTOSAVE_EXPLANATION:
+ CreateMessageDialog( MD_OK|MD_WARNING|iSimpleFrame|MD_RESTRICTPAINT,
+ "#GameUI_ConfirmNewGame_Title",
+ "#GameUI_AutoSave_Console_Explanation",
+ "StartNewGameNoCommentaryExplanation",
+ NULL,
+ pOwner );
+ break;
+
+ case MD_COMMENTARY_EXPLANATION:
+ CreateMessageDialog( MD_OK|MD_WARNING|iSimpleFrame|MD_RESTRICTPAINT,
+ "#GameUI_CommentaryDialogTitle",
+ "#GAMEUI_Commentary_Console_Explanation",
+ "StartNewGameNoCommentaryExplanation",
+ NULL,
+ pOwner );
+ break;
+
+ case MD_COMMENTARY_EXPLANATION_MULTI:
+ CreateMessageDialog( MD_OK|MD_WARNING,
+ "#GameUI_CommentaryDialogTitle",
+ "#GAMEUI_Commentary_Console_Explanation",
+ "StartNewGameNoCommentaryExplanation",
+ NULL,
+ pOwner );
+ break;
+
+ case MD_COMMENTARY_CHAPTER_UNLOCK_EXPLANATION:
+ CreateMessageDialog( MD_OK|MD_WARNING|iSimpleFrame|MD_RESTRICTPAINT,
+ "#GameUI_CommentaryDialogTitle",
+ "#GameUI_CommentaryUnlock",
+ "close_dialog",
+ NULL,
+ pOwner );
+ break;
+
+ case MD_SAVE_BEFORE_LANGUAGE_CHANGE:
+ CreateMessageDialog( MD_YESNO|MD_WARNING|MD_SIMPLEFRAME|MD_COMMANDAFTERCLOSE|MD_RESTRICTPAINT,
+ "#GameUI_ChangeLanguageRestart_Title",
+ "#GameUI_ChangeLanguageRestart_Info",
+ "AcceptVocalsLanguageChange",
+ "CancelVocalsLanguageChange",
+ pOwner );
+
+ case MD_SAVE_BEFORE_NEW_GAME:
+ CreateMessageDialog( MD_OKCANCEL|MD_WARNING|iSimpleFrame|MD_COMMANDAFTERCLOSE|MD_RESTRICTPAINT,
+ "#GameUI_ConfirmNewGame_Title",
+ "#GameUI_NewGameWarning",
+ "StartNewGame",
+ "close_dialog",
+ pOwner );
+ break;
+
+ case MD_SAVE_BEFORE_LOAD:
+ CreateMessageDialog( MD_OKCANCEL|MD_WARNING|iSimpleFrame|MD_COMMANDAFTERCLOSE|MD_RESTRICTPAINT,
+ "#GameUI_ConfirmLoadGame_Title",
+ "#GameUI_LoadWarning",
+ "LoadGame",
+ "LoadGameCancelled",
+ pOwner );
+ break;
+
+ case MD_DELETE_SAVE_CONFIRM:
+ CreateMessageDialog( MD_OKCANCEL|MD_WARNING|iSimpleFrame|MD_COMMANDAFTERCLOSE,
+ "#GameUI_ConfirmDeleteSaveGame_Title",
+ "#GameUI_ConfirmDeleteSaveGame_Info",
+ "DeleteGame",
+ "DeleteGameCancelled",
+ pOwner );
+ break;
+
+ case MD_SAVE_OVERWRITE:
+ CreateMessageDialog( MD_OKCANCEL|MD_WARNING|iSimpleFrame|MD_COMMANDAFTERCLOSE,
+ "#GameUI_ConfirmOverwriteSaveGame_Title",
+ "#GameUI_ConfirmOverwriteSaveGame_Info",
+ "SaveGame",
+ "OverwriteGameCancelled",
+ pOwner );
+ break;
+
+ case MD_SAVING_WARNING:
+ CreateMessageDialog( MD_WARNING|iSimpleFrame|MD_COMMANDONFORCECLOSE,
+ "",
+ "#GameUI_SavingWarning",
+ "SaveSuccess",
+ NULL,
+ pOwner,
+ true);
+ break;
+
+ case MD_SAVE_COMPLETE:
+ CreateMessageDialog( MD_OK|iSimpleFrame|MD_COMMANDAFTERCLOSE,
+ "#GameUI_ConfirmOverwriteSaveGame_Title",
+ "#GameUI_GameSaved",
+ "CloseAndSelectResume",
+ NULL,
+ pOwner );
+ break;
+
+ case MD_LOAD_FAILED_WARNING:
+ CreateMessageDialog( MD_OK |MD_WARNING|iSimpleFrame,
+ "#GameUI_LoadFailed",
+ "#GameUI_LoadFailed_Description",
+ "close_dialog",
+ NULL,
+ pOwner );
+ break;
+
+ case MD_OPTION_CHANGE_FROM_X360_DASHBOARD:
+ CreateMessageDialog( MD_OK|iSimpleFrame|MD_RESTRICTPAINT,
+ "#GameUI_SettingChangeFromX360Dashboard_Title",
+ "#GameUI_SettingChangeFromX360Dashboard_Info",
+ "close_dialog",
+ NULL,
+ pOwner );
+ break;
+
+ case MD_STANDARD_SAMPLE:
+ CreateMessageDialog( MD_OK,
+ "Standard Dialog",
+ "This is a standard dialog",
+ "close_dialog",
+ NULL,
+ pOwner );
+ break;
+
+ case MD_WARNING_SAMPLE:
+ CreateMessageDialog( MD_OK | MD_WARNING,
+ "#GameUI_Dialog_Warning",
+ "This is a warning dialog",
+ "close_dialog",
+ NULL,
+ pOwner );
+ break;
+
+ case MD_ERROR_SAMPLE:
+ CreateMessageDialog( MD_OK | MD_ERROR,
+ "Error Dialog",
+ "This is an error dialog",
+ "close_dialog",
+ NULL,
+ pOwner );
+ break;
+
+ case MD_STORAGE_DEVICES_CORRUPT:
+ CreateMessageDialog( MD_OK | MD_WARNING | iSimpleFrame | MD_RESTRICTPAINT,
+ "",
+ "#GameUI_Console_FileCorrupt",
+ "close_dialog",
+ NULL,
+ pOwner );
+ break;
+
+ case MD_CHECKING_STORAGE_DEVICE:
+ CreateMessageDialog( iSimpleFrame | MD_RESTRICTPAINT,
+ NULL,
+ "#GameUI_Dlg_CheckingStorageDevice",
+ NULL,
+ NULL,
+ pOwner,
+ true );
+ break;
+
+ default:
+ break;
+ }
+}
+
+void CMessageDialogHandler::CloseAllMessageDialogs()
+{
+ for ( int i = 0; i < MAX_MESSAGE_DIALOGS; ++i )
+ {
+ CMessageDialog *pDlg = m_hMessageDialogs[i];
+ if ( pDlg )
+ {
+ vgui::surface()->RestrictPaintToSinglePanel(NULL);
+ if ( vgui_message_dialog_modal.GetBool() )
+ {
+ vgui::input()->ReleaseAppModalSurface();
+ }
+
+ pDlg->Close();
+ m_hMessageDialogs[i] = NULL;
+ }
+ }
+}
+
+void CMessageDialogHandler::CloseMessageDialog( const uint nType )
+{
+ int nStackIdx = 0;
+ if ( nType & MD_WARNING )
+ {
+ nStackIdx = DIALOG_STACK_IDX_WARNING;
+ }
+ else if ( nType & MD_ERROR )
+ {
+ nStackIdx = DIALOG_STACK_IDX_ERROR;
+ }
+
+ CMessageDialog *pDlg = m_hMessageDialogs[nStackIdx];
+ if ( pDlg )
+ {
+ vgui::surface()->RestrictPaintToSinglePanel(NULL);
+ if ( vgui_message_dialog_modal.GetBool() )
+ {
+ vgui::input()->ReleaseAppModalSurface();
+ }
+
+ pDlg->Close();
+ m_hMessageDialogs[nStackIdx] = NULL;
+ }
+}
+
+void CMessageDialogHandler::CreateMessageDialog( const uint nType, const char *pTitle, const char *pMsg, const char *pCmdA, const char *pCmdB, vgui::Panel *pCreator, bool bShowActivity /*= false*/ )
+{
+ int nStackIdx = 0;
+ if ( nType & MD_WARNING )
+ {
+ nStackIdx = DIALOG_STACK_IDX_WARNING;
+ }
+ else if ( nType & MD_ERROR )
+ {
+ nStackIdx = DIALOG_STACK_IDX_ERROR;
+ }
+
+ // Can only show one dialog of each type at a time
+ if ( m_hMessageDialogs[nStackIdx].Get() )
+ {
+ Warning( "Tried to create two dialogs of type %d\n", nStackIdx );
+ return;
+ }
+
+ // Show the new dialog
+ m_hMessageDialogs[nStackIdx] = new CMessageDialog( BasePanel(), nType, pTitle, pMsg, pCmdA, pCmdB, pCreator, bShowActivity );
+
+ m_hMessageDialogs[nStackIdx]->SetControlSettingsKeys( BasePanel()->GetConsoleControlSettings()->FindKey( "MessageDialog.res" ) );
+
+ if ( nType & MD_RESTRICTPAINT )
+ {
+ vgui::surface()->RestrictPaintToSinglePanel( m_hMessageDialogs[nStackIdx]->GetVPanel() );
+ }
+
+ ActivateMessageDialog( nStackIdx );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Activate a new message dialog
+//-----------------------------------------------------------------------------
+void CMessageDialogHandler::ActivateMessageDialog( int nStackIdx )
+{
+ int x, y, wide, tall;
+ vgui::surface()->GetWorkspaceBounds( x, y, wide, tall );
+ PositionDialog( m_hMessageDialogs[nStackIdx], wide, tall );
+
+ uint nType = m_hMessageDialogs[nStackIdx]->GetType();
+ if ( nType & MD_WARNING )
+ {
+ m_hMessageDialogs[nStackIdx]->SetZPos( 75 );
+ }
+ else if ( nType & MD_ERROR )
+ {
+ m_hMessageDialogs[nStackIdx]->SetZPos( 100 );
+ }
+
+ // Make sure the topmost item on the stack still has focus
+ int idx = MAX_MESSAGE_DIALOGS - 1;
+ for ( idx; idx >= nStackIdx; --idx )
+ {
+ CMessageDialog *pDialog = m_hMessageDialogs[idx];
+ if ( pDialog )
+ {
+ pDialog->Activate();
+ if ( vgui_message_dialog_modal.GetBool() )
+ {
+ vgui::input()->SetAppModalSurface( pDialog->GetVPanel() );
+ }
+ m_iDialogStackTop = idx;
+ break;
+ }
+ }
+}
+
+void CMessageDialogHandler::PositionDialogs( int wide, int tall )
+{
+ for ( int i = 0; i < MAX_MESSAGE_DIALOGS; ++i )
+ {
+ if ( m_hMessageDialogs[i].Get() )
+ {
+ PositionDialog( m_hMessageDialogs[i], wide, tall );
+ }
+ }
+}
+
+void CMessageDialogHandler::PositionDialog( vgui::PHandle dlg, int wide, int tall )
+{
+ int w, t;
+ dlg->GetSize(w, t);
+ dlg->SetPos( (wide - w) / 2, (tall - t) / 2 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Editable panel that can replace the GameMenuButtons in CBasePanel
+//-----------------------------------------------------------------------------
+CMainMenuGameLogo::CMainMenuGameLogo( vgui::Panel *parent, const char *name ) : vgui::EditablePanel( parent, name )
+{
+ m_nOffsetX = 0;
+ m_nOffsetY = 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMainMenuGameLogo::ApplySettings( KeyValues *inResourceData )
+{
+ BaseClass::ApplySettings( inResourceData );
+
+ m_nOffsetX = inResourceData->GetInt( "offsetX", 0 );
+ m_nOffsetY = inResourceData->GetInt( "offsetY", 0 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMainMenuGameLogo::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ KeyValues *pConditions = new KeyValues( "conditions" );
+ if ( pConditions )
+ {
+ char background[MAX_PATH];
+ engine->GetMainMenuBackgroundName( background, sizeof(background) );
+
+ KeyValues *pSubKey = new KeyValues( background );
+ if ( pSubKey )
+ {
+ pConditions->AddSubKey( pSubKey );
+ }
+ }
+
+ LoadControlSettings( "Resource/GameLogo.res", NULL, NULL, pConditions );
+
+ if ( pConditions )
+ {
+ pConditions->deleteThis();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::CloseBaseDialogs( void )
+{
+ if ( m_hNewGameDialog.Get() )
+ m_hNewGameDialog->Close();
+
+ if ( m_hAchievementsDialog.Get() )
+ m_hAchievementsDialog->Close();
+
+ if ( m_hBonusMapsDialog.Get() )
+ m_hBonusMapsDialog->Close();
+
+ if ( m_hControllerDialog.Get() )
+ m_hControllerDialog->Close();
+
+ if ( m_hLoadGameDialog_Xbox.Get() )
+ m_hLoadGameDialog_Xbox->Close();
+
+ if ( m_hOptionsDialog_Xbox.Get() )
+ m_hOptionsDialog_Xbox->Close();
+
+ if ( m_hSaveGameDialog_Xbox.Get() )
+ m_hSaveGameDialog_Xbox->Close();
+
+ if ( m_hLoadCommentaryDialog.Get() )
+ m_hLoadCommentaryDialog->Close();
+
+ if ( m_hCreateMultiplayerGameDialog.Get() )
+ m_hCreateMultiplayerGameDialog->Close();
+}
+
+static void CC_GameUIShowDialog( const CCommand &args )
+{
+ int c = args.ArgC();
+
+ if ( c < 2 )
+ {
+ Msg( "Usage: gamemenucommand <commandname>\n" );
+ return;
+ }
+
+ GameUI().ShowMessageDialog( atoi(args[1]) );
+}
+static ConCommand gameui_show_dialog( "gameui_show_dialog", CC_GameUIShowDialog, "Show an arbitrary Dialog.", 0 );
+
+static void CC_GameUIHideDialog( const CCommand &args )
+{
+ int c = args.ArgC();
+ if ( c < 1 )
+ {
+ Msg( "Usage: gamemenucommand <commandname>\n" );
+ return;
+ }
+
+ GameUI().CloseMessageDialog( 0 );
+}
+static ConCommand gameui_hide_dialog( "gameui_hide_dialog", CC_GameUIHideDialog, "asdf", 0 );
+
+static void RefreshOptionsDialog( const CCommand &args )
+{
+ if ( g_hOptionsDialog )
+ {
+ CBasePanel* pBasePanel = (CBasePanel*) g_hOptionsDialog->GetParent();
+ g_hOptionsDialog->Close();
+ delete g_hOptionsDialog.Get();
+ if ( pBasePanel )
+ {
+ pBasePanel->OnOpenOptionsDialog();
+ COptionsDialog *pOptionsDialog = dynamic_cast<COptionsDialog*>( g_hOptionsDialog.Get() );
+ if ( pOptionsDialog )
+ {
+ pOptionsDialog->GetPropertySheet()->SetActivePage( pOptionsDialog->GetOptionsSubMultiplayer() );
+ }
+ }
+ }
+}
+static ConCommand refresh_options_dialog( "refresh_options_dialog", RefreshOptionsDialog, "Refresh the options dialog.", 0 );