You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1524 lines
44 KiB
1524 lines
44 KiB
//========= 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; |
|
} |
|
|
|
|