Team Fortress 2 Source Code as on 22/4/2020
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

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Multi-purpose menu for matchmaking dialogs, navigable with the xbox controller.
  4. //
  5. //=============================================================================//
  6. #include "engine/imatchmaking.h"
  7. #include "GameUI_Interface.h"
  8. #include "vgui_controls/Label.h"
  9. #include "vgui_controls/ImagePanel.h"
  10. #include "vgui/ILocalize.h"
  11. #include "vgui/ISurface.h"
  12. #include "KeyValues.h"
  13. #include "dialogmenu.h"
  14. #include "BasePanel.h"
  15. #include "vgui_controls/ImagePanel.h"
  16. #include "iachievementmgr.h" // for iachievement abstract class in CAchievementItem
  17. #include "achievementsdialog.h" // for helper functions used by both pc and xbox achievements
  18. // memdbgon must be the last include file in a .cpp file!!!
  19. #include "tier0/memdbgon.h"
  20. //-----------------------------------------------------------------------
  21. // Base class representing a generic menu item. Supports two text labels,
  22. // where the first label is the "action" text and the second is an optional
  23. // description of the action.
  24. //-----------------------------------------------------------------------
  25. CMenuItem::CMenuItem( CDialogMenu *pParent, const char *pTitle, const char *pDescription )
  26. : BaseClass( pParent, "MenuItem" )
  27. {
  28. // Quiet "parent not sized yet" spew
  29. SetSize( 10, 10 );
  30. m_pParent = pParent;
  31. m_bEnabled = true;
  32. m_nDisabledAlpha = 30;
  33. m_pTitle = new vgui::Label( this, "MenuItemText", pTitle );
  34. m_pDescription = NULL;
  35. if ( pDescription )
  36. {
  37. m_pDescription = new vgui::Label( this, "MenuItemDesc", pDescription );
  38. }
  39. }
  40. CMenuItem::~CMenuItem()
  41. {
  42. delete m_pTitle;
  43. delete m_pDescription;
  44. }
  45. //-----------------------------------------------------------------------
  46. // Update colors according to enabled/disabled state
  47. //-----------------------------------------------------------------------
  48. void CMenuItem::PerformLayout()
  49. {
  50. BaseClass::PerformLayout();
  51. }
  52. //-----------------------------------------------------------------------
  53. // Setup margins and calculate the total menu item size
  54. //-----------------------------------------------------------------------
  55. void CMenuItem::ApplySettings( KeyValues *pSettings )
  56. {
  57. BaseClass::ApplySettings( pSettings );
  58. m_nBottomMargin = pSettings->GetInt( "bottommargin", 0 );
  59. m_nRightMargin = pSettings->GetInt( "rightmargin", 0 );
  60. int x, y;
  61. m_pTitle->GetPos( x, y );
  62. m_pTitle->SizeToContents();
  63. int bgTall = y + m_pTitle->GetTall() + m_nBottomMargin;
  64. int textWide = m_pTitle->GetWide();
  65. if ( m_pDescription )
  66. {
  67. m_pDescription->SizeToContents();
  68. m_pDescription->GetPos( x, y );
  69. bgTall = y + m_pDescription->GetTall() + m_nBottomMargin;
  70. textWide = max( textWide, m_pDescription->GetWide() );
  71. }
  72. int bgWide = x + textWide + m_nRightMargin;
  73. SetSize( bgWide, bgTall );
  74. }
  75. //-----------------------------------------------------------------------
  76. // Setup colors and fonts
  77. //-----------------------------------------------------------------------
  78. void CMenuItem::ApplySchemeSettings( vgui::IScheme *pScheme )
  79. {
  80. BaseClass::ApplySchemeSettings( pScheme );
  81. SetPaintBackgroundType( 2 );
  82. m_BgColor = pScheme->GetColor( "MatchmakingMenuItemBackground", Color( 46, 43, 42, 255 ) );
  83. m_BgColorActive = pScheme->GetColor( "MatchmakingMenuItemBackgroundActive", Color( 150, 71, 0, 255 ) );
  84. m_pTitle->SetFgColor( pScheme->GetColor( "MatchmakingMenuItemTitleColor", Color( 0, 0, 0, 255 ) ) );
  85. if ( m_pDescription )
  86. {
  87. m_pDescription->SetFgColor( pScheme->GetColor( "MatchmakingMenuItemDescriptionColor", Color( 0, 0, 0, 255 ) ) );
  88. }
  89. KeyValues *pKeys = BasePanel()->GetConsoleControlSettings()->FindKey( "MenuItem.res" );
  90. ApplySettings( pKeys );
  91. }
  92. //-----------------------------------------------------------------------
  93. // Set an item as having input focus
  94. //-----------------------------------------------------------------------
  95. void CMenuItem::SetFocus( const bool bActive )
  96. {
  97. if ( bActive )
  98. {
  99. SetBgColor( m_BgColorActive );
  100. }
  101. else
  102. {
  103. SetBgColor( m_BgColor );
  104. }
  105. }
  106. //-----------------------------------------------------------------------
  107. // Set an item as having input focus
  108. //-----------------------------------------------------------------------
  109. void CMenuItem::SetEnabled( bool bEnabled )
  110. {
  111. if ( bEnabled )
  112. {
  113. SetAlpha( 255 );
  114. }
  115. else
  116. {
  117. SetAlpha( m_nDisabledAlpha );
  118. }
  119. m_bEnabled = bEnabled;
  120. }
  121. //-----------------------------------------------------------------------
  122. // Set a column as having focus
  123. //-----------------------------------------------------------------------
  124. void CMenuItem::SetActiveColumn( int col )
  125. {
  126. // do nothing
  127. }
  128. //-----------------------------------------------------------------------
  129. // Set an item as having input focus
  130. //-----------------------------------------------------------------------
  131. bool CMenuItem::IsEnabled()
  132. {
  133. return m_bEnabled;
  134. }
  135. //-----------------------------------------------------------------------
  136. // Perform any special actions when an item is "clicked"
  137. //-----------------------------------------------------------------------
  138. void CMenuItem::OnClick()
  139. {
  140. // do nothing - derived classes implement this
  141. }
  142. //-----------------------------------------------------------------------
  143. // CCommandItem
  144. //
  145. // Menu item that issues a command when clicked.
  146. //-----------------------------------------------------------------------
  147. CCommandItem::CCommandItem( CDialogMenu *pParent, const char *pTitleLabel, const char *pDescLabel, const char *pCommand )
  148. : BaseClass( pParent, pTitleLabel, pDescLabel )
  149. {
  150. Q_strncpy( m_szCommand, pCommand, MAX_COMMAND_LEN );
  151. }
  152. CCommandItem::~CCommandItem()
  153. {
  154. // do nothing
  155. }
  156. void CCommandItem::OnClick()
  157. {
  158. GetParent()->OnCommand( m_szCommand );
  159. vgui::surface()->PlaySound( "UI/buttonclick.wav" );
  160. }
  161. void CCommandItem::SetFocus(const bool bActive )
  162. {
  163. BaseClass::SetFocus( bActive );
  164. if ( bActive == true && m_bHasFocus == false )
  165. {
  166. vgui::surface()->PlaySound( "UI/buttonclickrelease.wav" );
  167. }
  168. m_bHasFocus = bActive;
  169. }
  170. //-----------------------------------------------------------------------
  171. // CPlayerItem
  172. //
  173. // Menu item to display a player in the lobby.
  174. //-----------------------------------------------------------------------
  175. CPlayerItem::CPlayerItem( CDialogMenu *pParent, const char *pTitleLabel, int64 nId, byte bVoice, bool bReady )
  176. : BaseClass( pParent, pTitleLabel, NULL, "ShowGamerCard" )
  177. {
  178. m_pVoiceIcon = new vgui::Label( this, "voiceicon", "" );
  179. m_pReadyIcon = new vgui::Label( this, "readyicon", "" );
  180. m_nId = nId;
  181. m_bVoice = bVoice;
  182. m_bReady = bReady;
  183. }
  184. CPlayerItem::~CPlayerItem()
  185. {
  186. delete m_pVoiceIcon;
  187. delete m_pReadyIcon;
  188. }
  189. void CPlayerItem::PerformLayout()
  190. {
  191. BaseClass::PerformLayout();
  192. const char *pVoice = "";
  193. if ( m_bVoice == 2 )
  194. {
  195. pVoice = "#TF_Icon_Voice";
  196. }
  197. else if ( m_bVoice == 1 )
  198. {
  199. pVoice = "#TF_Icon_Voice_Idle";
  200. }
  201. m_pVoiceIcon->SetText( pVoice );
  202. m_pReadyIcon->SetText( m_bReady ? "#TF_Icon_Ready" : "#TF_Icon_NotReady" );
  203. int x, y;
  204. m_pReadyIcon->GetPos( x, y );
  205. m_pReadyIcon->SetPos( GetWide() - m_pReadyIcon->GetWide() - m_nRightMargin, y );
  206. }
  207. void CPlayerItem::ApplySchemeSettings( vgui::IScheme *pScheme )
  208. {
  209. BaseClass::ApplySchemeSettings( pScheme );
  210. KeyValues *pKeys = BasePanel()->GetConsoleControlSettings()->FindKey( "PlayerItem.res" );
  211. ApplySettings( pKeys );
  212. }
  213. void CPlayerItem::OnClick()
  214. {
  215. BaseClass::OnClick();
  216. }
  217. //-----------------------------------------------------------------------
  218. // CBrowserItem
  219. //
  220. // Menu item used to display session search results.
  221. //-----------------------------------------------------------------------
  222. CBrowserItem::CBrowserItem( CDialogMenu *pParent, const char *pHost, const char *pPlayers, const char *pScenario, const char *pPing )
  223. : BaseClass( pParent, pHost, NULL, "SelectSession" )
  224. {
  225. m_pPlayers = new vgui::Label( this, "players", pPlayers );
  226. m_pScenario = new vgui::Label( this, "scenario", pScenario );
  227. m_pPing = new vgui::Label( this, "ping", pPing );
  228. }
  229. CBrowserItem::~CBrowserItem()
  230. {
  231. delete m_pPlayers;
  232. delete m_pScenario;
  233. delete m_pPing;
  234. }
  235. void CBrowserItem::PerformLayout()
  236. {
  237. BaseClass::PerformLayout();
  238. int x, y, wide, tall;
  239. m_pPing->GetBounds( x, y, wide, tall );
  240. m_pScenario->SizeToContents();
  241. int sx, sy;
  242. m_pScenario->GetPos( sx, sy );
  243. m_pScenario->SetPos( x - m_pScenario->GetWide() - m_nRightMargin, sy );
  244. SetSize( x + wide, GetTall() );
  245. }
  246. void CBrowserItem::ApplySettings( KeyValues *pSettings )
  247. {
  248. BaseClass::ApplySettings( pSettings );
  249. }
  250. void CBrowserItem::ApplySchemeSettings( vgui::IScheme *pScheme )
  251. {
  252. BaseClass::ApplySchemeSettings( pScheme );
  253. Color fgcolor = pScheme->GetColor( "MatchmakingMenuItemDescriptionColor", Color( 64, 64, 64, 255 ) );
  254. m_pPlayers->SetFgColor( fgcolor );
  255. m_pScenario->SetFgColor( fgcolor );
  256. m_pPing->SetContentAlignment( vgui::Label::a_center );
  257. KeyValues *pKeys = BasePanel()->GetConsoleControlSettings()->FindKey( "BrowserItem.res" );
  258. ApplySettings( pKeys );
  259. SetFocus( false );
  260. }
  261. //-----------------------------------------------------------------------
  262. // COptionsItem
  263. //
  264. // Menu item used to present a list of options for the player to select
  265. // from, such as "choose a map" or "number of rounds".
  266. //-----------------------------------------------------------------------
  267. COptionsItem::COptionsItem( CDialogMenu *pParent, const char *pLabel )
  268. : BaseClass( pParent, pLabel, NULL )
  269. {
  270. m_nActiveOption = m_Options.InvalidIndex();
  271. m_nOptionsXPos = 0;
  272. m_nMaxOptionWidth = 0;
  273. m_szOptionsFont[0] = '\0';
  274. m_hOptionsFont = vgui::INVALID_FONT;
  275. m_pLeftArrow = new vgui::Label( this, "LeftArrow", "" );
  276. m_pRightArrow = new vgui::Label( this, "RightArrow", "" );
  277. }
  278. COptionsItem::~COptionsItem()
  279. {
  280. m_OptionLabels.PurgeAndDeleteElements();
  281. delete m_pLeftArrow;
  282. delete m_pRightArrow;
  283. }
  284. void COptionsItem::PerformLayout()
  285. {
  286. BaseClass::PerformLayout();
  287. int optionWide = max( m_nOptionsMinWide, GetWide() - m_nOptionsXPos - m_pRightArrow->GetWide() - m_nOptionsLeftMargin );
  288. int optionTall = GetTall();
  289. for ( int i = 0; i < m_OptionLabels.Count(); ++i )
  290. {
  291. vgui::Label *pOption = m_OptionLabels[i];
  292. pOption->SetBounds( m_nOptionsXPos, 0, optionWide, optionTall );
  293. }
  294. int lx, ly;
  295. m_pLeftArrow->GetPos( lx, ly );
  296. m_pLeftArrow->SetPos( m_nOptionsXPos - m_nArrowGap - m_pLeftArrow->GetWide(), ly );
  297. int rx, ry;
  298. m_pRightArrow->GetPos( rx, ry );
  299. m_pRightArrow->SetPos( m_nOptionsXPos + optionWide + m_nArrowGap, ry );
  300. m_pLeftArrow->SetAlpha( 255 );
  301. m_pRightArrow->SetAlpha( 255 );
  302. if ( m_nActiveOption == 0 )
  303. {
  304. m_pLeftArrow->SetAlpha( 32 );
  305. }
  306. else if ( m_nActiveOption == m_OptionLabels.Count() - 1 )
  307. {
  308. m_pRightArrow->SetAlpha( 32 );
  309. }
  310. }
  311. void COptionsItem::ApplySettings( KeyValues *pSettings )
  312. {
  313. BaseClass::ApplySettings( pSettings );
  314. m_nOptionsXPos = pSettings->GetInt( "optionsxpos", 0 );
  315. m_nOptionsMinWide = pSettings->GetInt( "optionsminwide", 0 );
  316. m_nOptionsLeftMargin = pSettings->GetInt( "optionsleftmargin", 0 );
  317. m_nArrowGap = pSettings->GetInt( "arrowgap", 0 );
  318. Q_strncpy( m_szOptionsFont, pSettings->GetString( "optionsfont", "Default" ), sizeof( m_szOptionsFont ) );
  319. }
  320. void COptionsItem::ApplySchemeSettings( vgui::IScheme *pScheme )
  321. {
  322. BaseClass::ApplySchemeSettings( pScheme );
  323. SetPaintBackgroundEnabled( false );
  324. m_pTitle->SetFgColor( pScheme->GetColor( "MatchmakingMenuItemTitleColor", Color( 200, 184, 151, 255 ) ) );
  325. KeyValues *pKeys = BasePanel()->GetConsoleControlSettings()->FindKey( "OptionsItem.res" );
  326. ApplySettings( pKeys );
  327. m_hOptionsFont = pScheme->GetFont( m_szOptionsFont );
  328. }
  329. void COptionsItem::SetFocus( const bool bActive )
  330. {
  331. if ( bActive )
  332. {
  333. for ( int i = 0; i < m_OptionLabels.Count(); ++i )
  334. {
  335. m_OptionLabels[i]->SetBgColor( m_BgColorActive );
  336. }
  337. }
  338. else
  339. {
  340. for ( int i = 0; i < m_OptionLabels.Count(); ++i )
  341. {
  342. m_OptionLabels[i]->SetBgColor( m_BgColor );
  343. }
  344. }
  345. }
  346. void COptionsItem::AddOption( const char *pLabelText, const sessionProperty_t& option )
  347. {
  348. // Add a new option to this item's list of options
  349. m_Options.AddToTail( option );
  350. int idx = m_OptionLabels.AddToTail( new vgui::Label( this, "Option Value", pLabelText ) );
  351. vgui::Label *pOption = m_OptionLabels[idx];
  352. // Check for a format string
  353. if ( Q_stristr( pLabelText, "Fmt" ) )
  354. {
  355. wchar_t wszString[64];
  356. wchar_t wzNumber[8];
  357. wchar_t *wzFmt = g_pVGuiLocalize->Find( pLabelText );
  358. g_pVGuiLocalize->ConvertANSIToUnicode( option.szValue, wzNumber, sizeof( wzNumber ) );
  359. g_pVGuiLocalize->ConstructString( wszString, sizeof( wszString ), wzFmt, 1, wzNumber );
  360. pOption->SetText( wszString );
  361. }
  362. SETUP_PANEL( pOption );
  363. pOption->SetPaintBackgroundType( 2 );
  364. pOption->SetFont( m_hOptionsFont );
  365. pOption->SetBgColor( Color( 46, 43, 42, 255 ) );
  366. pOption->SetFgColor( m_pTitle ? m_pTitle->GetFgColor() : Color( 200, 184, 151, 255 ) );
  367. pOption->SetTextInset( m_nOptionsLeftMargin, 0 );
  368. pOption->SetContentAlignment( vgui::Label::a_southwest );
  369. pOption->SizeToContents();
  370. int wide = max( m_nOptionsMinWide, pOption->GetWide() );
  371. pOption->SetBounds( m_nOptionsXPos, 0, wide, GetTall() );
  372. m_nMaxOptionWidth = max( wide, m_nMaxOptionWidth );
  373. SetWide( m_nOptionsXPos + m_nMaxOptionWidth + m_nOptionsLeftMargin * 2 + m_nArrowGap * 2 + m_pRightArrow->GetWide() );
  374. }
  375. //-----------------------------------------------------------------------
  376. // Return the session property associated with the current active option
  377. //-----------------------------------------------------------------------
  378. const sessionProperty_t &COptionsItem::GetActiveOption()
  379. {
  380. return m_Options[m_nActiveOption];
  381. }
  382. //-----------------------------------------------------------------------
  383. // Return the index of the current active option
  384. //-----------------------------------------------------------------------
  385. int COptionsItem::GetActiveOptionIndex()
  386. {
  387. return m_nActiveOption;
  388. }
  389. //-----------------------------------------------------------------------
  390. // Sets which option currently has focus
  391. //-----------------------------------------------------------------------
  392. void COptionsItem::SetOptionFocus( unsigned int idx )
  393. {
  394. unsigned int itemCt = (unsigned int)m_OptionLabels.Count();
  395. if ( idx > itemCt )
  396. return;
  397. m_nActiveOption = idx;
  398. for ( unsigned int i = 0; i < itemCt; ++i )
  399. {
  400. vgui::Label *pLabel = m_OptionLabels[i];
  401. const bool bVisible = ( i == idx );
  402. pLabel->SetVisible( bVisible );
  403. }
  404. InvalidateLayout();
  405. }
  406. //-----------------------------------------------------------------------
  407. // Move focus to the next option - does not wrap
  408. //-----------------------------------------------------------------------
  409. void COptionsItem::SetOptionFocusNext()
  410. {
  411. if ( m_nActiveOption + 1 < m_OptionLabels.Count() )
  412. {
  413. SetOptionFocus( m_nActiveOption + 1 );
  414. }
  415. else
  416. {
  417. vgui::surface()->PlaySound( "player/suit_denydevice.wav" );
  418. }
  419. }
  420. //-----------------------------------------------------------------------
  421. // Move focus to the previous option - does not wrap
  422. //-----------------------------------------------------------------------
  423. void COptionsItem::SetOptionFocusPrev()
  424. {
  425. if ( m_nActiveOption > 0 )
  426. {
  427. SetOptionFocus( m_nActiveOption - 1 );
  428. }
  429. else
  430. {
  431. vgui::surface()->PlaySound( "player/suit_denydevice.wav" );
  432. }
  433. }
  434. //-----------------------------------------------------------------------
  435. // CAchievementItem
  436. //
  437. // Menu item used to present an achievement - including image, title,
  438. // description, points and unlock date. Clicking the item opens another
  439. // dialog with additional information about the achievement.
  440. //-----------------------------------------------------------------------
  441. CAchievementItem::CAchievementItem( CDialogMenu *pParent, const wchar_t *pName, const wchar_t *pDesc, uint points, bool bUnlocked, IAchievement* pSourceAchievement )
  442. : BaseClass( pParent, "", "" )
  443. {
  444. // Title and description were returned as results of a system query,
  445. // and are therefore already localized.
  446. m_pTitle->SetText( pName );
  447. if ( IsX360() )
  448. {
  449. wchar_t buf[120];
  450. // Get the screen size
  451. int wide, tall;
  452. vgui::surface()->GetScreenSize(wide, tall);
  453. unsigned int iWrapLen;
  454. if ( tall <= 480 )
  455. {
  456. iWrapLen = 50;
  457. }
  458. else
  459. {
  460. iWrapLen = 65;
  461. }
  462. // let's do some wrapping on this label
  463. wcsncpy( buf, pDesc, sizeof(buf) / sizeof( wchar_t ) );
  464. if ( wcslen(buf) > iWrapLen )
  465. {
  466. int iPos = iWrapLen;
  467. while ( iPos > 0 && buf[iPos] != L' ' )
  468. {
  469. iPos--;
  470. }
  471. if ( iPos > 0 && buf[iPos] == L' ' )
  472. {
  473. buf[iPos] = L'\n';
  474. }
  475. }
  476. m_pDescription->SetText( buf );
  477. }
  478. else
  479. {
  480. m_pDescription->SetText( pDesc );
  481. }
  482. m_pSourceAchievement = pSourceAchievement;
  483. m_pPercentageBarBackground = SETUP_PANEL( new vgui::ImagePanel( this, "PercentageBarBackground" ) );
  484. m_pPercentageBar = SETUP_PANEL( new vgui::ImagePanel( this, "PercentageBar" ) );
  485. m_pPercentageText = SETUP_PANEL( new vgui::Label( this, "PercentageText", "" ) );
  486. // Set the status icons
  487. m_pLockedIcon = SETUP_PANEL( new vgui::ImagePanel( this, "lockedicon" ) );
  488. m_pUnlockedIcon = SETUP_PANEL( new vgui::ImagePanel( this, "unlockedicon" ) );
  489. // Gamerscore number
  490. if ( IsX360() )
  491. {
  492. wchar_t *wzFormat = g_pVGuiLocalize->Find( "#GameUI_Achievement_Points" ); // "%s1G"
  493. wchar_t wzPoints[10];
  494. V_snwprintf( wzPoints, ARRAYSIZE( wzPoints ), L"%d", points );
  495. wchar_t wzPointsLayout[10];
  496. g_pVGuiLocalize->ConstructString( wzPointsLayout, sizeof( wzPointsLayout ), wzFormat, 1, wzPoints );
  497. m_pPoints = new vgui::Label( this, "Points", wzPointsLayout );
  498. }
  499. // Achievement image
  500. m_pImage = new vgui::ImagePanel( this, "icon" );
  501. }
  502. CAchievementItem::~CAchievementItem()
  503. {
  504. delete m_pImage;
  505. delete m_pPoints;
  506. delete m_pLockedIcon;
  507. delete m_pUnlockedIcon;
  508. delete m_pPercentageBarBackground;
  509. delete m_pPercentageBar;
  510. delete m_pPercentageText;
  511. }
  512. void CAchievementItem::PerformLayout()
  513. {
  514. BaseClass::PerformLayout();
  515. int x, y;
  516. m_pPoints->SizeToContents();
  517. m_pPoints->GetPos( x, y );
  518. x = GetWide() - m_pPoints->GetWide() - m_nRightMargin;
  519. m_pPoints->SetPos( x, y );
  520. }
  521. void CAchievementItem::ApplySchemeSettings( vgui::IScheme *pScheme )
  522. {
  523. BaseClass::ApplySchemeSettings( pScheme );
  524. KeyValues*pKeys = BasePanel()->GetConsoleControlSettings()->FindKey( "AchievementItem.res" );
  525. ApplySettings( pKeys );
  526. m_pImage->SetBgColor( Color( 32, 32, 32, 255 ) );
  527. m_pImage->SetFgColor( Color( 32, 32, 32, 255 ) );
  528. m_pImage->SetPaintBackgroundEnabled( true );
  529. m_pPoints->SetFgColor( pScheme->GetColor( "MatchmakingMenuItemDescriptionColor", Color( 64, 64, 64, 255 ) ) );
  530. // Set icon image
  531. LoadAchievementIcon( m_pImage, m_pSourceAchievement );
  532. // Percentage completion bar (for progressive achievements)
  533. UpdateProgressBar( this, m_pSourceAchievement, m_clrProgressBar );
  534. if ( m_pSourceAchievement && m_pSourceAchievement->IsAchieved() )
  535. {
  536. m_pLockedIcon->SetVisible( false );
  537. m_pUnlockedIcon->SetVisible ( true );
  538. m_pImage->SetVisible( true );
  539. }
  540. else
  541. {
  542. m_pLockedIcon->SetVisible( true );
  543. m_pUnlockedIcon->SetVisible( false );
  544. m_pImage->SetVisible( false );
  545. }
  546. }
  547. //-----------------------------------------------------------------------
  548. // CSectionedItem
  549. //
  550. // Menu item used to display some number of data entries, which are arranged
  551. // into columns. Supports scrolling through columns horizontally with the
  552. // ability to "lock" columns so they don't scroll
  553. //-----------------------------------------------------------------------
  554. CSectionedItem::CSectionedItem( CDialogMenu *pParent, const char **ppEntries, int ct )
  555. : BaseClass( pParent, "", NULL, "SelectSession" )
  556. {
  557. m_bHeader = false;
  558. for ( int i = 0; i < ct; ++i )
  559. {
  560. AddSection( ppEntries[i], m_pParent->GetColumnAlignment( i ) );
  561. }
  562. }
  563. CSectionedItem::~CSectionedItem()
  564. {
  565. ClearSections();
  566. }
  567. void CSectionedItem::ClearSections()
  568. {
  569. for ( int i = 0; i < m_Sections.Count(); ++i )
  570. {
  571. section_s &sec = m_Sections[i];
  572. delete sec.pLabel;
  573. }
  574. }
  575. void CSectionedItem::PerformLayout()
  576. {
  577. BaseClass::PerformLayout();
  578. int tall = GetTall();
  579. for ( int i = 0; i < m_Sections.Count(); ++i )
  580. {
  581. vgui::Label *pLabel = m_Sections[i].pLabel;
  582. if ( !m_bHeader )
  583. {
  584. pLabel->SetFont( m_pParent->GetColumnFont(i) );
  585. pLabel->SetFgColor( m_pParent->GetColumnColor(i) );
  586. }
  587. pLabel->SetBounds( m_pParent->GetColumnXPos(i), 0, m_pParent->GetColumnWide(i), tall );
  588. pLabel->SetTextInset( 10, m_bHeader ? 5 : m_pParent->GetColumnYPos(i) ); // only use ypos for the y-inset if we're not a header
  589. }
  590. }
  591. void CSectionedItem::ApplySettings( KeyValues *pResourceData )
  592. {
  593. BaseClass::ApplySettings( pResourceData );
  594. }
  595. void CSectionedItem::ApplySchemeSettings( vgui::IScheme *pScheme )
  596. {
  597. BaseClass::ApplySchemeSettings( pScheme );
  598. KeyValues *pKeys = BasePanel()->GetConsoleControlSettings()->FindKey( "SectionedItem.res" );
  599. ApplySettings( pKeys );
  600. int iLast = m_Sections.Count() -1;
  601. SetWide( m_pParent->GetColumnXPos(iLast) + m_pParent->GetColumnWide(iLast) );
  602. }
  603. void CSectionedItem::AddSection( const char *pText, int align )
  604. {
  605. section_s sec;
  606. sec.pLabel = new vgui::Label( this, "Section", pText );
  607. SETUP_PANEL( sec.pLabel );
  608. sec.pLabel->SetContentAlignment( (vgui::Label::Alignment)align );
  609. sec.pLabel->SetTextInset( 10, 0 );
  610. sec.pLabel->SetBgColor( Color( 209, 112, 52, 128 ) );
  611. m_Sections.AddToTail( sec );
  612. }
  613. void CSectionedItem::SetActiveColumn( int col )
  614. {
  615. for ( int i = 0; i < m_Sections.Count(); ++i )
  616. {
  617. m_Sections[i].pLabel->SetPaintBackgroundEnabled( i == col );
  618. }
  619. }
  620. //--------------------------------------------------------------------------------------
  621. // Generic menu for Xbox 360 matchmaking dialogs. Contains a list of CMenuItems arranged
  622. // vertically. The user can navigate the list using the controller and click on any
  623. // item. A clicked item may send a command to the dialog and the dialog responds accordingly.
  624. //--------------------------------------------------------------------------------------
  625. CDialogMenu::CDialogMenu() : BaseClass( NULL, "DialogMenu" )
  626. {
  627. // Quiet "parent not sized yet" spew
  628. SetSize( 100, 100 );
  629. m_pParent = NULL;
  630. m_pHeader = NULL;
  631. m_bUseFilter = false;
  632. m_bHasHeader = false;
  633. m_nItemSpacing = 0;
  634. m_nMinWide = 0;
  635. m_nActive = -1;
  636. m_nActiveColumn = -1;
  637. m_nBaseRowIdx = 0;
  638. m_nBaseColumnIdx = 0;
  639. m_iUnlocked = 0;
  640. m_nMaxVisibleItems = 1000; // arbitrarily large
  641. m_nMaxVisibleColumns = 1000;// arbitrarily large
  642. }
  643. CDialogMenu::~CDialogMenu()
  644. {
  645. m_MenuItems.PurgeAndDeleteElements();
  646. delete m_pHeader;
  647. }
  648. void CDialogMenu::SetParent( CBaseDialog *pParent )
  649. {
  650. BaseClass::SetParent( pParent );
  651. m_pParent = pParent;
  652. }
  653. //--------------------------------------------------------------------------------------
  654. // Set a filter to use when reading in menu item keyvalues
  655. //--------------------------------------------------------------------------------------
  656. void CDialogMenu::SetFilter( const char *pFilter )
  657. {
  658. if ( pFilter )
  659. {
  660. Q_strncpy( m_szFilter, pFilter, sizeof( m_szFilter ) );
  661. m_bUseFilter = true;
  662. }
  663. else
  664. {
  665. m_bUseFilter = false;
  666. }
  667. }
  668. //--------------------------------------------------------------------------------------
  669. // Add a new menu item to the item array
  670. //--------------------------------------------------------------------------------------
  671. CMenuItem *CDialogMenu::AddItemInternal( CMenuItem *pItem )
  672. {
  673. int idx = m_MenuItems.AddToTail( pItem );
  674. SETUP_PANEL( pItem );
  675. return m_MenuItems[idx];
  676. }
  677. //--------------------------------------------------------------------------------------
  678. // Add a new menu item of some type that derives from CMenuItem
  679. //--------------------------------------------------------------------------------------
  680. CCommandItem *CDialogMenu::AddCommandItem( const char *pTitleLabel, const char *pDescLabel, const char *pCommand )
  681. {
  682. return (CCommandItem*)AddItemInternal( new CCommandItem( this, pTitleLabel, pDescLabel, pCommand ) );
  683. }
  684. CBrowserItem *CDialogMenu::AddBrowserItem( const char *pHost, const char *pPlayers, const char *pScenario, const char *pPing )
  685. {
  686. // Results are added to the menu at runtime, so the layout needs to be updated after each addition.
  687. CBrowserItem *pItem = (CBrowserItem*)AddItemInternal( new CBrowserItem( this, pHost, pPlayers, pScenario, pPing ) );
  688. PerformLayout();
  689. return pItem;
  690. }
  691. COptionsItem *CDialogMenu::AddOptionsItem( const char *pLabel )
  692. {
  693. return (COptionsItem*)AddItemInternal( new COptionsItem( this, pLabel ) );
  694. }
  695. CAchievementItem *CDialogMenu::AddAchievementItem( const wchar_t *pName, const wchar_t *pDesc, uint points, bool bUnlocked, IAchievement* pSourceAchievement )
  696. {
  697. return (CAchievementItem*)AddItemInternal( new CAchievementItem( this, pName, pDesc, points, bUnlocked, pSourceAchievement ) );
  698. }
  699. CSectionedItem *CDialogMenu::AddSectionedItem( const char **ppEntries, int ct )
  700. {
  701. CSectionedItem *pItem = (CSectionedItem*)AddItemInternal( new CSectionedItem( this, ppEntries, ct ) );
  702. PerformLayout();
  703. return pItem;
  704. }
  705. CPlayerItem *CDialogMenu::AddPlayerItem( const char *pTitleLabel, int64 nId, byte bVoice, bool bReady )
  706. {
  707. // Players are added to the lobby at runtime, so the layout needs to be updated after each addition.
  708. CPlayerItem *pItem = (CPlayerItem*)AddItemInternal( new CPlayerItem( this, pTitleLabel, nId, bVoice, bReady ) );
  709. PerformLayout();
  710. return pItem;
  711. }
  712. void CDialogMenu::RemovePlayerItem( int idx )
  713. {
  714. delete m_MenuItems[idx];
  715. m_MenuItems.Remove( idx );
  716. PerformLayout();
  717. }
  718. void CDialogMenu::ClearItems()
  719. {
  720. m_MenuItems.PurgeAndDeleteElements();
  721. InvalidateLayout();
  722. }
  723. //--------------------------------------------------------------------------------------
  724. // Set the size an position of all the menu items
  725. //--------------------------------------------------------------------------------------
  726. void CDialogMenu::PerformLayout()
  727. {
  728. BaseClass::PerformLayout();
  729. // Position the menu items and set their width
  730. int yPos = 0;
  731. int wide = GetWide();
  732. if ( m_bHasHeader )
  733. {
  734. yPos = 40;
  735. m_pHeader->SetPos( 0, 0 );
  736. m_pHeader->SetWide( wide );
  737. m_pHeader->PerformLayout();
  738. }
  739. for ( int i = 0; i < m_MenuItems.Count(); ++i )
  740. {
  741. CMenuItem *pItem = m_MenuItems[i];
  742. pItem->SetPos( 0, yPos );
  743. pItem->SetWide( wide );
  744. pItem->SetActiveColumn( m_nActiveColumn );
  745. pItem->PerformLayout();
  746. if ( i < m_nBaseRowIdx || i > m_nBaseRowIdx + m_nMaxVisibleItems - 1 )
  747. {
  748. pItem->SetVisible( false );
  749. }
  750. else
  751. {
  752. pItem->SetVisible( true );
  753. yPos += pItem->GetTall() + m_nItemSpacing;
  754. }
  755. }
  756. // Reset the focus to update background colors of all menu items
  757. SetFocus( m_nActive );
  758. SetTall( yPos );
  759. }
  760. //--------------------------------------------------------------------------------------
  761. // Parse the res file for menu items to build out the dialog menu.
  762. //--------------------------------------------------------------------------------------
  763. void CDialogMenu::ApplySettings( KeyValues *pResourceData )
  764. {
  765. BaseClass::ApplySettings( pResourceData );
  766. m_nItemSpacing = pResourceData->GetInt( "itemspacing", 2 );
  767. m_nMinWide = pResourceData->GetInt( "minwide", 0 );
  768. m_nActiveColumn = pResourceData->GetInt( "activecolumn", -1 );
  769. m_nMaxVisibleItems = pResourceData->GetInt( "maxvisibleitems", 1000 ); // arbitrarily large
  770. m_nMaxVisibleColumns = pResourceData->GetInt( "maxvisiblecolumns", 1000 ); // arbitrarily large
  771. KeyValues *pColumnData = pResourceData->FindKey( "Columns" );
  772. if ( pColumnData )
  773. {
  774. int xPos = 0;
  775. int idx = 0;
  776. const char *ppHeader[MAX_COLUMNS];
  777. for ( KeyValues *pColumn = pColumnData->GetFirstSubKey(); pColumn != NULL; pColumn = pColumn->GetNextKey() )
  778. {
  779. if ( !Q_stricmp( pColumn->GetName(), "Column" ) )
  780. {
  781. columninfo_s col;
  782. col.bSortDown = true;
  783. col.xpos = pColumn->GetInt( "xpos", xPos );
  784. col.ypos = pColumn->GetInt( "ypos", 0 );
  785. col.wide = pColumn->GetInt( "wide", 0 );
  786. col.align = pColumn->GetInt( "align", 3 ); // west by default
  787. col.bLocked = pColumn->GetInt( "locked", 0 );
  788. col.hFont = m_pScheme->GetFont( pColumn->GetString( "font", "default" ) );
  789. col.color = m_pScheme->GetColor( pColumn->GetString( "fgcolor" ), Color( 0, 0, 0, 255 ) );
  790. ppHeader[idx++] = pColumn->GetString( "header", "" );
  791. xPos = col.xpos + col.wide;
  792. m_Columns.AddToTail( col );
  793. if ( col.bLocked )
  794. {
  795. m_nBaseColumnIdx = idx;
  796. m_iUnlocked = idx;
  797. }
  798. }
  799. }
  800. m_bHasHeader = true;
  801. m_pHeader = new CSectionedItem( this, ppHeader, idx );
  802. m_pHeader->m_bHeader = true;
  803. SETUP_PANEL( m_pHeader );
  804. m_pHeader->SetPaintBackgroundEnabled( false );
  805. vgui::HFont headerFont = m_pScheme->GetFont( pColumnData->GetString( "headerfont", "default" ) );
  806. Color headerColor = m_pScheme->GetColor( pColumnData->GetString( "headerfgcolor" ), Color( 0, 0, 0, 255 ) );
  807. for ( int i = 0; i < idx; ++i )
  808. {
  809. vgui::Label *pLabel = m_pHeader->m_Sections[i].pLabel;
  810. pLabel->SetFont( headerFont );
  811. pLabel->SetFgColor( headerColor );
  812. pLabel->SetPaintBackgroundEnabled( false );
  813. }
  814. }
  815. for ( KeyValues *pMenuData = pResourceData->GetFirstSubKey(); pMenuData != NULL; pMenuData = pMenuData->GetNextKey() )
  816. {
  817. // See if we should skip over this block
  818. if ( m_bUseFilter )
  819. {
  820. if ( pMenuData->GetInt( m_szFilter, 0 ) == 0 )
  821. continue;
  822. }
  823. // Give our parent a chance to change the properties of this item
  824. m_pParent->OverrideMenuItem( pMenuData );
  825. if ( !Q_stricmp( pMenuData->GetName(), "CommandItem" ) )
  826. {
  827. // New Command Item
  828. const char *label = pMenuData->GetString( "label", "<unknown>" );
  829. const char *description = pMenuData->GetString( "description", NULL );
  830. const char *command = pMenuData->GetString( "command", "<unknown>" );
  831. AddCommandItem( label, description, command );
  832. }
  833. else if ( !Q_stricmp( pMenuData->GetName(), "OptionsItem" ) )
  834. {
  835. // New Options Item
  836. COptionsItem *pItem = AddOptionsItem( pMenuData->GetString( "label", "<unknown>" ) );
  837. // ID and ValueType and the same for all option values
  838. const char *pID = pMenuData->GetString( "id", "NULL" );
  839. const char *pValueType = pMenuData->GetString( "valuetype", NULL );
  840. // Add all the options
  841. for ( KeyValues *pValue = pMenuData->GetFirstSubKey(); pValue != NULL; pValue = pValue->GetNextKey() )
  842. {
  843. if ( !Q_stricmp( pValue->GetName(), "Option" ) )
  844. {
  845. sessionProperty_t prop;
  846. prop.nType = SESSION_CONTEXT;
  847. Q_strncpy( prop.szID, pID, sizeof( prop.szID ) );
  848. Q_strncpy( prop.szValue, pValue->GetString( "value", "NULL" ), sizeof( prop.szValue ) );
  849. if ( pValueType )
  850. {
  851. // Only session properties have a type
  852. prop.nType = SESSION_PROPERTY;
  853. Q_strncpy( prop.szValueType, pValueType, sizeof( prop.szValueType ) );
  854. }
  855. const char *pLabel = pValue->GetString( "label", "<unknown>" );
  856. pItem->AddOption( pLabel, prop );
  857. }
  858. }
  859. // Add range items after the specified items
  860. if ( pMenuData->GetInt( "userange" ) )
  861. {
  862. // Options are an implicit range of integers
  863. int nStart = pMenuData->GetInt( "rangelow" );
  864. int nEnd = pMenuData->GetInt( "rangehigh" );
  865. int nInterval = pMenuData->GetInt( "interval", 1 );
  866. // Prevent total destruction from a bad resource file
  867. if ( nEnd < nStart )
  868. {
  869. nEnd = nStart;
  870. }
  871. for ( int i = nStart; i <= nEnd; i += nInterval )
  872. {
  873. sessionProperty_t prop;
  874. prop.nType = SESSION_PROPERTY;
  875. Q_strncpy( prop.szID, pID, sizeof( prop.szID ) );
  876. Q_strncpy( prop.szValueType, pValueType, sizeof( prop.szValueType ) );
  877. Q_snprintf( prop.szValue, sizeof(prop.szValue), "%d", i );
  878. pItem->AddOption( prop.szValue, prop );
  879. }
  880. }
  881. // Set the default active option
  882. int active = pMenuData->GetInt( "activeoption", 0 );
  883. pItem->SetOptionFocus( active );
  884. // Notify our parent that each option has been set to its current setting
  885. KeyValues *kv = new KeyValues( "MenuItemChanged", "item", GetItemCount() - 1 );
  886. PostActionSignal( kv );
  887. }
  888. }
  889. // Calculate the final menu size according to the widest menu item
  890. int wide = m_nMinWide;
  891. for ( int i = 0; i < m_MenuItems.Count(); ++i )
  892. {
  893. wide = max( wide, m_MenuItems[i]->GetWide() );
  894. }
  895. SetWide( wide );
  896. }
  897. //--------------------------------------------------------------------------------------
  898. // Cache off the scheme
  899. //--------------------------------------------------------------------------------------
  900. void CDialogMenu::ApplySchemeSettings( vgui::IScheme *pScheme )
  901. {
  902. BaseClass::ApplySchemeSettings( pScheme );
  903. m_pScheme = pScheme;
  904. }
  905. //--------------------------------------------------------------------------------------
  906. // Give focus (highlights) a particular menu item by index
  907. //--------------------------------------------------------------------------------------
  908. void CDialogMenu::SetFocus( int idx )
  909. {
  910. int itemCt = (unsigned int)m_MenuItems.Count();
  911. if ( idx >= itemCt )
  912. return;
  913. for ( int i = 0; i < itemCt; ++i )
  914. {
  915. m_MenuItems[i]->SetFocus( i == idx );
  916. }
  917. m_nActive = idx;
  918. if ( m_nActive >= 0 && m_nActive < m_nBaseRowIdx )
  919. {
  920. m_nBaseRowIdx = m_nActive;
  921. }
  922. else if ( m_nActive > m_nBaseRowIdx + m_nMaxVisibleItems - 1 )
  923. {
  924. m_nBaseRowIdx = m_nActive - ( m_nMaxVisibleItems - 1 );
  925. }
  926. }
  927. //--------------------------------------------------------------------------------------
  928. // Sort the menu items according to the selected column
  929. //--------------------------------------------------------------------------------------
  930. void CDialogMenu::SortMenuItems()
  931. {
  932. if ( !m_bHasHeader )
  933. return;
  934. // Simple bubble sort
  935. char szBufferOne[32];
  936. char szBufferTwo[32];
  937. bool bSortDown = GetColumnSortType( m_nActiveColumn );
  938. for ( int i = 1; i <= m_MenuItems.Count(); ++i )
  939. {
  940. for ( int j = 0; j < m_MenuItems.Count() - i; ++j )
  941. {
  942. ((CSectionedItem*)m_MenuItems[j])->m_Sections[m_nActiveColumn].pLabel->GetText( szBufferOne, sizeof( szBufferOne ) );
  943. ((CSectionedItem*)m_MenuItems[j+1])->m_Sections[m_nActiveColumn].pLabel->GetText( szBufferTwo, sizeof( szBufferTwo ) );
  944. int diff = Q_stricmp( szBufferOne, szBufferTwo );
  945. bool bSwap = bSortDown ? diff > 0 : diff < 0;
  946. if ( bSwap )
  947. {
  948. CMenuItem *pTemp = m_MenuItems[j+1];
  949. m_MenuItems[j+1] = m_MenuItems[j];
  950. m_MenuItems[j] = pTemp;
  951. m_pParent->SwapMenuItems( j, j+1 );
  952. }
  953. }
  954. }
  955. InvalidateLayout();
  956. }
  957. //--------------------------------------------------------------------------------------
  958. // Move item focus to the next item in the menu - supports wrapping
  959. //--------------------------------------------------------------------------------------
  960. void CDialogMenu::SetFocusNext()
  961. {
  962. if ( m_MenuItems.Count() )
  963. {
  964. int iNewIndex = ( m_nActive + 1 ) % m_MenuItems.Count();
  965. int i = 0;
  966. bool bSet = false;
  967. while ( i < m_MenuItems.Count() )
  968. {
  969. if ( m_MenuItems[iNewIndex]->IsEnabled() )
  970. {
  971. SetFocus( iNewIndex );
  972. bSet = true;
  973. break;
  974. }
  975. iNewIndex = ( iNewIndex + 1 ) % m_MenuItems.Count();
  976. i++;
  977. }
  978. InvalidateLayout();
  979. }
  980. }
  981. //--------------------------------------------------------------------------------------
  982. // Move item focus to the previous item in the menu - supports wrapping
  983. //--------------------------------------------------------------------------------------
  984. void CDialogMenu::SetFocusPrev()
  985. {
  986. if ( m_MenuItems.Count() )
  987. {
  988. int iNewIndex = m_nActive - 1;
  989. if ( iNewIndex < 0 )
  990. iNewIndex = m_MenuItems.Count() - 1;
  991. int i = 0;
  992. bool bSet = false;
  993. while ( i < m_MenuItems.Count() )
  994. {
  995. if ( m_MenuItems[iNewIndex]->IsEnabled() )
  996. {
  997. SetFocus( iNewIndex );
  998. bSet = true;
  999. break;
  1000. }
  1001. if ( --iNewIndex < 0 )
  1002. iNewIndex = m_MenuItems.Count() - 1;
  1003. i++;
  1004. }
  1005. InvalidateLayout();
  1006. }
  1007. }
  1008. //--------------------------------------------------------------------------------------
  1009. // For OptionsItems: Move focus to the next option in the menu item - does not wrap
  1010. //--------------------------------------------------------------------------------------
  1011. void CDialogMenu::SetOptionFocusNext()
  1012. {
  1013. COptionsItem *pItem = dynamic_cast< COptionsItem* >( GetItem( m_nActive ) );
  1014. if ( pItem )
  1015. {
  1016. pItem->SetOptionFocusNext();
  1017. KeyValues *kv = new KeyValues( "MenuItemChanged", "item", m_nActive );
  1018. PostActionSignal( kv );
  1019. }
  1020. }
  1021. //--------------------------------------------------------------------------------------
  1022. // For OptionsItems: Move focus to the previous option in the menu item - does not wrap
  1023. //--------------------------------------------------------------------------------------
  1024. void CDialogMenu::SetOptionFocusPrev()
  1025. {
  1026. COptionsItem *pItem = dynamic_cast< COptionsItem* >( GetItem( m_nActive ) );
  1027. if ( pItem )
  1028. {
  1029. pItem->SetOptionFocusPrev();
  1030. KeyValues *kv = new KeyValues( "MenuItemChanged", "item", m_nActive );
  1031. PostActionSignal( kv );
  1032. }
  1033. }
  1034. //--------------------------------------------------------------------------------------
  1035. // For OptionsItems: Update the base index for the columns
  1036. //--------------------------------------------------------------------------------------
  1037. void CDialogMenu::UpdateBaseColumnIndex()
  1038. {
  1039. if ( m_iUnlocked + m_nActiveColumn - m_nBaseColumnIdx >= m_nMaxVisibleColumns )
  1040. {
  1041. m_nBaseColumnIdx = m_iUnlocked + m_nActiveColumn - m_nMaxVisibleColumns + 1;
  1042. }
  1043. else if ( m_nActiveColumn - m_nBaseColumnIdx < 0 )
  1044. {
  1045. m_nBaseColumnIdx = m_nActiveColumn;
  1046. }
  1047. }
  1048. //--------------------------------------------------------------------------------------
  1049. // For menus with sectioned columns - move focus to the next column
  1050. //--------------------------------------------------------------------------------------
  1051. void CDialogMenu::SetColumnFocusNext()
  1052. {
  1053. if ( m_nActiveColumn == -1 )
  1054. return;
  1055. if ( m_Columns.Count() )
  1056. {
  1057. int iNewColumn = m_nActiveColumn + 1;
  1058. if ( iNewColumn >= m_Columns.Count() )
  1059. return;
  1060. m_nActiveColumn = iNewColumn;
  1061. UpdateBaseColumnIndex();
  1062. InvalidateLayout();
  1063. }
  1064. }
  1065. //--------------------------------------------------------------------------------------
  1066. // For menus with sectioned columns - move focus to the next column
  1067. //--------------------------------------------------------------------------------------
  1068. void CDialogMenu::SetColumnFocusPrev()
  1069. {
  1070. if ( m_nActiveColumn == -1 )
  1071. return;
  1072. if ( m_Columns.Count() )
  1073. {
  1074. int iNewColumn = m_nActiveColumn - 1;
  1075. if ( iNewColumn < 0 || m_Columns[iNewColumn].bLocked )
  1076. return;
  1077. m_nActiveColumn = iNewColumn;
  1078. UpdateBaseColumnIndex();
  1079. InvalidateLayout();
  1080. }
  1081. }
  1082. //--------------------------------------------------------------------------------------
  1083. // For OptionsItems: Lets the dialog find out which option is currently selected
  1084. //--------------------------------------------------------------------------------------
  1085. int CDialogMenu::GetActiveOptionIndex( int nMenuItemIdx )
  1086. {
  1087. int retval = -1;
  1088. COptionsItem *pItem = dynamic_cast< COptionsItem* >( GetItem( nMenuItemIdx ) );
  1089. if ( pItem )
  1090. {
  1091. retval = pItem->GetActiveOptionIndex();
  1092. }
  1093. return retval;
  1094. }
  1095. //-----------------------------------------------------------------------
  1096. // Return the index of the current active menu item
  1097. //-----------------------------------------------------------------------
  1098. int CDialogMenu::GetActiveItemIndex()
  1099. {
  1100. return m_nActive;
  1101. }
  1102. //-----------------------------------------------------------------------
  1103. // Return the index of the current active menu column
  1104. //-----------------------------------------------------------------------
  1105. int CDialogMenu::GetActiveColumnIndex()
  1106. {
  1107. return m_nActiveColumn;
  1108. }
  1109. //-----------------------------------------------------------------------
  1110. // Return the number of menu items
  1111. //-----------------------------------------------------------------------
  1112. int CDialogMenu::GetItemCount()
  1113. {
  1114. return m_MenuItems.Count();
  1115. }
  1116. //-----------------------------------------------------------------------
  1117. // Return the number of visible menu items
  1118. //-----------------------------------------------------------------------
  1119. int CDialogMenu::GetVisibleItemCount()
  1120. {
  1121. return min( GetItemCount(), m_nMaxVisibleItems );
  1122. }
  1123. //-----------------------------------------------------------------------
  1124. // Return the number of visible menu columns
  1125. //-----------------------------------------------------------------------
  1126. int CDialogMenu::GetVisibleColumnCount()
  1127. {
  1128. return m_nMaxVisibleColumns;
  1129. }
  1130. //-----------------------------------------------------------------------
  1131. // Return the index of the first unlocked column
  1132. //-----------------------------------------------------------------------
  1133. int CDialogMenu::GetFirstUnlockedColumnIndex()
  1134. {
  1135. return m_iUnlocked;
  1136. }
  1137. //-----------------------------------------------------------------------
  1138. // Return the first visible index in the menu
  1139. //-----------------------------------------------------------------------
  1140. int CDialogMenu::GetBaseRowIndex()
  1141. {
  1142. return m_nBaseRowIdx;
  1143. }
  1144. //-----------------------------------------------------------------------
  1145. // Set the first visible index in the menu
  1146. //-----------------------------------------------------------------------
  1147. void CDialogMenu::SetBaseRowIndex( int idx )
  1148. {
  1149. m_nBaseRowIdx = idx;
  1150. }
  1151. //-----------------------------------------------------------------------
  1152. // Return the specified menu item
  1153. //-----------------------------------------------------------------------
  1154. CMenuItem *CDialogMenu::GetItem( int idx )
  1155. {
  1156. if ( m_MenuItems.IsValidIndex( idx ) )
  1157. {
  1158. return m_MenuItems[idx];
  1159. }
  1160. return NULL;
  1161. }
  1162. //-----------------------------------------------------------------------
  1163. // Return the specified column xpos
  1164. //-----------------------------------------------------------------------
  1165. int CDialogMenu::GetColumnXPos( int idx )
  1166. {
  1167. // Compensate for scrolling offsets
  1168. columninfo_s &col = m_Columns[idx];
  1169. int xpos;
  1170. if ( col.bLocked )
  1171. {
  1172. xpos = m_Columns[idx].xpos;
  1173. }
  1174. else
  1175. {
  1176. int trueIdx = m_iUnlocked + idx - m_nBaseColumnIdx;
  1177. if ( trueIdx < m_iUnlocked )
  1178. {
  1179. // Put it offscreen
  1180. xpos = -100 - col.wide;
  1181. }
  1182. else
  1183. {
  1184. xpos = m_Columns[trueIdx].xpos;
  1185. }
  1186. }
  1187. return xpos;
  1188. }
  1189. //-----------------------------------------------------------------------
  1190. // Return the specified column ypos
  1191. //-----------------------------------------------------------------------
  1192. int CDialogMenu::GetColumnYPos( int idx )
  1193. {
  1194. return m_Columns[idx].ypos;
  1195. }
  1196. //-----------------------------------------------------------------------
  1197. // Return the specified column width
  1198. //-----------------------------------------------------------------------
  1199. int CDialogMenu::GetColumnWide( int idx )
  1200. {
  1201. return m_Columns[idx].wide;
  1202. }
  1203. //-----------------------------------------------------------------------
  1204. // Return the specified column alignment
  1205. //-----------------------------------------------------------------------
  1206. int CDialogMenu::GetColumnAlignment( int idx )
  1207. {
  1208. return m_Columns[idx].align;
  1209. }
  1210. //-----------------------------------------------------------------------
  1211. // Return the specified column font
  1212. //-----------------------------------------------------------------------
  1213. HFont CDialogMenu::GetColumnFont( int idx )
  1214. {
  1215. return m_Columns[idx].hFont;
  1216. }
  1217. //-----------------------------------------------------------------------
  1218. // Return the specified column fgcolor
  1219. //-----------------------------------------------------------------------
  1220. Color CDialogMenu::GetColumnColor( int idx )
  1221. {
  1222. return m_Columns[idx].color;
  1223. }
  1224. //-----------------------------------------------------------------------
  1225. // Return the specified column fgcolor
  1226. //-----------------------------------------------------------------------
  1227. bool CDialogMenu::GetColumnSortType( int idx )
  1228. {
  1229. bool bSortDown = m_Columns[idx].bSortDown;
  1230. m_Columns[idx].bSortDown = !bSortDown;
  1231. return bSortDown;
  1232. }
  1233. //--------------------------------------------------------------------------------------
  1234. // Receive the command from a clicked menu item and forwards it to the parent dialog
  1235. //--------------------------------------------------------------------------------------
  1236. void CDialogMenu::OnCommand( const char *pCommand )
  1237. {
  1238. GetParent()->OnCommand( pCommand );
  1239. }
  1240. //--------------------------------------------------------------------------------------
  1241. // Update the menu state according to controller input.
  1242. // Returns whether or not the keycode was handled by the menu.
  1243. //--------------------------------------------------------------------------------------
  1244. bool CDialogMenu::HandleKeyCode( vgui::KeyCode code )
  1245. {
  1246. switch( code )
  1247. {
  1248. case KEY_XBUTTON_DOWN:
  1249. case KEY_XSTICK1_DOWN:
  1250. case STEAMCONTROLLER_DPAD_DOWN:
  1251. SetFocusNext();
  1252. break;
  1253. case KEY_XBUTTON_UP:
  1254. case KEY_XSTICK1_UP:
  1255. case STEAMCONTROLLER_DPAD_UP:
  1256. SetFocusPrev();
  1257. break;
  1258. case KEY_XBUTTON_LEFT:
  1259. case KEY_XSTICK1_LEFT:
  1260. case STEAMCONTROLLER_DPAD_LEFT:
  1261. SetOptionFocusPrev();
  1262. SetColumnFocusPrev();
  1263. break;
  1264. case KEY_XBUTTON_RIGHT:
  1265. case KEY_XSTICK1_RIGHT:
  1266. case STEAMCONTROLLER_DPAD_RIGHT:
  1267. SetOptionFocusNext();
  1268. SetColumnFocusNext();
  1269. break;
  1270. case KEY_XBUTTON_A:
  1271. case STEAMCONTROLLER_A:
  1272. if ( m_MenuItems.Count() && m_nActive >= 0 )
  1273. {
  1274. m_MenuItems[m_nActive]->OnClick();
  1275. }
  1276. break;
  1277. case KEY_XBUTTON_Y:
  1278. case STEAMCONTROLLER_Y:
  1279. SortMenuItems();
  1280. break;
  1281. default:
  1282. // Not handled
  1283. return false;
  1284. }
  1285. return true;
  1286. }