//========= 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"
#include "VGuiMatSurface/IMatSystemSurface.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"

#ifdef ANDROID
#include <SDL_misc.h>
#endif

#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;
}

class ImageButton : public vgui::Panel
{
public:
	ImageButton(Panel *parent, const char *imageName) : Panel(parent)
	{
		m_szUrl = NULL;

		m_textureID = vgui::surface()->CreateNewTextureID();
		vgui::surface()->DrawSetTextureFile( m_textureID, imageName, true, false);
		m_bSelected = false;
	}

	virtual void Paint()
	{
		if( GameUI().IsInLevel() ) return;

		int color = m_bSelected ? 120 : 160;

		vgui::surface()->DrawSetColor(color, color, color, 100);
		vgui::surface()->DrawFilledRect( 0, 0, GetWide(), GetTall() );
		vgui::surface()->DrawSetTexture( m_textureID );

		vgui::surface()->DrawSetColor( 255, 255, 255, 255 );
		vgui::surface()->DrawTexturedRect( 0, 0, GetWide(), GetTall() );
	}

	virtual void OnMousePressed(MouseCode code)
	{
		if( GameUI().IsInLevel() ) return;

		m_bSelected = true;
		input()->SetMouseCapture(GetVPanel());
	}

	virtual void OnMouseReleased(MouseCode code)
	{
		if( GameUI().IsInLevel() ) return;

		m_bSelected = false;
#ifdef ANDROID
		if( m_szUrl ) SDL_OpenURL( m_szUrl );
#endif

		input()->SetMouseCapture(NULL);
	}

	void SetUrl( const char *url )
	{
		m_szUrl = url;
	}

	virtual void OnScreenSizeChanged( int nOldWidth, int nOldHeight )
	{
		int nw, nh;
		surface()->GetScreenSize(nw, nh);
		int scaled_w = scheme()->GetProportionalScaledValue(m_iOldW);

		Panel::SetPos(nw-scheme()->GetProportionalScaledValue(m_iOldX)-scaled_w, m_iOldY);
		Panel::SetSize(scaled_w, scheme()->GetProportionalScaledValue(m_iOldH));
	}

	void SetBounds( int x, int y, int w, int h )
	{
		m_iOldX = x; m_iOldY = y;
		m_iOldW = w; m_iOldH = h;

		int nw, nh;
		surface()->GetScreenSize(nw, nh);
		int scaled_w = scheme()->GetProportionalScaledValue(m_iOldW);

		Panel::SetPos(nw-scheme()->GetProportionalScaledValue(m_iOldX)-scaled_w, m_iOldY);
		Panel::SetSize(scaled_w, scheme()->GetProportionalScaledValue(m_iOldH));
	}

private:
	int m_iOldX, m_iOldY;
	int m_iOldW, m_iOldH;

	bool m_bSelected;
	int m_textureID;
	const char *m_szUrl;
};

void AddUrlButton(vgui::Panel *parent, const char *imgName, const char *url )
{
	static int i = 0;
	ImageButton *panel = new ImageButton( parent, imgName );
	panel->SetUrl( url );
	panel->SetBounds( 15+i*52, 10, 48, 48 );
	i++;
}

//-----------------------------------------------------------------------------
// 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);

		int height = atoi(pScheme->GetResourceString("MainMenu.MenuItemHeight"));
		if( IsProportional() )
			height = scheme()->GetProportionalScaledValue( height );

		// make fully transparent
		SetMenuItemHeight(height);
		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, wchar_t *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 || !kv2 )
						continue;

					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_HANDLE( OnCursorEnteredMenuItem, "CursorEnteredMenuItem", menuItem);

private:
	CFooterPanel *m_pConsoleFooter;
	vgui::CKeyRepeatHandler	m_KeyRepeat;
	vgui::VPANEL	m_hMainMenuOverridePanel;
};

//-----------------------------------------------------------------------------
// Purpose: Respond to cursor entering a menuItem.
//-----------------------------------------------------------------------------
void CGameMenu::OnCursorEnteredMenuItem(VPANEL menuItem)
{
	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( menuItem );
}

