summaryrefslogtreecommitdiff
path: root/gameui/matchmaking/dialogmenu.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /gameui/matchmaking/dialogmenu.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'gameui/matchmaking/dialogmenu.cpp')
-rw-r--r--gameui/matchmaking/dialogmenu.cpp1524
1 files changed, 1524 insertions, 0 deletions
diff --git a/gameui/matchmaking/dialogmenu.cpp b/gameui/matchmaking/dialogmenu.cpp
new file mode 100644
index 0000000..e46888b
--- /dev/null
+++ b/gameui/matchmaking/dialogmenu.cpp
@@ -0,0 +1,1524 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Multi-purpose menu for matchmaking dialogs, navigable with the xbox controller.
+//
+//=============================================================================//
+
+#include "engine/imatchmaking.h"
+#include "GameUI_Interface.h"
+#include "vgui_controls/Label.h"
+#include "vgui_controls/ImagePanel.h"
+#include "vgui/ILocalize.h"
+#include "vgui/ISurface.h"
+#include "KeyValues.h"
+#include "dialogmenu.h"
+#include "BasePanel.h"
+#include "vgui_controls/ImagePanel.h"
+#include "iachievementmgr.h" // for iachievement abstract class in CAchievementItem
+#include "achievementsdialog.h" // for helper functions used by both pc and xbox achievements
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+//-----------------------------------------------------------------------
+// Base class representing a generic menu item. Supports two text labels,
+// where the first label is the "action" text and the second is an optional
+// description of the action.
+//-----------------------------------------------------------------------
+CMenuItem::CMenuItem( CDialogMenu *pParent, const char *pTitle, const char *pDescription )
+ : BaseClass( pParent, "MenuItem" )
+{
+ // Quiet "parent not sized yet" spew
+ SetSize( 10, 10 );
+
+ m_pParent = pParent;
+
+ m_bEnabled = true;
+ m_nDisabledAlpha = 30;
+
+ m_pTitle = new vgui::Label( this, "MenuItemText", pTitle );
+ m_pDescription = NULL;
+ if ( pDescription )
+ {
+ m_pDescription = new vgui::Label( this, "MenuItemDesc", pDescription );
+ }
+}
+
+CMenuItem::~CMenuItem()
+{
+ delete m_pTitle;
+ delete m_pDescription;
+}
+
+//-----------------------------------------------------------------------
+// Update colors according to enabled/disabled state
+//-----------------------------------------------------------------------
+void CMenuItem::PerformLayout()
+{
+ BaseClass::PerformLayout();
+}
+
+//-----------------------------------------------------------------------
+// Setup margins and calculate the total menu item size
+//-----------------------------------------------------------------------
+void CMenuItem::ApplySettings( KeyValues *pSettings )
+{
+ BaseClass::ApplySettings( pSettings );
+
+ m_nBottomMargin = pSettings->GetInt( "bottommargin", 0 );
+ m_nRightMargin = pSettings->GetInt( "rightmargin", 0 );
+
+ int x, y;
+ m_pTitle->GetPos( x, y );
+ m_pTitle->SizeToContents();
+
+ int bgTall = y + m_pTitle->GetTall() + m_nBottomMargin;
+ int textWide = m_pTitle->GetWide();
+
+ if ( m_pDescription )
+ {
+ m_pDescription->SizeToContents();
+ m_pDescription->GetPos( x, y );
+ bgTall = y + m_pDescription->GetTall() + m_nBottomMargin;
+ textWide = max( textWide, m_pDescription->GetWide() );
+ }
+
+ int bgWide = x + textWide + m_nRightMargin;
+
+ SetSize( bgWide, bgTall );
+}
+
+//-----------------------------------------------------------------------
+// Setup colors and fonts
+//-----------------------------------------------------------------------
+void CMenuItem::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ SetPaintBackgroundType( 2 );
+
+ m_BgColor = pScheme->GetColor( "MatchmakingMenuItemBackground", Color( 46, 43, 42, 255 ) );
+ m_BgColorActive = pScheme->GetColor( "MatchmakingMenuItemBackgroundActive", Color( 150, 71, 0, 255 ) );
+
+ m_pTitle->SetFgColor( pScheme->GetColor( "MatchmakingMenuItemTitleColor", Color( 0, 0, 0, 255 ) ) );
+
+ if ( m_pDescription )
+ {
+ m_pDescription->SetFgColor( pScheme->GetColor( "MatchmakingMenuItemDescriptionColor", Color( 0, 0, 0, 255 ) ) );
+ }
+
+ KeyValues *pKeys = BasePanel()->GetConsoleControlSettings()->FindKey( "MenuItem.res" );
+ ApplySettings( pKeys );
+}
+
+//-----------------------------------------------------------------------
+// Set an item as having input focus
+//-----------------------------------------------------------------------
+void CMenuItem::SetFocus( const bool bActive )
+{
+ if ( bActive )
+ {
+ SetBgColor( m_BgColorActive );
+ }
+ else
+ {
+ SetBgColor( m_BgColor );
+ }
+}
+
+//-----------------------------------------------------------------------
+// Set an item as having input focus
+//-----------------------------------------------------------------------
+void CMenuItem::SetEnabled( bool bEnabled )
+{
+ if ( bEnabled )
+ {
+ SetAlpha( 255 );
+ }
+ else
+ {
+ SetAlpha( m_nDisabledAlpha );
+ }
+ m_bEnabled = bEnabled;
+}
+
+//-----------------------------------------------------------------------
+// Set a column as having focus
+//-----------------------------------------------------------------------
+void CMenuItem::SetActiveColumn( int col )
+{
+ // do nothing
+}
+
+//-----------------------------------------------------------------------
+// Set an item as having input focus
+//-----------------------------------------------------------------------
+bool CMenuItem::IsEnabled()
+{
+ return m_bEnabled;
+}
+
+//-----------------------------------------------------------------------
+// Perform any special actions when an item is "clicked"
+//-----------------------------------------------------------------------
+void CMenuItem::OnClick()
+{
+ // do nothing - derived classes implement this
+}
+
+
+//-----------------------------------------------------------------------
+// CCommandItem
+//
+// Menu item that issues a command when clicked.
+//-----------------------------------------------------------------------
+CCommandItem::CCommandItem( CDialogMenu *pParent, const char *pTitleLabel, const char *pDescLabel, const char *pCommand )
+ : BaseClass( pParent, pTitleLabel, pDescLabel )
+{
+ Q_strncpy( m_szCommand, pCommand, MAX_COMMAND_LEN );
+}
+
+CCommandItem::~CCommandItem()
+{
+ // do nothing
+}
+
+void CCommandItem::OnClick()
+{
+ GetParent()->OnCommand( m_szCommand );
+
+ vgui::surface()->PlaySound( "UI/buttonclick.wav" );
+}
+
+void CCommandItem::SetFocus(const bool bActive )
+{
+ BaseClass::SetFocus( bActive );
+
+ if ( bActive == true && m_bHasFocus == false )
+ {
+ vgui::surface()->PlaySound( "UI/buttonclickrelease.wav" );
+ }
+
+ m_bHasFocus = bActive;
+}
+
+
+//-----------------------------------------------------------------------
+// CPlayerItem
+//
+// Menu item to display a player in the lobby.
+//-----------------------------------------------------------------------
+CPlayerItem::CPlayerItem( CDialogMenu *pParent, const char *pTitleLabel, int64 nId, byte bVoice, bool bReady )
+: BaseClass( pParent, pTitleLabel, NULL, "ShowGamerCard" )
+{
+ m_pVoiceIcon = new vgui::Label( this, "voiceicon", "" );
+ m_pReadyIcon = new vgui::Label( this, "readyicon", "" );
+
+ m_nId = nId;
+ m_bVoice = bVoice;
+ m_bReady = bReady;
+}
+
+CPlayerItem::~CPlayerItem()
+{
+ delete m_pVoiceIcon;
+ delete m_pReadyIcon;
+}
+
+void CPlayerItem::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ const char *pVoice = "";
+
+ if ( m_bVoice == 2 )
+ {
+ pVoice = "#TF_Icon_Voice";
+ }
+ else if ( m_bVoice == 1 )
+ {
+ pVoice = "#TF_Icon_Voice_Idle";
+ }
+
+ m_pVoiceIcon->SetText( pVoice );
+ m_pReadyIcon->SetText( m_bReady ? "#TF_Icon_Ready" : "#TF_Icon_NotReady" );
+
+ int x, y;
+ m_pReadyIcon->GetPos( x, y );
+ m_pReadyIcon->SetPos( GetWide() - m_pReadyIcon->GetWide() - m_nRightMargin, y );
+}
+
+void CPlayerItem::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ KeyValues *pKeys = BasePanel()->GetConsoleControlSettings()->FindKey( "PlayerItem.res" );
+ ApplySettings( pKeys );
+}
+
+void CPlayerItem::OnClick()
+{
+ BaseClass::OnClick();
+}
+
+//-----------------------------------------------------------------------
+// CBrowserItem
+//
+// Menu item used to display session search results.
+//-----------------------------------------------------------------------
+CBrowserItem::CBrowserItem( CDialogMenu *pParent, const char *pHost, const char *pPlayers, const char *pScenario, const char *pPing )
+ : BaseClass( pParent, pHost, NULL, "SelectSession" )
+{
+ m_pPlayers = new vgui::Label( this, "players", pPlayers );
+ m_pScenario = new vgui::Label( this, "scenario", pScenario );
+ m_pPing = new vgui::Label( this, "ping", pPing );
+}
+
+CBrowserItem::~CBrowserItem()
+{
+ delete m_pPlayers;
+ delete m_pScenario;
+ delete m_pPing;
+}
+
+void CBrowserItem::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ int x, y, wide, tall;
+ m_pPing->GetBounds( x, y, wide, tall );
+
+ m_pScenario->SizeToContents();
+ int sx, sy;
+ m_pScenario->GetPos( sx, sy );
+ m_pScenario->SetPos( x - m_pScenario->GetWide() - m_nRightMargin, sy );
+
+ SetSize( x + wide, GetTall() );
+}
+
+void CBrowserItem::ApplySettings( KeyValues *pSettings )
+{
+ BaseClass::ApplySettings( pSettings );
+}
+
+void CBrowserItem::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ Color fgcolor = pScheme->GetColor( "MatchmakingMenuItemDescriptionColor", Color( 64, 64, 64, 255 ) );
+ m_pPlayers->SetFgColor( fgcolor );
+ m_pScenario->SetFgColor( fgcolor );
+
+ m_pPing->SetContentAlignment( vgui::Label::a_center );
+
+ KeyValues *pKeys = BasePanel()->GetConsoleControlSettings()->FindKey( "BrowserItem.res" );
+ ApplySettings( pKeys );
+
+ SetFocus( false );
+}
+
+//-----------------------------------------------------------------------
+// COptionsItem
+//
+// Menu item used to present a list of options for the player to select
+// from, such as "choose a map" or "number of rounds".
+//-----------------------------------------------------------------------
+COptionsItem::COptionsItem( CDialogMenu *pParent, const char *pLabel )
+ : BaseClass( pParent, pLabel, NULL )
+{
+ m_nActiveOption = m_Options.InvalidIndex();
+ m_nOptionsXPos = 0;
+ m_nMaxOptionWidth = 0;
+
+ m_szOptionsFont[0] = '\0';
+ m_hOptionsFont = vgui::INVALID_FONT;
+
+ m_pLeftArrow = new vgui::Label( this, "LeftArrow", "" );
+ m_pRightArrow = new vgui::Label( this, "RightArrow", "" );
+}
+
+COptionsItem::~COptionsItem()
+{
+ m_OptionLabels.PurgeAndDeleteElements();
+
+ delete m_pLeftArrow;
+ delete m_pRightArrow;
+}
+
+void COptionsItem::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ int optionWide = max( m_nOptionsMinWide, GetWide() - m_nOptionsXPos - m_pRightArrow->GetWide() - m_nOptionsLeftMargin );
+ int optionTall = GetTall();
+
+ for ( int i = 0; i < m_OptionLabels.Count(); ++i )
+ {
+ vgui::Label *pOption = m_OptionLabels[i];
+
+ pOption->SetBounds( m_nOptionsXPos, 0, optionWide, optionTall );
+ }
+
+ int lx, ly;
+ m_pLeftArrow->GetPos( lx, ly );
+ m_pLeftArrow->SetPos( m_nOptionsXPos - m_nArrowGap - m_pLeftArrow->GetWide(), ly );
+
+ int rx, ry;
+ m_pRightArrow->GetPos( rx, ry );
+ m_pRightArrow->SetPos( m_nOptionsXPos + optionWide + m_nArrowGap, ry );
+
+ m_pLeftArrow->SetAlpha( 255 );
+ m_pRightArrow->SetAlpha( 255 );
+
+ if ( m_nActiveOption == 0 )
+ {
+ m_pLeftArrow->SetAlpha( 32 );
+ }
+ else if ( m_nActiveOption == m_OptionLabels.Count() - 1 )
+ {
+ m_pRightArrow->SetAlpha( 32 );
+ }
+}
+
+void COptionsItem::ApplySettings( KeyValues *pSettings )
+{
+ BaseClass::ApplySettings( pSettings );
+
+ m_nOptionsXPos = pSettings->GetInt( "optionsxpos", 0 );
+ m_nOptionsMinWide = pSettings->GetInt( "optionsminwide", 0 );
+ m_nOptionsLeftMargin = pSettings->GetInt( "optionsleftmargin", 0 );
+ m_nArrowGap = pSettings->GetInt( "arrowgap", 0 );
+
+ Q_strncpy( m_szOptionsFont, pSettings->GetString( "optionsfont", "Default" ), sizeof( m_szOptionsFont ) );
+}
+
+void COptionsItem::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+ SetPaintBackgroundEnabled( false );
+
+ m_pTitle->SetFgColor( pScheme->GetColor( "MatchmakingMenuItemTitleColor", Color( 200, 184, 151, 255 ) ) );
+
+ KeyValues *pKeys = BasePanel()->GetConsoleControlSettings()->FindKey( "OptionsItem.res" );
+ ApplySettings( pKeys );
+
+ m_hOptionsFont = pScheme->GetFont( m_szOptionsFont );
+}
+
+void COptionsItem::SetFocus( const bool bActive )
+{
+ if ( bActive )
+ {
+ for ( int i = 0; i < m_OptionLabels.Count(); ++i )
+ {
+ m_OptionLabels[i]->SetBgColor( m_BgColorActive );
+ }
+ }
+ else
+ {
+ for ( int i = 0; i < m_OptionLabels.Count(); ++i )
+ {
+ m_OptionLabels[i]->SetBgColor( m_BgColor );
+ }
+ }
+}
+
+void COptionsItem::AddOption( const char *pLabelText, const sessionProperty_t& option )
+{
+ // Add a new option to this item's list of options
+ m_Options.AddToTail( option );
+
+ int idx = m_OptionLabels.AddToTail( new vgui::Label( this, "Option Value", pLabelText ) );
+ vgui::Label *pOption = m_OptionLabels[idx];
+
+ // Check for a format string
+ if ( Q_stristr( pLabelText, "Fmt" ) )
+ {
+ wchar_t wszString[64];
+ wchar_t wzNumber[8];
+ wchar_t *wzFmt = g_pVGuiLocalize->Find( pLabelText );
+ g_pVGuiLocalize->ConvertANSIToUnicode( option.szValue, wzNumber, sizeof( wzNumber ) );
+ g_pVGuiLocalize->ConstructString( wszString, sizeof( wszString ), wzFmt, 1, wzNumber );
+ pOption->SetText( wszString );
+ }
+
+ SETUP_PANEL( pOption );
+ pOption->SetPaintBackgroundType( 2 );
+
+ pOption->SetFont( m_hOptionsFont );
+ pOption->SetBgColor( Color( 46, 43, 42, 255 ) );
+ pOption->SetFgColor( m_pTitle ? m_pTitle->GetFgColor() : Color( 200, 184, 151, 255 ) );
+ pOption->SetTextInset( m_nOptionsLeftMargin, 0 );
+ pOption->SetContentAlignment( vgui::Label::a_southwest );
+ pOption->SizeToContents();
+
+ int wide = max( m_nOptionsMinWide, pOption->GetWide() );
+ pOption->SetBounds( m_nOptionsXPos, 0, wide, GetTall() );
+ m_nMaxOptionWidth = max( wide, m_nMaxOptionWidth );
+
+ SetWide( m_nOptionsXPos + m_nMaxOptionWidth + m_nOptionsLeftMargin * 2 + m_nArrowGap * 2 + m_pRightArrow->GetWide() );
+}
+
+//-----------------------------------------------------------------------
+// Return the session property associated with the current active option
+//-----------------------------------------------------------------------
+const sessionProperty_t &COptionsItem::GetActiveOption()
+{
+ return m_Options[m_nActiveOption];
+}
+
+//-----------------------------------------------------------------------
+// Return the index of the current active option
+//-----------------------------------------------------------------------
+int COptionsItem::GetActiveOptionIndex()
+{
+ return m_nActiveOption;
+}
+
+//-----------------------------------------------------------------------
+// Sets which option currently has focus
+//-----------------------------------------------------------------------
+void COptionsItem::SetOptionFocus( unsigned int idx )
+{
+ unsigned int itemCt = (unsigned int)m_OptionLabels.Count();
+ if ( idx > itemCt )
+ return;
+
+ m_nActiveOption = idx;
+
+ for ( unsigned int i = 0; i < itemCt; ++i )
+ {
+ vgui::Label *pLabel = m_OptionLabels[i];
+
+ const bool bVisible = ( i == idx );
+ pLabel->SetVisible( bVisible );
+ }
+
+ InvalidateLayout();
+}
+
+//-----------------------------------------------------------------------
+// Move focus to the next option - does not wrap
+//-----------------------------------------------------------------------
+void COptionsItem::SetOptionFocusNext()
+{
+ if ( m_nActiveOption + 1 < m_OptionLabels.Count() )
+ {
+ SetOptionFocus( m_nActiveOption + 1 );
+ }
+ else
+ {
+ vgui::surface()->PlaySound( "player/suit_denydevice.wav" );
+ }
+}
+
+//-----------------------------------------------------------------------
+// Move focus to the previous option - does not wrap
+//-----------------------------------------------------------------------
+void COptionsItem::SetOptionFocusPrev()
+{
+ if ( m_nActiveOption > 0 )
+ {
+ SetOptionFocus( m_nActiveOption - 1 );
+ }
+ else
+ {
+ vgui::surface()->PlaySound( "player/suit_denydevice.wav" );
+ }
+}
+
+
+//-----------------------------------------------------------------------
+// CAchievementItem
+//
+// Menu item used to present an achievement - including image, title,
+// description, points and unlock date. Clicking the item opens another
+// dialog with additional information about the achievement.
+//-----------------------------------------------------------------------
+CAchievementItem::CAchievementItem( CDialogMenu *pParent, const wchar_t *pName, const wchar_t *pDesc, uint points, bool bUnlocked, IAchievement* pSourceAchievement )
+ : BaseClass( pParent, "", "" )
+{
+ // Title and description were returned as results of a system query,
+ // and are therefore already localized.
+ m_pTitle->SetText( pName );
+
+ if ( IsX360() )
+ {
+ wchar_t buf[120];
+
+ // Get the screen size
+ int wide, tall;
+ vgui::surface()->GetScreenSize(wide, tall);
+
+ unsigned int iWrapLen;
+
+ if ( tall <= 480 )
+ {
+ iWrapLen = 50;
+ }
+ else
+ {
+ iWrapLen = 65;
+ }
+
+ // let's do some wrapping on this label
+ wcsncpy( buf, pDesc, sizeof(buf) / sizeof( wchar_t ) );
+
+ if ( wcslen(buf) > iWrapLen )
+ {
+ int iPos = iWrapLen;
+
+ while ( iPos > 0 && buf[iPos] != L' ' )
+ {
+ iPos--;
+ }
+
+ if ( iPos > 0 && buf[iPos] == L' ' )
+ {
+ buf[iPos] = L'\n';
+ }
+ }
+
+ m_pDescription->SetText( buf );
+ }
+ else
+ {
+ m_pDescription->SetText( pDesc );
+ }
+
+ m_pSourceAchievement = pSourceAchievement;
+
+ m_pPercentageBarBackground = SETUP_PANEL( new vgui::ImagePanel( this, "PercentageBarBackground" ) );
+ m_pPercentageBar = SETUP_PANEL( new vgui::ImagePanel( this, "PercentageBar" ) );
+ m_pPercentageText = SETUP_PANEL( new vgui::Label( this, "PercentageText", "" ) );
+
+ // Set the status icons
+ m_pLockedIcon = SETUP_PANEL( new vgui::ImagePanel( this, "lockedicon" ) );
+ m_pUnlockedIcon = SETUP_PANEL( new vgui::ImagePanel( this, "unlockedicon" ) );
+
+ // Gamerscore number
+ if ( IsX360() )
+ {
+ wchar_t *wzFormat = g_pVGuiLocalize->Find( "#GameUI_Achievement_Points" ); // "%s1G"
+ wchar_t wzPoints[10];
+ V_snwprintf( wzPoints, ARRAYSIZE( wzPoints ), L"%d", points );
+ wchar_t wzPointsLayout[10];
+ g_pVGuiLocalize->ConstructString( wzPointsLayout, sizeof( wzPointsLayout ), wzFormat, 1, wzPoints );
+ m_pPoints = new vgui::Label( this, "Points", wzPointsLayout );
+ }
+
+ // Achievement image
+ m_pImage = new vgui::ImagePanel( this, "icon" );
+}
+
+CAchievementItem::~CAchievementItem()
+{
+ delete m_pImage;
+ delete m_pPoints;
+ delete m_pLockedIcon;
+ delete m_pUnlockedIcon;
+ delete m_pPercentageBarBackground;
+ delete m_pPercentageBar;
+ delete m_pPercentageText;
+}
+
+void CAchievementItem::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ int x, y;
+
+ m_pPoints->SizeToContents();
+ m_pPoints->GetPos( x, y );
+ x = GetWide() - m_pPoints->GetWide() - m_nRightMargin;
+ m_pPoints->SetPos( x, y );
+
+}
+
+void CAchievementItem::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ KeyValues*pKeys = BasePanel()->GetConsoleControlSettings()->FindKey( "AchievementItem.res" );
+ ApplySettings( pKeys );
+
+ m_pImage->SetBgColor( Color( 32, 32, 32, 255 ) );
+ m_pImage->SetFgColor( Color( 32, 32, 32, 255 ) );
+ m_pImage->SetPaintBackgroundEnabled( true );
+
+ m_pPoints->SetFgColor( pScheme->GetColor( "MatchmakingMenuItemDescriptionColor", Color( 64, 64, 64, 255 ) ) );
+
+ // Set icon image
+ LoadAchievementIcon( m_pImage, m_pSourceAchievement );
+
+ // Percentage completion bar (for progressive achievements)
+ UpdateProgressBar( this, m_pSourceAchievement, m_clrProgressBar );
+
+ if ( m_pSourceAchievement && m_pSourceAchievement->IsAchieved() )
+ {
+ m_pLockedIcon->SetVisible( false );
+ m_pUnlockedIcon->SetVisible ( true );
+ m_pImage->SetVisible( true );
+ }
+ else
+ {
+ m_pLockedIcon->SetVisible( true );
+ m_pUnlockedIcon->SetVisible( false );
+ m_pImage->SetVisible( false );
+ }
+}
+
+//-----------------------------------------------------------------------
+// CSectionedItem
+//
+// Menu item used to display some number of data entries, which are arranged
+// into columns. Supports scrolling through columns horizontally with the
+// ability to "lock" columns so they don't scroll
+//-----------------------------------------------------------------------
+CSectionedItem::CSectionedItem( CDialogMenu *pParent, const char **ppEntries, int ct )
+ : BaseClass( pParent, "", NULL, "SelectSession" )
+{
+ m_bHeader = false;
+ for ( int i = 0; i < ct; ++i )
+ {
+ AddSection( ppEntries[i], m_pParent->GetColumnAlignment( i ) );
+ }
+}
+
+CSectionedItem::~CSectionedItem()
+{
+ ClearSections();
+}
+
+void CSectionedItem::ClearSections()
+{
+ for ( int i = 0; i < m_Sections.Count(); ++i )
+ {
+ section_s &sec = m_Sections[i];
+ delete sec.pLabel;
+ }
+}
+
+void CSectionedItem::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ int tall = GetTall();
+ for ( int i = 0; i < m_Sections.Count(); ++i )
+ {
+ vgui::Label *pLabel = m_Sections[i].pLabel;
+ if ( !m_bHeader )
+ {
+ pLabel->SetFont( m_pParent->GetColumnFont(i) );
+ pLabel->SetFgColor( m_pParent->GetColumnColor(i) );
+ }
+ pLabel->SetBounds( m_pParent->GetColumnXPos(i), 0, m_pParent->GetColumnWide(i), tall );
+ pLabel->SetTextInset( 10, m_bHeader ? 5 : m_pParent->GetColumnYPos(i) ); // only use ypos for the y-inset if we're not a header
+ }
+}
+
+void CSectionedItem::ApplySettings( KeyValues *pResourceData )
+{
+ BaseClass::ApplySettings( pResourceData );
+}
+
+void CSectionedItem::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ KeyValues *pKeys = BasePanel()->GetConsoleControlSettings()->FindKey( "SectionedItem.res" );
+ ApplySettings( pKeys );
+
+ int iLast = m_Sections.Count() -1;
+ SetWide( m_pParent->GetColumnXPos(iLast) + m_pParent->GetColumnWide(iLast) );
+}
+
+void CSectionedItem::AddSection( const char *pText, int align )
+{
+ section_s sec;
+ sec.pLabel = new vgui::Label( this, "Section", pText );
+ SETUP_PANEL( sec.pLabel );
+ sec.pLabel->SetContentAlignment( (vgui::Label::Alignment)align );
+ sec.pLabel->SetTextInset( 10, 0 );
+ sec.pLabel->SetBgColor( Color( 209, 112, 52, 128 ) );
+ m_Sections.AddToTail( sec );
+}
+
+void CSectionedItem::SetActiveColumn( int col )
+{
+ for ( int i = 0; i < m_Sections.Count(); ++i )
+ {
+ m_Sections[i].pLabel->SetPaintBackgroundEnabled( i == col );
+ }
+}
+
+//--------------------------------------------------------------------------------------
+// Generic menu for Xbox 360 matchmaking dialogs. Contains a list of CMenuItems arranged
+// vertically. The user can navigate the list using the controller and click on any
+// item. A clicked item may send a command to the dialog and the dialog responds accordingly.
+//--------------------------------------------------------------------------------------
+CDialogMenu::CDialogMenu() : BaseClass( NULL, "DialogMenu" )
+{
+ // Quiet "parent not sized yet" spew
+ SetSize( 100, 100 );
+
+ m_pParent = NULL;
+ m_pHeader = NULL;
+ m_bUseFilter = false;
+ m_bHasHeader = false;
+ m_nItemSpacing = 0;
+ m_nMinWide = 0;
+ m_nActive = -1;
+ m_nActiveColumn = -1;
+ m_nBaseRowIdx = 0;
+ m_nBaseColumnIdx = 0;
+ m_iUnlocked = 0;
+ m_nMaxVisibleItems = 1000; // arbitrarily large
+ m_nMaxVisibleColumns = 1000;// arbitrarily large
+}
+
+CDialogMenu::~CDialogMenu()
+{
+ m_MenuItems.PurgeAndDeleteElements();
+ delete m_pHeader;
+}
+
+void CDialogMenu::SetParent( CBaseDialog *pParent )
+{
+ BaseClass::SetParent( pParent );
+ m_pParent = pParent;
+}
+
+//--------------------------------------------------------------------------------------
+// Set a filter to use when reading in menu item keyvalues
+//--------------------------------------------------------------------------------------
+void CDialogMenu::SetFilter( const char *pFilter )
+{
+ if ( pFilter )
+ {
+ Q_strncpy( m_szFilter, pFilter, sizeof( m_szFilter ) );
+ m_bUseFilter = true;
+ }
+ else
+ {
+ m_bUseFilter = false;
+ }
+}
+
+//--------------------------------------------------------------------------------------
+// Add a new menu item to the item array
+//--------------------------------------------------------------------------------------
+CMenuItem *CDialogMenu::AddItemInternal( CMenuItem *pItem )
+{
+ int idx = m_MenuItems.AddToTail( pItem );
+
+ SETUP_PANEL( pItem );
+
+ return m_MenuItems[idx];
+}
+
+//--------------------------------------------------------------------------------------
+// Add a new menu item of some type that derives from CMenuItem
+//--------------------------------------------------------------------------------------
+CCommandItem *CDialogMenu::AddCommandItem( const char *pTitleLabel, const char *pDescLabel, const char *pCommand )
+{
+ return (CCommandItem*)AddItemInternal( new CCommandItem( this, pTitleLabel, pDescLabel, pCommand ) );
+}
+
+CBrowserItem *CDialogMenu::AddBrowserItem( const char *pHost, const char *pPlayers, const char *pScenario, const char *pPing )
+{
+ // Results are added to the menu at runtime, so the layout needs to be updated after each addition.
+ CBrowserItem *pItem = (CBrowserItem*)AddItemInternal( new CBrowserItem( this, pHost, pPlayers, pScenario, pPing ) );
+ PerformLayout();
+ return pItem;
+}
+
+COptionsItem *CDialogMenu::AddOptionsItem( const char *pLabel )
+{
+ return (COptionsItem*)AddItemInternal( new COptionsItem( this, pLabel ) );
+}
+
+CAchievementItem *CDialogMenu::AddAchievementItem( const wchar_t *pName, const wchar_t *pDesc, uint points, bool bUnlocked, IAchievement* pSourceAchievement )
+{
+ return (CAchievementItem*)AddItemInternal( new CAchievementItem( this, pName, pDesc, points, bUnlocked, pSourceAchievement ) );
+}
+
+CSectionedItem *CDialogMenu::AddSectionedItem( const char **ppEntries, int ct )
+{
+ CSectionedItem *pItem = (CSectionedItem*)AddItemInternal( new CSectionedItem( this, ppEntries, ct ) );
+ PerformLayout();
+ return pItem;
+}
+
+CPlayerItem *CDialogMenu::AddPlayerItem( const char *pTitleLabel, int64 nId, byte bVoice, bool bReady )
+{
+ // Players are added to the lobby at runtime, so the layout needs to be updated after each addition.
+ CPlayerItem *pItem = (CPlayerItem*)AddItemInternal( new CPlayerItem( this, pTitleLabel, nId, bVoice, bReady ) );
+ PerformLayout();
+ return pItem;
+}
+
+void CDialogMenu::RemovePlayerItem( int idx )
+{
+ delete m_MenuItems[idx];
+ m_MenuItems.Remove( idx );
+ PerformLayout();
+}
+
+void CDialogMenu::ClearItems()
+{
+ m_MenuItems.PurgeAndDeleteElements();
+ InvalidateLayout();
+}
+
+//--------------------------------------------------------------------------------------
+// Set the size an position of all the menu items
+//--------------------------------------------------------------------------------------
+void CDialogMenu::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ // Position the menu items and set their width
+ int yPos = 0;
+ int wide = GetWide();
+
+ if ( m_bHasHeader )
+ {
+ yPos = 40;
+ m_pHeader->SetPos( 0, 0 );
+ m_pHeader->SetWide( wide );
+ m_pHeader->PerformLayout();
+ }
+
+ for ( int i = 0; i < m_MenuItems.Count(); ++i )
+ {
+ CMenuItem *pItem = m_MenuItems[i];
+
+ pItem->SetPos( 0, yPos );
+ pItem->SetWide( wide );
+ pItem->SetActiveColumn( m_nActiveColumn );
+ pItem->PerformLayout();
+
+ if ( i < m_nBaseRowIdx || i > m_nBaseRowIdx + m_nMaxVisibleItems - 1 )
+ {
+ pItem->SetVisible( false );
+ }
+ else
+ {
+ pItem->SetVisible( true );
+ yPos += pItem->GetTall() + m_nItemSpacing;
+ }
+ }
+
+ // Reset the focus to update background colors of all menu items
+ SetFocus( m_nActive );
+
+
+ SetTall( yPos );
+}
+
+//--------------------------------------------------------------------------------------
+// Parse the res file for menu items to build out the dialog menu.
+//--------------------------------------------------------------------------------------
+void CDialogMenu::ApplySettings( KeyValues *pResourceData )
+{
+ BaseClass::ApplySettings( pResourceData );
+
+ m_nItemSpacing = pResourceData->GetInt( "itemspacing", 2 );
+ m_nMinWide = pResourceData->GetInt( "minwide", 0 );
+ m_nActiveColumn = pResourceData->GetInt( "activecolumn", -1 );
+ m_nMaxVisibleItems = pResourceData->GetInt( "maxvisibleitems", 1000 ); // arbitrarily large
+ m_nMaxVisibleColumns = pResourceData->GetInt( "maxvisiblecolumns", 1000 ); // arbitrarily large
+
+ KeyValues *pColumnData = pResourceData->FindKey( "Columns" );
+ if ( pColumnData )
+ {
+ int xPos = 0;
+ int idx = 0;
+ const char *ppHeader[MAX_COLUMNS];
+ for ( KeyValues *pColumn = pColumnData->GetFirstSubKey(); pColumn != NULL; pColumn = pColumn->GetNextKey() )
+ {
+ if ( !Q_stricmp( pColumn->GetName(), "Column" ) )
+ {
+ columninfo_s col;
+ col.bSortDown = true;
+ col.xpos = pColumn->GetInt( "xpos", xPos );
+ col.ypos = pColumn->GetInt( "ypos", 0 );
+ col.wide = pColumn->GetInt( "wide", 0 );
+ col.align = pColumn->GetInt( "align", 3 ); // west by default
+ col.bLocked = pColumn->GetInt( "locked", 0 );
+ col.hFont = m_pScheme->GetFont( pColumn->GetString( "font", "default" ) );
+ col.color = m_pScheme->GetColor( pColumn->GetString( "fgcolor" ), Color( 0, 0, 0, 255 ) );
+
+ ppHeader[idx++] = pColumn->GetString( "header", "" );
+
+ xPos = col.xpos + col.wide;
+ m_Columns.AddToTail( col );
+
+ if ( col.bLocked )
+ {
+ m_nBaseColumnIdx = idx;
+ m_iUnlocked = idx;
+ }
+ }
+ }
+ m_bHasHeader = true;
+ m_pHeader = new CSectionedItem( this, ppHeader, idx );
+ m_pHeader->m_bHeader = true;
+ SETUP_PANEL( m_pHeader );
+
+ m_pHeader->SetPaintBackgroundEnabled( false );
+ vgui::HFont headerFont = m_pScheme->GetFont( pColumnData->GetString( "headerfont", "default" ) );
+ Color headerColor = m_pScheme->GetColor( pColumnData->GetString( "headerfgcolor" ), Color( 0, 0, 0, 255 ) );
+ for ( int i = 0; i < idx; ++i )
+ {
+ vgui::Label *pLabel = m_pHeader->m_Sections[i].pLabel;
+ pLabel->SetFont( headerFont );
+ pLabel->SetFgColor( headerColor );
+ pLabel->SetPaintBackgroundEnabled( false );
+ }
+ }
+
+ for ( KeyValues *pMenuData = pResourceData->GetFirstSubKey(); pMenuData != NULL; pMenuData = pMenuData->GetNextKey() )
+ {
+ // See if we should skip over this block
+ if ( m_bUseFilter )
+ {
+ if ( pMenuData->GetInt( m_szFilter, 0 ) == 0 )
+ continue;
+ }
+
+ // Give our parent a chance to change the properties of this item
+ m_pParent->OverrideMenuItem( pMenuData );
+
+ if ( !Q_stricmp( pMenuData->GetName(), "CommandItem" ) )
+ {
+ // New Command Item
+ const char *label = pMenuData->GetString( "label", "<unknown>" );
+ const char *description = pMenuData->GetString( "description", NULL );
+ const char *command = pMenuData->GetString( "command", "<unknown>" );
+
+ AddCommandItem( label, description, command );
+ }
+ else if ( !Q_stricmp( pMenuData->GetName(), "OptionsItem" ) )
+ {
+ // New Options Item
+ COptionsItem *pItem = AddOptionsItem( pMenuData->GetString( "label", "<unknown>" ) );
+
+ // ID and ValueType and the same for all option values
+ const char *pID = pMenuData->GetString( "id", "NULL" );
+ const char *pValueType = pMenuData->GetString( "valuetype", NULL );
+
+ // Add all the options
+ for ( KeyValues *pValue = pMenuData->GetFirstSubKey(); pValue != NULL; pValue = pValue->GetNextKey() )
+ {
+ if ( !Q_stricmp( pValue->GetName(), "Option" ) )
+ {
+ sessionProperty_t prop;
+ prop.nType = SESSION_CONTEXT;
+ Q_strncpy( prop.szID, pID, sizeof( prop.szID ) );
+ Q_strncpy( prop.szValue, pValue->GetString( "value", "NULL" ), sizeof( prop.szValue ) );
+
+ if ( pValueType )
+ {
+ // Only session properties have a type
+ prop.nType = SESSION_PROPERTY;
+ Q_strncpy( prop.szValueType, pValueType, sizeof( prop.szValueType ) );
+ }
+
+ const char *pLabel = pValue->GetString( "label", "<unknown>" );
+ pItem->AddOption( pLabel, prop );
+ }
+ }
+
+ // Add range items after the specified items
+ if ( pMenuData->GetInt( "userange" ) )
+ {
+ // Options are an implicit range of integers
+ int nStart = pMenuData->GetInt( "rangelow" );
+ int nEnd = pMenuData->GetInt( "rangehigh" );
+ int nInterval = pMenuData->GetInt( "interval", 1 );
+
+ // Prevent total destruction from a bad resource file
+ if ( nEnd < nStart )
+ {
+ nEnd = nStart;
+ }
+
+ for ( int i = nStart; i <= nEnd; i += nInterval )
+ {
+ sessionProperty_t prop;
+ prop.nType = SESSION_PROPERTY;
+ Q_strncpy( prop.szID, pID, sizeof( prop.szID ) );
+ Q_strncpy( prop.szValueType, pValueType, sizeof( prop.szValueType ) );
+ Q_snprintf( prop.szValue, sizeof(prop.szValue), "%d", i );
+
+ pItem->AddOption( prop.szValue, prop );
+ }
+ }
+
+ // Set the default active option
+ int active = pMenuData->GetInt( "activeoption", 0 );
+ pItem->SetOptionFocus( active );
+
+ // Notify our parent that each option has been set to its current setting
+ KeyValues *kv = new KeyValues( "MenuItemChanged", "item", GetItemCount() - 1 );
+ PostActionSignal( kv );
+ }
+ }
+
+ // Calculate the final menu size according to the widest menu item
+ int wide = m_nMinWide;
+ for ( int i = 0; i < m_MenuItems.Count(); ++i )
+ {
+ wide = max( wide, m_MenuItems[i]->GetWide() );
+ }
+ SetWide( wide );
+}
+
+//--------------------------------------------------------------------------------------
+// Cache off the scheme
+//--------------------------------------------------------------------------------------
+void CDialogMenu::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ m_pScheme = pScheme;
+}
+
+//--------------------------------------------------------------------------------------
+// Give focus (highlights) a particular menu item by index
+//--------------------------------------------------------------------------------------
+void CDialogMenu::SetFocus( int idx )
+{
+ int itemCt = (unsigned int)m_MenuItems.Count();
+ if ( idx >= itemCt )
+ return;
+
+ for ( int i = 0; i < itemCt; ++i )
+ {
+ m_MenuItems[i]->SetFocus( i == idx );
+ }
+ m_nActive = idx;
+
+ if ( m_nActive >= 0 && m_nActive < m_nBaseRowIdx )
+ {
+ m_nBaseRowIdx = m_nActive;
+ }
+ else if ( m_nActive > m_nBaseRowIdx + m_nMaxVisibleItems - 1 )
+ {
+ m_nBaseRowIdx = m_nActive - ( m_nMaxVisibleItems - 1 );
+ }
+}
+
+//--------------------------------------------------------------------------------------
+// Sort the menu items according to the selected column
+//--------------------------------------------------------------------------------------
+void CDialogMenu::SortMenuItems()
+{
+ if ( !m_bHasHeader )
+ return;
+
+ // Simple bubble sort
+ char szBufferOne[32];
+ char szBufferTwo[32];
+ bool bSortDown = GetColumnSortType( m_nActiveColumn );
+ for ( int i = 1; i <= m_MenuItems.Count(); ++i )
+ {
+ for ( int j = 0; j < m_MenuItems.Count() - i; ++j )
+ {
+ ((CSectionedItem*)m_MenuItems[j])->m_Sections[m_nActiveColumn].pLabel->GetText( szBufferOne, sizeof( szBufferOne ) );
+ ((CSectionedItem*)m_MenuItems[j+1])->m_Sections[m_nActiveColumn].pLabel->GetText( szBufferTwo, sizeof( szBufferTwo ) );
+
+ int diff = Q_stricmp( szBufferOne, szBufferTwo );
+ bool bSwap = bSortDown ? diff > 0 : diff < 0;
+ if ( bSwap )
+ {
+ CMenuItem *pTemp = m_MenuItems[j+1];
+ m_MenuItems[j+1] = m_MenuItems[j];
+ m_MenuItems[j] = pTemp;
+
+ m_pParent->SwapMenuItems( j, j+1 );
+ }
+ }
+ }
+ InvalidateLayout();
+}
+
+//--------------------------------------------------------------------------------------
+// Move item focus to the next item in the menu - supports wrapping
+//--------------------------------------------------------------------------------------
+void CDialogMenu::SetFocusNext()
+{
+ if ( m_MenuItems.Count() )
+ {
+ int iNewIndex = ( m_nActive + 1 ) % m_MenuItems.Count();
+
+ int i = 0;
+ bool bSet = false;
+ while ( i < m_MenuItems.Count() )
+ {
+ if ( m_MenuItems[iNewIndex]->IsEnabled() )
+ {
+ SetFocus( iNewIndex );
+ bSet = true;
+ break;
+ }
+
+ iNewIndex = ( iNewIndex + 1 ) % m_MenuItems.Count();
+ i++;
+ }
+
+ InvalidateLayout();
+ }
+}
+
+//--------------------------------------------------------------------------------------
+// Move item focus to the previous item in the menu - supports wrapping
+//--------------------------------------------------------------------------------------
+void CDialogMenu::SetFocusPrev()
+{
+ if ( m_MenuItems.Count() )
+ {
+ int iNewIndex = m_nActive - 1;
+ if ( iNewIndex < 0 )
+ iNewIndex = m_MenuItems.Count() - 1;
+
+ int i = 0;
+ bool bSet = false;
+ while ( i < m_MenuItems.Count() )
+ {
+ if ( m_MenuItems[iNewIndex]->IsEnabled() )
+ {
+ SetFocus( iNewIndex );
+ bSet = true;
+ break;
+ }
+
+ if ( --iNewIndex < 0 )
+ iNewIndex = m_MenuItems.Count() - 1;
+
+ i++;
+ }
+
+ InvalidateLayout();
+ }
+}
+
+//--------------------------------------------------------------------------------------
+// For OptionsItems: Move focus to the next option in the menu item - does not wrap
+//--------------------------------------------------------------------------------------
+void CDialogMenu::SetOptionFocusNext()
+{
+ COptionsItem *pItem = dynamic_cast< COptionsItem* >( GetItem( m_nActive ) );
+ if ( pItem )
+ {
+ pItem->SetOptionFocusNext();
+
+ KeyValues *kv = new KeyValues( "MenuItemChanged", "item", m_nActive );
+ PostActionSignal( kv );
+ }
+}
+
+//--------------------------------------------------------------------------------------
+// For OptionsItems: Move focus to the previous option in the menu item - does not wrap
+//--------------------------------------------------------------------------------------
+void CDialogMenu::SetOptionFocusPrev()
+{
+ COptionsItem *pItem = dynamic_cast< COptionsItem* >( GetItem( m_nActive ) );
+ if ( pItem )
+ {
+ pItem->SetOptionFocusPrev();
+
+ KeyValues *kv = new KeyValues( "MenuItemChanged", "item", m_nActive );
+ PostActionSignal( kv );
+ }
+}
+
+//--------------------------------------------------------------------------------------
+// For OptionsItems: Update the base index for the columns
+//--------------------------------------------------------------------------------------
+void CDialogMenu::UpdateBaseColumnIndex()
+{
+ if ( m_iUnlocked + m_nActiveColumn - m_nBaseColumnIdx >= m_nMaxVisibleColumns )
+ {
+ m_nBaseColumnIdx = m_iUnlocked + m_nActiveColumn - m_nMaxVisibleColumns + 1;
+ }
+ else if ( m_nActiveColumn - m_nBaseColumnIdx < 0 )
+ {
+ m_nBaseColumnIdx = m_nActiveColumn;
+ }
+}
+
+//--------------------------------------------------------------------------------------
+// For menus with sectioned columns - move focus to the next column
+//--------------------------------------------------------------------------------------
+void CDialogMenu::SetColumnFocusNext()
+{
+ if ( m_nActiveColumn == -1 )
+ return;
+
+ if ( m_Columns.Count() )
+ {
+ int iNewColumn = m_nActiveColumn + 1;
+ if ( iNewColumn >= m_Columns.Count() )
+ return;
+
+ m_nActiveColumn = iNewColumn;
+ UpdateBaseColumnIndex();
+ InvalidateLayout();
+ }
+}
+
+//--------------------------------------------------------------------------------------
+// For menus with sectioned columns - move focus to the next column
+//--------------------------------------------------------------------------------------
+void CDialogMenu::SetColumnFocusPrev()
+{
+ if ( m_nActiveColumn == -1 )
+ return;
+
+ if ( m_Columns.Count() )
+ {
+ int iNewColumn = m_nActiveColumn - 1;
+ if ( iNewColumn < 0 || m_Columns[iNewColumn].bLocked )
+ return;
+
+ m_nActiveColumn = iNewColumn;
+ UpdateBaseColumnIndex();
+ InvalidateLayout();
+ }
+}
+
+//--------------------------------------------------------------------------------------
+// For OptionsItems: Lets the dialog find out which option is currently selected
+//--------------------------------------------------------------------------------------
+int CDialogMenu::GetActiveOptionIndex( int nMenuItemIdx )
+{
+ int retval = -1;
+ COptionsItem *pItem = dynamic_cast< COptionsItem* >( GetItem( nMenuItemIdx ) );
+ if ( pItem )
+ {
+ retval = pItem->GetActiveOptionIndex();
+ }
+ return retval;
+}
+
+//-----------------------------------------------------------------------
+// Return the index of the current active menu item
+//-----------------------------------------------------------------------
+int CDialogMenu::GetActiveItemIndex()
+{
+ return m_nActive;
+}
+
+//-----------------------------------------------------------------------
+// Return the index of the current active menu column
+//-----------------------------------------------------------------------
+int CDialogMenu::GetActiveColumnIndex()
+{
+ return m_nActiveColumn;
+}
+
+//-----------------------------------------------------------------------
+// Return the number of menu items
+//-----------------------------------------------------------------------
+int CDialogMenu::GetItemCount()
+{
+ return m_MenuItems.Count();
+}
+
+//-----------------------------------------------------------------------
+// Return the number of visible menu items
+//-----------------------------------------------------------------------
+int CDialogMenu::GetVisibleItemCount()
+{
+ return min( GetItemCount(), m_nMaxVisibleItems );
+}
+
+//-----------------------------------------------------------------------
+// Return the number of visible menu columns
+//-----------------------------------------------------------------------
+int CDialogMenu::GetVisibleColumnCount()
+{
+ return m_nMaxVisibleColumns;
+}
+
+//-----------------------------------------------------------------------
+// Return the index of the first unlocked column
+//-----------------------------------------------------------------------
+int CDialogMenu::GetFirstUnlockedColumnIndex()
+{
+ return m_iUnlocked;
+}
+
+//-----------------------------------------------------------------------
+// Return the first visible index in the menu
+//-----------------------------------------------------------------------
+int CDialogMenu::GetBaseRowIndex()
+{
+ return m_nBaseRowIdx;
+}
+
+//-----------------------------------------------------------------------
+// Set the first visible index in the menu
+//-----------------------------------------------------------------------
+void CDialogMenu::SetBaseRowIndex( int idx )
+{
+ m_nBaseRowIdx = idx;
+}
+
+//-----------------------------------------------------------------------
+// Return the specified menu item
+//-----------------------------------------------------------------------
+CMenuItem *CDialogMenu::GetItem( int idx )
+{
+ if ( m_MenuItems.IsValidIndex( idx ) )
+ {
+ return m_MenuItems[idx];
+ }
+ return NULL;
+}
+
+//-----------------------------------------------------------------------
+// Return the specified column xpos
+//-----------------------------------------------------------------------
+int CDialogMenu::GetColumnXPos( int idx )
+{
+ // Compensate for scrolling offsets
+ columninfo_s &col = m_Columns[idx];
+
+ int xpos;
+ if ( col.bLocked )
+ {
+ xpos = m_Columns[idx].xpos;
+ }
+ else
+ {
+ int trueIdx = m_iUnlocked + idx - m_nBaseColumnIdx;
+ if ( trueIdx < m_iUnlocked )
+ {
+ // Put it offscreen
+ xpos = -100 - col.wide;
+ }
+ else
+ {
+ xpos = m_Columns[trueIdx].xpos;
+ }
+ }
+ return xpos;
+}
+
+//-----------------------------------------------------------------------
+// Return the specified column ypos
+//-----------------------------------------------------------------------
+int CDialogMenu::GetColumnYPos( int idx )
+{
+ return m_Columns[idx].ypos;
+}
+
+//-----------------------------------------------------------------------
+// Return the specified column width
+//-----------------------------------------------------------------------
+int CDialogMenu::GetColumnWide( int idx )
+{
+ return m_Columns[idx].wide;
+}
+
+//-----------------------------------------------------------------------
+// Return the specified column alignment
+//-----------------------------------------------------------------------
+int CDialogMenu::GetColumnAlignment( int idx )
+{
+ return m_Columns[idx].align;
+}
+
+//-----------------------------------------------------------------------
+// Return the specified column font
+//-----------------------------------------------------------------------
+HFont CDialogMenu::GetColumnFont( int idx )
+{
+ return m_Columns[idx].hFont;
+}
+
+//-----------------------------------------------------------------------
+// Return the specified column fgcolor
+//-----------------------------------------------------------------------
+Color CDialogMenu::GetColumnColor( int idx )
+{
+ return m_Columns[idx].color;
+}
+
+//-----------------------------------------------------------------------
+// Return the specified column fgcolor
+//-----------------------------------------------------------------------
+bool CDialogMenu::GetColumnSortType( int idx )
+{
+ bool bSortDown = m_Columns[idx].bSortDown;
+ m_Columns[idx].bSortDown = !bSortDown;
+ return bSortDown;
+}
+
+//--------------------------------------------------------------------------------------
+// Receive the command from a clicked menu item and forwards it to the parent dialog
+//--------------------------------------------------------------------------------------
+void CDialogMenu::OnCommand( const char *pCommand )
+{
+ GetParent()->OnCommand( pCommand );
+}
+
+//--------------------------------------------------------------------------------------
+// Update the menu state according to controller input.
+// Returns whether or not the keycode was handled by the menu.
+//--------------------------------------------------------------------------------------
+bool CDialogMenu::HandleKeyCode( vgui::KeyCode code )
+{
+ switch( code )
+ {
+ case KEY_XBUTTON_DOWN:
+ case KEY_XSTICK1_DOWN:
+ case STEAMCONTROLLER_DPAD_DOWN:
+ SetFocusNext();
+ break;
+
+ case KEY_XBUTTON_UP:
+ case KEY_XSTICK1_UP:
+ case STEAMCONTROLLER_DPAD_UP:
+ SetFocusPrev();
+ break;
+
+ case KEY_XBUTTON_LEFT:
+ case KEY_XSTICK1_LEFT:
+ case STEAMCONTROLLER_DPAD_LEFT:
+ SetOptionFocusPrev();
+ SetColumnFocusPrev();
+ break;
+
+ case KEY_XBUTTON_RIGHT:
+ case KEY_XSTICK1_RIGHT:
+ case STEAMCONTROLLER_DPAD_RIGHT:
+ SetOptionFocusNext();
+ SetColumnFocusNext();
+ break;
+
+ case KEY_XBUTTON_A:
+ case STEAMCONTROLLER_A:
+ if ( m_MenuItems.Count() && m_nActive >= 0 )
+ {
+ m_MenuItems[m_nActive]->OnClick();
+ }
+ break;
+
+ case KEY_XBUTTON_Y:
+ case STEAMCONTROLLER_Y:
+ SortMenuItems();
+ break;
+
+ default:
+ // Not handled
+ return false;
+ }
+
+ return true;
+}
+