diff options
Diffstat (limited to 'gameui/matchmaking/dialogmenu.cpp')
| -rw-r--r-- | gameui/matchmaking/dialogmenu.cpp | 1524 |
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; +} + |