static CBackgroundMenuButton* CreateMenuButton( CBasePanel *parent, const char *panelName, const wchar_t *panelText )
{
	CBackgroundMenuButton *pButton = new CBackgroundMenuButton( parent, panelName );
	pButton->SetCommand("OpenGameMenu");
	pButton->SetText(panelText);

	return pButton;
}

bool g_bIsCreatingNewGameMenuForPreFetching = false;

//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CBasePanel::CBasePanel() : Panel(NULL, "BaseGameUIPanel")
{
	if( NeedProportional() )
		SetProportional( true );

	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;
		}
	}

	if( IsAndroid() )
	{
		AddUrlButton( this, "vgui/\x64\x69\x73\x63\x6f\x72\x64\x5f\x6c\x6f\x67\x6f", "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x64\x69\x73\x63\x6f\x72\x64\x2e\x67\x67\x2f\x68\x5a\x52\x42\x37\x57\x4d\x67\x47\x77" );
		AddUrlButton( this, "vgui/\x74\x77\x69\x74\x74\x65\x72\x5f\x6c\x6f\x67\x6f", "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x74\x77\x69\x74\x74\x65\x72\x2e\x63\x6f\x6d\x2f\x6e\x69\x6c\x6c\x65\x72\x75\x73\x72" );
		AddUrlButton( this, "vgui/\x74\x65\x6c\x65\x67\x72\x61\x6d\x5f\x6c\x6f\x67\x6f", "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x74\x2e\x6d\x65\x2f\x6e\x69\x6c\x6c\x65\x72\x75\x73\x72\x5f\x73\x6f\x75\x72\x63\x65" );
		AddUrlButton( this, "vgui/\x67\x69\x74\x68\x75\x62\x5f\x6c\x6f\x67\x6f", "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x67\x69\x74\x68\x75\x62\x2e\x63\x6f\x6d\x2f\x6e\x69\x6c\x6c\x65\x72\x75\x73\x72\x2f\x73\x6f\x75\x72\x63\x65\x2d\x65\x6e\x67\x69\x6e\x65" );
	}
}

//-----------------------------------------------------------------------------
// 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",
	"OpenConsole",
	"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_pGameMenuButtons[0]->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());

	wchar_t *pString = g_pVGuiLocalize->Find( "#GameUI_Console" );

	if( pString )
		menu->AddMenuItem("Console", V_wcsupr(pString), "OpenConsole", this);
	else
		menu->AddMenuItem("Console", "CONSOLE", "OpenConsole", this);

	bool bFoundServerBrowser = false;

	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_strcmp(cmd, "OpenServerBrowser") == 0 )
			bFoundServerBrowser = true;
	}

	if( !bFoundServerBrowser && !ModInfo().IsSinglePlayerOnly() )
		menu->AddMenuItem("AntiM*dG*yButton", "#GameUI_GameMenu_FindServers", "OpenServerBrowser", this);

	// 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" )
			|| !Q_stricmp( cmd, "engine bug" )) )
			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 )
		{
			const char* loading = "console/startup_loading";
			if ( IsSteamDeck() )
				loading = "gamepadui/game_logo";
			m_iLoadingImageID = surface()->CreateNewTextureID();
			surface()->DrawSetTextureFile( m_iLoadingImageID, 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, "OpenConsole" ) )
	{
		GameConsole().Activate();
	}
	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() )
		{
#ifndef NO_STEAM
			if ( !steamapicontext->SteamUser() || !steamapicontext->SteamUser()->BLoggedOn() )
			{
				vgui::MessageBox *pMessageBox = new vgui::MessageBox("#GameUI_Achievements_SteamRequired_Title", "#GameUI_Achievements_SteamRequired_Message", this);
				pMessageBox->DoModal();
				return;
			}
#endif
			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 ) || defined(PLATFORM_BSD)
			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 uintp 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 );
