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.

1292 lines
35 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "ienginevgui.h"
  8. #include <vgui_controls/ScrollBarSlider.h>
  9. #include "vgui/ILocalize.h"
  10. #include "vgui/ISurface.h"
  11. #include "vgui/IInput.h"
  12. #include "tf_controls.h"
  13. #include "vgui_controls/TextImage.h"
  14. #include "vgui_controls/PropertyPage.h"
  15. #include "econ_item_system.h"
  16. #include "iachievementmgr.h"
  17. #include <vgui_controls/ListPanel.h>
  18. #include <vgui_controls/PanelListPanel.h>
  19. #include <vgui_controls/Label.h>
  20. #include <vgui_controls/Button.h>
  21. #include <vgui_controls/MessageBox.h>
  22. #include <vgui_controls/CheckButton.h>
  23. #include <vgui_controls/ComboBox.h>
  24. #include <vgui_controls/TextEntry.h>
  25. #include <../common/GameUI/cvarslider.h>
  26. #include "filesystem.h"
  27. using namespace vgui;
  28. wchar_t* LocalizeNumberWithToken( const char* pszLocToken, int nValue )
  29. {
  30. static wchar_t wszOutString[ 128 ];
  31. wchar_t wszCount[ 16 ];
  32. _snwprintf( wszCount, ARRAYSIZE( wszCount ), L"%d", nValue );
  33. const wchar_t *wpszFormat = g_pVGuiLocalize->Find( pszLocToken );
  34. g_pVGuiLocalize->ConstructString_safe( wszOutString, wpszFormat, 1, wszCount );
  35. return wszOutString;
  36. }
  37. DECLARE_BUILD_FACTORY( CExCheckButton );
  38. DECLARE_BUILD_FACTORY( CTFFooter );
  39. //-----------------------------------------------------------------------------
  40. // Purpose: Xbox-specific panel that displays button icons text labels
  41. //-----------------------------------------------------------------------------
  42. CTFFooter::CTFFooter( Panel *parent, const char *panelName ) : BaseClass( parent, panelName )
  43. {
  44. SetVisible( true );
  45. SetAlpha( 0 );
  46. m_nButtonGap = 32;
  47. m_ButtonPinRight = 100;
  48. m_FooterTall = 80;
  49. m_ButtonOffsetFromTop = 0;
  50. m_ButtonSeparator = 4;
  51. m_TextAdjust = 0;
  52. m_bPaintBackground = false;
  53. m_bCenterHorizontal = true;
  54. m_szButtonFont[0] = '\0';
  55. m_szTextFont[0] = '\0';
  56. m_szFGColor[0] = '\0';
  57. m_szBGColor[0] = '\0';
  58. }
  59. //-----------------------------------------------------------------------------
  60. // Purpose:
  61. //-----------------------------------------------------------------------------
  62. CTFFooter::~CTFFooter()
  63. {
  64. ClearButtons();
  65. }
  66. //-----------------------------------------------------------------------------
  67. // Purpose:
  68. //-----------------------------------------------------------------------------
  69. void CTFFooter::ApplySchemeSettings( vgui::IScheme *pScheme )
  70. {
  71. BaseClass::ApplySchemeSettings( pScheme );
  72. m_hButtonFont = pScheme->GetFont( ( m_szButtonFont[0] != '\0' ) ? m_szButtonFont : "GameUIButtons" );
  73. m_hTextFont = pScheme->GetFont( ( m_szTextFont[0] != '\0' ) ? m_szTextFont : "MenuLarge" );
  74. SetFgColor( pScheme->GetColor( m_szFGColor, Color( 255, 255, 255, 255 ) ) );
  75. SetBgColor( pScheme->GetColor( m_szBGColor, Color( 0, 0, 0, 255 ) ) );
  76. int x, y, w, h;
  77. GetParent()->GetBounds( x, y, w, h );
  78. SetBounds( x, h - m_FooterTall, w, m_FooterTall );
  79. }
  80. //-----------------------------------------------------------------------------
  81. // Purpose:
  82. //-----------------------------------------------------------------------------
  83. void CTFFooter::ApplySettings( KeyValues *inResourceData )
  84. {
  85. BaseClass::ApplySettings( inResourceData );
  86. // gap between hints
  87. m_nButtonGap = inResourceData->GetInt( "buttongap", 32 );
  88. m_ButtonPinRight = inResourceData->GetInt( "button_pin_right", 100 );
  89. m_FooterTall = inResourceData->GetInt( "tall", 80 );
  90. m_ButtonOffsetFromTop = inResourceData->GetInt( "buttonoffsety", 0 );
  91. m_ButtonSeparator = inResourceData->GetInt( "button_separator", 4 );
  92. m_TextAdjust = inResourceData->GetInt( "textadjust", 0 );
  93. m_bCenterHorizontal = ( inResourceData->GetInt( "center", 1 ) == 1 );
  94. m_bPaintBackground = ( inResourceData->GetInt( "paintbackground", 0 ) == 1 );
  95. // fonts for text and button
  96. Q_strncpy( m_szTextFont, inResourceData->GetString( "fonttext", "MenuLarge" ), sizeof( m_szTextFont ) );
  97. Q_strncpy( m_szButtonFont, inResourceData->GetString( "fontbutton", "GameUIButtons" ), sizeof( m_szButtonFont ) );
  98. // fg and bg colors
  99. Q_strncpy( m_szFGColor, inResourceData->GetString( "fgcolor", "White" ), sizeof( m_szFGColor ) );
  100. Q_strncpy( m_szBGColor, inResourceData->GetString( "bgcolor", "Black" ), sizeof( m_szBGColor ) );
  101. // clear the buttons because we're going to re-add them here
  102. ClearButtons();
  103. for ( KeyValues *pButton = inResourceData->GetFirstSubKey(); pButton != NULL; pButton = pButton->GetNextKey() )
  104. {
  105. const char *pNameButton = pButton->GetName();
  106. if ( !Q_stricmp( pNameButton, "button" ) )
  107. {
  108. // Add a button to the footer
  109. const char *pName = pButton->GetString( "name", "NULL" );
  110. const char *pText = pButton->GetString( "text", "NULL" );
  111. const char *pIcon = pButton->GetString( "icon", "NULL" );
  112. AddNewButtonLabel( pName, pText, pIcon );
  113. }
  114. }
  115. InvalidateLayout( false, true ); // force ApplySchemeSettings to run
  116. }
  117. //-----------------------------------------------------------------------------
  118. // Purpose:
  119. //-----------------------------------------------------------------------------
  120. void CTFFooter::AddNewButtonLabel( const char *name, const char *text, const char *icon )
  121. {
  122. FooterButton_t *button = new FooterButton_t;
  123. button->bVisible = true;
  124. Q_strncpy( button->name, name, sizeof( button->name ) );
  125. // Button icons are a single character
  126. wchar_t *pIcon = g_pVGuiLocalize->Find( icon );
  127. if ( pIcon )
  128. {
  129. button->icon[0] = pIcon[0];
  130. button->icon[1] = '\0';
  131. }
  132. else
  133. {
  134. button->icon[0] = '\0';
  135. }
  136. // Set the help text
  137. wchar_t *pText = g_pVGuiLocalize->Find( text );
  138. if ( pText )
  139. {
  140. wcsncpy( button->text, pText, wcslen( pText ) + 1 );
  141. }
  142. else
  143. {
  144. button->text[0] = '\0';
  145. }
  146. m_Buttons.AddToTail( button );
  147. }
  148. //-----------------------------------------------------------------------------
  149. // Purpose:
  150. //-----------------------------------------------------------------------------
  151. void CTFFooter::ShowButtonLabel( const char *name, bool show )
  152. {
  153. for ( int i = 0; i < m_Buttons.Count(); ++i )
  154. {
  155. if ( !Q_stricmp( m_Buttons[ i ]->name, name ) )
  156. {
  157. m_Buttons[ i ]->bVisible = show;
  158. break;
  159. }
  160. }
  161. }
  162. //-----------------------------------------------------------------------------
  163. // Purpose:
  164. //-----------------------------------------------------------------------------
  165. void CTFFooter::PaintBackground( void )
  166. {
  167. if ( !m_bPaintBackground )
  168. return;
  169. BaseClass::PaintBackground();
  170. }
  171. //-----------------------------------------------------------------------------
  172. // Purpose:
  173. //-----------------------------------------------------------------------------
  174. void CTFFooter::Paint( void )
  175. {
  176. // inset from right edge
  177. int wide = GetWide();
  178. // center the text within the button
  179. int buttonHeight = vgui::surface()->GetFontTall( m_hButtonFont );
  180. int fontHeight = vgui::surface()->GetFontTall( m_hTextFont );
  181. int textY = ( buttonHeight - fontHeight )/2 + m_TextAdjust;
  182. if ( textY < 0 )
  183. {
  184. textY = 0;
  185. }
  186. int y = m_ButtonOffsetFromTop;
  187. if ( !m_bCenterHorizontal )
  188. {
  189. // draw the buttons, right to left
  190. int x = wide - m_ButtonPinRight;
  191. vgui::Label label( this, "temp", L"" );
  192. for ( int i = m_Buttons.Count() - 1 ; i >= 0 ; --i )
  193. {
  194. FooterButton_t *pButton = m_Buttons[i];
  195. if ( !pButton->bVisible )
  196. continue;
  197. // Get the string length
  198. label.SetFont( m_hTextFont );
  199. label.SetText( pButton->text );
  200. label.SizeToContents();
  201. int iTextWidth = label.GetWide();
  202. if ( iTextWidth == 0 )
  203. x += m_nButtonGap; // There's no text, so remove the gap between buttons
  204. else
  205. x -= iTextWidth;
  206. // Draw the string
  207. vgui::surface()->DrawSetTextFont( m_hTextFont );
  208. vgui::surface()->DrawSetTextColor( GetFgColor() );
  209. vgui::surface()->DrawSetTextPos( x, y + textY );
  210. vgui::surface()->DrawPrintText( pButton->text, wcslen( pButton->text ) );
  211. // Draw the button
  212. // back up button width and a little extra to leave a gap between button and text
  213. x -= ( vgui::surface()->GetCharacterWidth( m_hButtonFont, pButton->icon[0] ) + m_ButtonSeparator );
  214. vgui::surface()->DrawSetTextFont( m_hButtonFont );
  215. vgui::surface()->DrawSetTextColor( 255, 255, 255, 255 );
  216. vgui::surface()->DrawSetTextPos( x, y );
  217. vgui::surface()->DrawPrintText( pButton->icon, 1 );
  218. // back up to next string
  219. x -= m_nButtonGap;
  220. }
  221. }
  222. else
  223. {
  224. // center the buttons (as a group)
  225. int x = wide / 2;
  226. int totalWidth = 0;
  227. int i = 0;
  228. int nButtonCount = 0;
  229. vgui::Label label( this, "temp", L"" );
  230. // need to loop through and figure out how wide our buttons and text are (with gaps between) so we can offset from the center
  231. for ( i = 0; i < m_Buttons.Count(); ++i )
  232. {
  233. FooterButton_t *pButton = m_Buttons[i];
  234. if ( !pButton->bVisible )
  235. continue;
  236. // Get the string length
  237. label.SetFont( m_hTextFont );
  238. label.SetText( pButton->text );
  239. label.SizeToContents();
  240. totalWidth += vgui::surface()->GetCharacterWidth( m_hButtonFont, pButton->icon[0] );
  241. totalWidth += m_ButtonSeparator;
  242. totalWidth += label.GetWide();
  243. nButtonCount++; // keep track of how many active buttons we'll be drawing
  244. }
  245. totalWidth += ( nButtonCount - 1 ) * m_nButtonGap; // add in the gaps between the buttons
  246. x -= ( totalWidth / 2 );
  247. for ( i = 0; i < m_Buttons.Count(); ++i )
  248. {
  249. FooterButton_t *pButton = m_Buttons[i];
  250. if ( !pButton->bVisible )
  251. continue;
  252. // Get the string length
  253. label.SetFont( m_hTextFont );
  254. label.SetText( pButton->text );
  255. label.SizeToContents();
  256. int iTextWidth = label.GetWide();
  257. // Draw the icon
  258. vgui::surface()->DrawSetTextFont( m_hButtonFont );
  259. vgui::surface()->DrawSetTextColor( 255, 255, 255, 255 );
  260. vgui::surface()->DrawSetTextPos( x, y );
  261. vgui::surface()->DrawPrintText( pButton->icon, 1 );
  262. x += vgui::surface()->GetCharacterWidth( m_hButtonFont, pButton->icon[0] ) + m_ButtonSeparator;
  263. // Draw the string
  264. vgui::surface()->DrawSetTextFont( m_hTextFont );
  265. vgui::surface()->DrawSetTextColor( GetFgColor() );
  266. vgui::surface()->DrawSetTextPos( x, y + textY );
  267. vgui::surface()->DrawPrintText( pButton->text, wcslen( pButton->text ) );
  268. x += iTextWidth + m_nButtonGap;
  269. }
  270. }
  271. }
  272. //-----------------------------------------------------------------------------
  273. // Purpose:
  274. //-----------------------------------------------------------------------------
  275. void CTFFooter::ClearButtons( void )
  276. {
  277. m_Buttons.PurgeAndDeleteElements();
  278. }
  279. #define OPTIONS_DIR "cfg"
  280. #define DEFAULT_OPTIONS_FILE OPTIONS_DIR "/user_default.scr"
  281. #define OPTIONS_FILE OPTIONS_DIR "/user.scr"
  282. //-----------------------------------------------------------------------------
  283. // Purpose: Constructor
  284. //-----------------------------------------------------------------------------
  285. CTFAdvancedOptionsDialog::CTFAdvancedOptionsDialog(vgui::Panel *parent) : BaseClass(NULL, "TFAdvancedOptionsDialog")
  286. {
  287. // Need to use the clientscheme (we're not parented to a clientscheme'd panel)
  288. vgui::HScheme scheme = vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), "resource/ClientScheme.res", "ClientScheme");
  289. SetScheme(scheme);
  290. SetProportional( true );
  291. m_pListPanel = new vgui::PanelListPanel( this, "PanelListPanel" );
  292. m_pList = NULL;
  293. m_pToolTip = new CTFTextToolTip( this );
  294. m_pToolTipEmbeddedPanel = new vgui::EditablePanel( this, "TooltipPanel" );
  295. m_pToolTipEmbeddedPanel->SetKeyBoardInputEnabled( false );
  296. m_pToolTipEmbeddedPanel->SetMouseInputEnabled( false );
  297. m_pToolTip->SetEmbeddedPanel( m_pToolTipEmbeddedPanel );
  298. m_pToolTip->SetTooltipDelay( 0 );
  299. m_pDescription = new CInfoDescription();
  300. m_pDescription->InitFromFile( DEFAULT_OPTIONS_FILE );
  301. m_pDescription->InitFromFile( OPTIONS_FILE, false );
  302. m_pDescription->TransferCurrentValues( NULL );
  303. // MoveToCenterOfScreen();
  304. // SetSizeable( false );
  305. // SetDeleteSelfOnClose( true );
  306. }
  307. //-----------------------------------------------------------------------------
  308. // Purpose: Destructor
  309. //-----------------------------------------------------------------------------
  310. CTFAdvancedOptionsDialog::~CTFAdvancedOptionsDialog()
  311. {
  312. delete m_pDescription;
  313. }
  314. //-----------------------------------------------------------------------------
  315. // Purpose:
  316. //-----------------------------------------------------------------------------
  317. void CTFAdvancedOptionsDialog::ApplySchemeSettings( vgui::IScheme *pScheme )
  318. {
  319. BaseClass::ApplySchemeSettings( pScheme );
  320. LoadControlSettings("resource/ui/TFAdvancedOptionsDialog.res");
  321. m_pListPanel->SetFirstColumnWidth( 0 );
  322. CreateControls();
  323. }
  324. //-----------------------------------------------------------------------------
  325. // Purpose:
  326. //-----------------------------------------------------------------------------
  327. void CTFAdvancedOptionsDialog::ApplySettings( KeyValues *inResourceData )
  328. {
  329. BaseClass::ApplySettings( inResourceData );
  330. }
  331. //-----------------------------------------------------------------------------
  332. // Purpose:
  333. //-----------------------------------------------------------------------------
  334. void CTFAdvancedOptionsDialog::OnClose()
  335. {
  336. BaseClass::OnClose();
  337. TFModalStack()->PopModal( this );
  338. MarkForDeletion();
  339. }
  340. //-----------------------------------------------------------------------------
  341. // Purpose:
  342. // Input : *command -
  343. //-----------------------------------------------------------------------------
  344. void CTFAdvancedOptionsDialog::OnCommand( const char *command )
  345. {
  346. if ( !stricmp( command, "Ok" ) )
  347. {
  348. // OnApplyChanges();
  349. SaveValues();
  350. OnClose();
  351. return;
  352. }
  353. else if ( !stricmp( command, "Close" ) )
  354. {
  355. OnClose();
  356. return;
  357. }
  358. BaseClass::OnCommand( command );
  359. }
  360. void CTFAdvancedOptionsDialog::OnKeyCodeTyped(KeyCode code)
  361. {
  362. // force ourselves to be closed if the escape key it pressed
  363. if ( code == KEY_ESCAPE )
  364. {
  365. OnClose();
  366. }
  367. else
  368. {
  369. BaseClass::OnKeyCodeTyped(code);
  370. }
  371. }
  372. //-----------------------------------------------------------------------------
  373. // Purpose:
  374. //-----------------------------------------------------------------------------
  375. void CTFAdvancedOptionsDialog::OnKeyCodePressed(KeyCode code)
  376. {
  377. // force ourselves to be closed if the escape key it pressed
  378. if ( GetBaseButtonCode( code ) == KEY_XBUTTON_B || GetBaseButtonCode( code ) == STEAMCONTROLLER_B || GetBaseButtonCode( code ) == STEAMCONTROLLER_START )
  379. {
  380. OnClose();
  381. }
  382. else
  383. {
  384. BaseClass::OnKeyCodePressed(code);
  385. }
  386. }
  387. //-----------------------------------------------------------------------------
  388. // Purpose:
  389. //-----------------------------------------------------------------------------
  390. void CTFAdvancedOptionsDialog::GatherCurrentValues()
  391. {
  392. if ( !m_pDescription )
  393. return;
  394. // OK
  395. CheckButton *pBox;
  396. TextEntry *pEdit;
  397. ComboBox *pCombo;
  398. CCvarSlider *pSlider;
  399. mpcontrol_t *pList;
  400. CScriptObject *pObj;
  401. CScriptListItem *pItem;
  402. char szValue[256];
  403. char strValue[ 256 ];
  404. pList = m_pList;
  405. while ( pList )
  406. {
  407. pObj = pList->pScrObj;
  408. if ( pObj->type == O_CATEGORY )
  409. {
  410. pList = pList->next;
  411. continue;
  412. }
  413. if ( !pList->pControl )
  414. {
  415. pObj->SetCurValue( pObj->defValue );
  416. pList = pList->next;
  417. continue;
  418. }
  419. switch ( pObj->type )
  420. {
  421. case O_BOOL:
  422. pBox = (CheckButton *)pList->pControl;
  423. sprintf( szValue, "%s", pBox->IsSelected() ? "1" : "0" );
  424. break;
  425. case O_NUMBER:
  426. pEdit = ( TextEntry * )pList->pControl;
  427. pEdit->GetText( strValue, sizeof( strValue ) );
  428. sprintf( szValue, "%s", strValue );
  429. break;
  430. case O_STRING:
  431. pEdit = ( TextEntry * )pList->pControl;
  432. pEdit->GetText( strValue, sizeof( strValue ) );
  433. sprintf( szValue, "%s", strValue );
  434. break;
  435. case O_LIST:
  436. {
  437. pCombo = (ComboBox *)pList->pControl;
  438. // pCombo->GetText( strValue, sizeof( strValue ) );
  439. int activeItem = pCombo->GetActiveItem();
  440. pItem = pObj->pListItems;
  441. // int n = (int)pObj->fdefValue;
  442. while ( pItem )
  443. {
  444. if (!activeItem--)
  445. break;
  446. pItem = pItem->pNext;
  447. }
  448. if ( pItem )
  449. {
  450. sprintf( szValue, "%s", pItem->szValue );
  451. }
  452. else // Couln't find index
  453. {
  454. //assert(!("Couldn't find string in list, using default value"));
  455. sprintf( szValue, "%s", pObj->defValue );
  456. }
  457. break;
  458. }
  459. case O_SLIDER:
  460. pSlider = ( CCvarSlider * )pList->pControl;
  461. sprintf( szValue, "%.2f", pSlider->GetSliderValue() );
  462. break;
  463. }
  464. // Remove double quotes and % characters
  465. UTIL_StripInvalidCharacters( szValue, sizeof(szValue) );
  466. V_strcpy_safe( strValue, szValue );
  467. pObj->SetCurValue( strValue );
  468. pList = pList->next;
  469. }
  470. }
  471. //-----------------------------------------------------------------------------
  472. // Purpose:
  473. //-----------------------------------------------------------------------------
  474. void CTFAdvancedOptionsDialog::CreateControls()
  475. {
  476. DestroyControls();
  477. // Go through desciption creating controls
  478. CScriptObject *pObj;
  479. pObj = m_pDescription->pObjList;
  480. // Build out the clan dropdown
  481. CScriptObject *pClanObj = m_pDescription->FindObject( "cl_clanid" );
  482. ISteamFriends *pFriends = steamapicontext->SteamFriends();
  483. if ( pFriends && pClanObj )
  484. {
  485. pClanObj->RemoveAndDeleteAllItems();
  486. int iGroupCount = pFriends->GetClanCount();
  487. pClanObj->AddItem( new CScriptListItem( "#Cstrike_ClanTag_None", "0" ) );
  488. for ( int k = 0; k < iGroupCount; ++ k )
  489. {
  490. CSteamID clanID = pFriends->GetClanByIndex( k );
  491. const char *pName = pFriends->GetClanName( clanID );
  492. const char *pTag = pFriends->GetClanTag( clanID );
  493. char id[12];
  494. Q_snprintf( id, sizeof( id ), "%d", clanID.GetAccountID() );
  495. pClanObj->AddItem( new CScriptListItem( CFmtStr( "%s (%s)", pTag, pName ), id ) );
  496. }
  497. }
  498. mpcontrol_t *pCtrl;
  499. CheckButton *pBox;
  500. TextEntry *pEdit;
  501. ComboBox *pCombo;
  502. CCvarSlider *pSlider;
  503. CScriptListItem *pListItem;
  504. Panel *objParent = m_pListPanel;
  505. IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
  506. vgui::HFont hTextFont = pScheme->GetFont( "HudFontSmallestBold", true );
  507. Color tanDark = pScheme->GetColor( "TanDark", Color(255,0,0,255) );
  508. while ( pObj )
  509. {
  510. if ( pObj->type == O_OBSOLETE )
  511. {
  512. pObj = pObj->pNext;
  513. continue;
  514. }
  515. pCtrl = new mpcontrol_t( objParent, "mpcontrol_t" );
  516. pCtrl->type = pObj->type;
  517. // Force it to invalidate scheme now, so we can change color afterwards and have it persist
  518. pCtrl->InvalidateLayout( true, true );
  519. switch ( pCtrl->type )
  520. {
  521. case O_BOOL:
  522. pBox = new CheckButton( pCtrl, "DescCheckButton", pObj->prompt );
  523. pBox->SetSelected( pObj->fdefValue != 0.0f ? true : false );
  524. pCtrl->pControl = (Panel *)pBox;
  525. pBox->SetFont( hTextFont );
  526. pBox->InvalidateLayout( true, true );
  527. // This is utterly fucking retarded.
  528. pBox->SetFgColor( tanDark );
  529. pBox->SetDefaultColor( tanDark, pBox->GetBgColor() );
  530. pBox->SetArmedColor( tanDark, pBox->GetBgColor() );
  531. pBox->SetDepressedColor( tanDark, pBox->GetBgColor() );
  532. pBox->SetSelectedColor( tanDark, pBox->GetBgColor() );
  533. pBox->SetHighlightColor( tanDark );
  534. pBox->GetCheckImage()->SetColor( tanDark );
  535. break;
  536. case O_STRING:
  537. case O_NUMBER:
  538. pEdit = new TextEntry( pCtrl, "DescTextEntry");
  539. pEdit->InsertString(pObj->defValue);
  540. pCtrl->pControl = (Panel *)pEdit;
  541. pEdit->SetFont( hTextFont );
  542. pEdit->InvalidateLayout( true, true );
  543. pEdit->SetBgColor( Color(0,0,0,255) );
  544. break;
  545. case O_LIST:
  546. {
  547. pCombo = new ComboBox( pCtrl, "DescComboBox", 5, false );
  548. // track which row matches the current value
  549. int iRow = -1;
  550. int iCount = 0;
  551. pListItem = pObj->pListItems;
  552. while ( pListItem )
  553. {
  554. if ( iRow == -1 && !Q_stricmp( pListItem->szValue, pObj->curValue ) )
  555. iRow = iCount;
  556. pCombo->AddItem( pListItem->szItemText, NULL );
  557. pListItem = pListItem->pNext;
  558. ++iCount;
  559. }
  560. pCombo->ActivateItemByRow( iRow );
  561. pCtrl->pControl = (Panel *)pCombo;
  562. pCombo->SetFont( hTextFont );
  563. }
  564. break;
  565. case O_SLIDER:
  566. pSlider = new CCvarSlider( pCtrl, "DescSlider", "Test", pObj->fMin, pObj->fMax, pObj->cvarname, false );
  567. pCtrl->pControl = (Panel *)pSlider;
  568. break;
  569. case O_CATEGORY:
  570. pCtrl->SetBorder( pScheme->GetBorder("OptionsCategoryBorder") );
  571. break;
  572. default:
  573. break;
  574. }
  575. if ( pCtrl->type != O_BOOL )
  576. {
  577. pCtrl->pPrompt = new vgui::Label( pCtrl, "DescLabel", "" );
  578. pCtrl->pPrompt->SetContentAlignment( vgui::Label::a_west );
  579. pCtrl->pPrompt->SetTextInset( 5, 0 );
  580. pCtrl->pPrompt->SetText( pObj->prompt );
  581. pCtrl->pPrompt->SetFont( hTextFont );
  582. pCtrl->pPrompt->InvalidateLayout( true, true );
  583. if ( pCtrl->type == O_CATEGORY )
  584. {
  585. pCtrl->pPrompt->SetFont( pScheme->GetFont( "HudFontSmallBold", true ) );
  586. pCtrl->pPrompt->SetFgColor( pScheme->GetColor( "TanLight", Color(255,0,0,255) ) );
  587. }
  588. else
  589. {
  590. pCtrl->pPrompt->SetFgColor( tanDark );
  591. }
  592. }
  593. pCtrl->pScrObj = pObj;
  594. switch ( pCtrl->type )
  595. {
  596. case O_BOOL:
  597. case O_STRING:
  598. case O_NUMBER:
  599. case O_LIST:
  600. case O_CATEGORY:
  601. pCtrl->SetSize( m_iControlW, m_iControlH );
  602. break;
  603. case O_SLIDER:
  604. pCtrl->SetSize( m_iSliderW, m_iSliderH );
  605. break;
  606. default:
  607. break;
  608. }
  609. // Hook up the tooltip, if the entry has one
  610. if ( pObj->tooltip && pObj->tooltip[0] )
  611. {
  612. if ( pCtrl->pPrompt )
  613. {
  614. pCtrl->pPrompt->SetTooltip( m_pToolTip, pObj->tooltip );
  615. }
  616. else
  617. {
  618. pCtrl->SetTooltip( m_pToolTip, pObj->tooltip );
  619. pCtrl->pControl->SetTooltip( m_pToolTip, pObj->tooltip );
  620. }
  621. }
  622. m_pListPanel->AddItem( NULL, pCtrl );
  623. // Link it in
  624. if ( !m_pList )
  625. {
  626. m_pList = pCtrl;
  627. pCtrl->next = NULL;
  628. }
  629. else
  630. {
  631. mpcontrol_t *p;
  632. p = m_pList;
  633. while ( p )
  634. {
  635. if ( !p->next )
  636. {
  637. p->next = pCtrl;
  638. pCtrl->next = NULL;
  639. break;
  640. }
  641. p = p->next;
  642. }
  643. }
  644. pObj = pObj->pNext;
  645. }
  646. }
  647. //-----------------------------------------------------------------------------
  648. // Purpose:
  649. //-----------------------------------------------------------------------------
  650. void CTFAdvancedOptionsDialog::DestroyControls()
  651. {
  652. mpcontrol_t *p, *n;
  653. p = m_pList;
  654. while ( p )
  655. {
  656. n = p->next;
  657. //
  658. if ( p->pControl )
  659. {
  660. p->pControl->MarkForDeletion();
  661. p->pControl = NULL;
  662. }
  663. if ( p->pPrompt )
  664. {
  665. p->pPrompt->MarkForDeletion();
  666. p->pPrompt = NULL;
  667. }
  668. delete p;
  669. p = n;
  670. }
  671. m_pList = NULL;
  672. }
  673. //-----------------------------------------------------------------------------
  674. // Purpose:
  675. //-----------------------------------------------------------------------------
  676. void CTFAdvancedOptionsDialog::SaveValues()
  677. {
  678. // Get the values from the controls:
  679. GatherCurrentValues();
  680. // Create the game.cfg file
  681. if ( m_pDescription )
  682. {
  683. FileHandle_t fp;
  684. // Add settings to config.cfg
  685. m_pDescription->WriteToConfig();
  686. g_pFullFileSystem->CreateDirHierarchy( OPTIONS_DIR );
  687. fp = g_pFullFileSystem->Open( OPTIONS_FILE, "wb" );
  688. if ( fp )
  689. {
  690. m_pDescription->WriteToScriptFile( fp );
  691. g_pFullFileSystem->Close( fp );
  692. }
  693. }
  694. }
  695. //-----------------------------------------------------------------------------
  696. // Purpose:
  697. //-----------------------------------------------------------------------------
  698. void CTFAdvancedOptionsDialog::Deploy( void )
  699. {
  700. SetVisible( true );
  701. MakePopup();
  702. MoveToFront();
  703. SetKeyBoardInputEnabled(true);
  704. SetMouseInputEnabled(true);
  705. TFModalStack()->PushModal( this );
  706. // Center it, keeping requested size
  707. int x, y, ww, wt, wide, tall;
  708. vgui::surface()->GetWorkspaceBounds( x, y, ww, wt );
  709. GetSize(wide, tall);
  710. SetPos(x + ((ww - wide) / 2), y + ((wt - tall) / 2));
  711. }
  712. //-----------------------------------------------------------------------------
  713. // Purpose:
  714. //-----------------------------------------------------------------------------
  715. void CTFTextToolTip::PerformLayout()
  716. {
  717. if ( !ShouldLayout() )
  718. return;
  719. _isDirty = false;
  720. // Resize our text labels to fit.
  721. int iW = m_pEmbeddedPanel->GetWide();
  722. int iH = 0;
  723. for (int i = 0; i < m_pEmbeddedPanel->GetChildCount(); i++)
  724. {
  725. vgui::Label *pLabel = dynamic_cast<vgui::Label*>( m_pEmbeddedPanel->GetChild(i) );
  726. if ( !pLabel )
  727. continue;
  728. // Only checking to see if we have any text
  729. char szTmp[2];
  730. pLabel->GetText( szTmp, sizeof(szTmp) );
  731. if ( !szTmp[0] )
  732. continue;
  733. int iLX, iLY;
  734. pLabel->GetPos( iLX, iLY );
  735. int iMaxWidth = m_pEmbeddedPanel->GetWide() - (iLX * 2);
  736. pLabel->GetTextImage()->ResizeImageToContentMaxWidth( iMaxWidth );
  737. pLabel->SizeToContents();
  738. pLabel->SetWide( iMaxWidth );
  739. pLabel->InvalidateLayout(true);
  740. int iX, iY;
  741. pLabel->GetPos( iX, iY );
  742. iW = MAX( iW, ( pLabel->GetWide() + (iX * 2) ) );
  743. if ( iH == 0 )
  744. {
  745. iH += MAX( iH, pLabel->GetTall() + (iY * 2) );
  746. }
  747. else
  748. {
  749. iH += MAX( iH, pLabel->GetTall() );
  750. }
  751. }
  752. m_pEmbeddedPanel->SetSize( m_pEmbeddedPanel->GetWide(), iH );
  753. m_pEmbeddedPanel->SetVisible(true);
  754. PositionWindow( m_pEmbeddedPanel );
  755. }
  756. //-----------------------------------------------------------------------------
  757. // Purpose:
  758. //-----------------------------------------------------------------------------
  759. void CTFTextToolTip::PositionWindow( Panel *pTipPanel )
  760. {
  761. int iTipW, iTipH;
  762. pTipPanel->GetSize( iTipW, iTipH );
  763. int cursorX, cursorY;
  764. input()->GetCursorPos(cursorX, cursorY);
  765. int px, py, wide, tall;
  766. ipanel()->GetAbsPos( m_pEmbeddedPanel->GetParent()->GetVPanel(), px, py );
  767. m_pEmbeddedPanel->GetParent()->GetSize(wide, tall);
  768. if ( !m_pEmbeddedPanel->IsPopup() )
  769. {
  770. // Move the cursor into our parent space
  771. cursorX -= px;
  772. cursorY -= py;
  773. }
  774. if (wide - iTipW > cursorX)
  775. {
  776. cursorY += 20;
  777. // menu hanging right
  778. if (tall - iTipH > cursorY)
  779. {
  780. // menu hanging down
  781. pTipPanel->SetPos(cursorX, cursorY);
  782. }
  783. else
  784. {
  785. // menu hanging up
  786. pTipPanel->SetPos(cursorX, cursorY - iTipH - 20);
  787. }
  788. }
  789. else
  790. {
  791. // menu hanging left
  792. if (tall - iTipH > cursorY)
  793. {
  794. // menu hanging down
  795. pTipPanel->SetPos( Max( 0, cursorX - iTipW ), cursorY);
  796. }
  797. else
  798. {
  799. // menu hanging up
  800. pTipPanel->SetPos( Max( 0, cursorX - iTipW ), cursorY - iTipH - 20 );
  801. }
  802. }
  803. }
  804. static vgui::DHANDLE<CTFAdvancedOptionsDialog> g_pTFAdvancedOptionsDialog;
  805. //-----------------------------------------------------------------------------
  806. // Purpose: Callback to open the game menus
  807. //-----------------------------------------------------------------------------
  808. void CL_OpenTFAdvancedOptionsDialog( const CCommand &args )
  809. {
  810. if ( g_pTFAdvancedOptionsDialog.Get() == NULL )
  811. {
  812. g_pTFAdvancedOptionsDialog = vgui::SETUP_PANEL( new CTFAdvancedOptionsDialog( NULL ) );
  813. }
  814. g_pTFAdvancedOptionsDialog->Deploy();
  815. }
  816. // the console commands
  817. static ConCommand opentf2options( "opentf2options", &CL_OpenTFAdvancedOptionsDialog, "Displays the TF2 Advanced Options dialog." );
  818. //-----------------------------------------------------------------------------
  819. // Purpose: A scroll bar that can have specified width
  820. //-----------------------------------------------------------------------------
  821. class CExScrollBar : public ScrollBar
  822. {
  823. DECLARE_CLASS_SIMPLE( CExScrollBar, ScrollBar );
  824. public:
  825. CExScrollBar( Panel *parent, const char *name, bool bVertical )
  826. : ScrollBar( parent, name, bVertical )
  827. {}
  828. virtual void ApplySchemeSettings( IScheme *pScheme ) OVERRIDE
  829. {
  830. // Deliberately skip ScrollBar
  831. Panel::ApplySchemeSettings( pScheme );
  832. }
  833. };
  834. DECLARE_BUILD_FACTORY( CExScrollingEditablePanel );
  835. //-----------------------------------------------------------------------------
  836. // Purpose:
  837. //-----------------------------------------------------------------------------
  838. CExScrollingEditablePanel::CExScrollingEditablePanel( Panel *pParent, const char *pszName )
  839. : EditablePanel( pParent, pszName )
  840. , m_nLastScrollValue( 0 )
  841. , m_bUseMouseWheelToScroll( true )
  842. {
  843. m_pScrollBar = new CExScrollBar( this, "ScrollBar", true );
  844. m_pScrollBar->AddActionSignalTarget( this );
  845. }
  846. //-----------------------------------------------------------------------------
  847. // Purpose:
  848. //-----------------------------------------------------------------------------
  849. CExScrollingEditablePanel::~CExScrollingEditablePanel()
  850. {}
  851. //-----------------------------------------------------------------------------
  852. // Purpose:
  853. //-----------------------------------------------------------------------------
  854. void CExScrollingEditablePanel::ApplySettings( KeyValues *inResourceData )
  855. {
  856. BaseClass::ApplySettings( inResourceData );
  857. KeyValues *pScrollbarKV = inResourceData->FindKey( "Scrollbar" );
  858. if ( pScrollbarKV )
  859. {
  860. m_pScrollBar->ApplySettings( pScrollbarKV );
  861. }
  862. m_bUseMouseWheelToScroll = inResourceData->GetBool( "allow_mouse_wheel_to_scroll", true );
  863. }
  864. //-----------------------------------------------------------------------------
  865. // Purpose:
  866. //-----------------------------------------------------------------------------
  867. void CExScrollingEditablePanel::OnSizeChanged( int newWide, int newTall )
  868. {
  869. BaseClass::OnSizeChanged( newWide, newTall );
  870. int nDelta = m_nLastScrollValue;
  871. // Go through all our children and move them BACK into position
  872. int nNumChildren = GetChildCount();
  873. for ( int i=0; i < nNumChildren; ++i )
  874. {
  875. Panel* pChild = GetChild( i );
  876. if ( pChild == m_pScrollBar )
  877. continue;
  878. EditablePanel* pEditableChild = dynamic_cast< EditablePanel* >( pChild );
  879. if ( pEditableChild && pEditableChild->ShouldSkipAutoResize() )
  880. continue;
  881. int x,y;
  882. pChild->GetPos( x, y );
  883. pChild->SetPos( x, y - nDelta );
  884. }
  885. }
  886. //-----------------------------------------------------------------------------
  887. // Purpose:
  888. //-----------------------------------------------------------------------------
  889. void CExScrollingEditablePanel::PerformLayout()
  890. {
  891. BaseClass::PerformLayout();
  892. int nFurthestY = 0;
  893. // Go through all our children and find the lowest point on the lowest child
  894. // that we'd need to scroll to
  895. int nNumChildren = GetChildCount();
  896. for ( int i=0; i < nNumChildren; ++i )
  897. {
  898. Panel* pChild = GetChild( i );
  899. if ( pChild == m_pScrollBar )
  900. continue;
  901. int x,y,wide,tall;
  902. pChild->GetBounds( x, y, wide, tall );
  903. // Offset by our scroll value
  904. y += m_nLastScrollValue;
  905. if ( m_bRestrictWidth )
  906. {
  907. int nMaxWide = Min( x + wide, GetWide() - m_pScrollBar->GetWide() );
  908. pChild->SetWide( nMaxWide - x );
  909. }
  910. nFurthestY = Max( y + tall, nFurthestY );
  911. }
  912. int nMaxRange = nFurthestY + m_iBottomBuffer;
  913. m_pScrollBar->SetRange( 0, nMaxRange );
  914. m_pScrollBar->SetRangeWindow( GetTall() );
  915. OnScrollBarSliderMoved();
  916. }
  917. //-----------------------------------------------------------------------------
  918. // Called when the scroll bar moves
  919. //-----------------------------------------------------------------------------
  920. void CExScrollingEditablePanel::OnScrollBarSliderMoved()
  921. {
  922. // Figure out how far they just scrolled
  923. int nScrollAmount = m_pScrollBar->GetValue();
  924. int nDelta = nScrollAmount - m_nLastScrollValue;
  925. if ( nDelta == 0 )
  926. return;
  927. ShiftChildren( nDelta );
  928. m_nLastScrollValue = nScrollAmount;
  929. }
  930. void CExScrollingEditablePanel::ShiftChildren( int nDistance )
  931. {
  932. // Go through all our children and move them
  933. int nNumChildren = GetChildCount();
  934. for ( int i=0; i < nNumChildren; ++i )
  935. {
  936. Panel* pChild = GetChild( i );
  937. if ( pChild == m_pScrollBar )
  938. continue;
  939. int x,y;
  940. pChild->GetPos( x, y );
  941. pChild->SetPos( x, y - nDistance );
  942. }
  943. }
  944. //-----------------------------------------------------------------------------
  945. // respond to mouse wheel events
  946. //-----------------------------------------------------------------------------
  947. void CExScrollingEditablePanel::OnMouseWheeled( int delta )
  948. {
  949. if ( !m_bUseMouseWheelToScroll )
  950. {
  951. BaseClass::OnMouseWheeled( delta );
  952. return;
  953. }
  954. int val = m_pScrollBar->GetValue();
  955. val -= ( delta * m_iScrollStep );
  956. m_pScrollBar->SetValue( val );
  957. }
  958. DECLARE_BUILD_FACTORY( CScrollableList );
  959. //-----------------------------------------------------------------------------
  960. // Clearnup
  961. //-----------------------------------------------------------------------------
  962. CScrollableList::~CScrollableList()
  963. {
  964. ClearAutoLayoutPanels();
  965. }
  966. void CScrollableList::PerformLayout()
  967. {
  968. int nYpos = -m_nLastScrollValue;
  969. for( int i=0; i<m_vecAutoLayoutPanels.Count(); ++i )
  970. {
  971. LayoutInfo_t layout = m_vecAutoLayoutPanels[ i ];
  972. nYpos += layout.m_nGap;
  973. layout.m_pPanel->SetPos( layout.m_pPanel->GetXPos(), nYpos );
  974. nYpos += layout.m_pPanel->GetTall();
  975. }
  976. BaseClass::PerformLayout();
  977. }
  978. //-----------------------------------------------------------------------------
  979. // Add a panel to the bottom
  980. //-----------------------------------------------------------------------------
  981. void CScrollableList::AddPanel( Panel* pPanel, int nGap )
  982. {
  983. // We're the captain now
  984. pPanel->SetParent( this );
  985. pPanel->SetAutoDelete( false );
  986. auto idx = m_vecAutoLayoutPanels.AddToTail();
  987. LayoutInfo_t& layout = m_vecAutoLayoutPanels[ idx ];
  988. layout.m_pPanel = pPanel;
  989. layout.m_nGap = nGap;
  990. // Need to do a perform layout so we get sized correctly
  991. InvalidateLayout();
  992. }
  993. //-----------------------------------------------------------------------------
  994. // Delete any panels we own
  995. //-----------------------------------------------------------------------------
  996. void CScrollableList::ClearAutoLayoutPanels()
  997. {
  998. FOR_EACH_VEC( m_vecAutoLayoutPanels, i )
  999. {
  1000. m_vecAutoLayoutPanels[ i ].m_pPanel->MarkForDeletion();
  1001. }
  1002. m_vecAutoLayoutPanels.Purge();
  1003. }
  1004. //-----------------------------------------------------------------------------
  1005. //
  1006. //-----------------------------------------------------------------------------
  1007. CExpandablePanel::CExpandablePanel( Panel* pParent, const char* pszName )
  1008. : vgui::EditablePanel( pParent, pszName )
  1009. , m_bExpanded( false )
  1010. , m_flAnimEndTime( 0.f )
  1011. , m_flResizeTime( 0.f )
  1012. {}
  1013. //-----------------------------------------------------------------------------
  1014. // Set spcific collapsed state
  1015. //-----------------------------------------------------------------------------
  1016. void CExpandablePanel::SetCollapsed( bool bCollapsed )
  1017. {
  1018. if ( bCollapsed == m_bExpanded )
  1019. {
  1020. ToggleCollapse();
  1021. }
  1022. }
  1023. //-----------------------------------------------------------------------------
  1024. // Toggle collapsed state
  1025. //-----------------------------------------------------------------------------
  1026. void CExpandablePanel::ToggleCollapse()
  1027. {
  1028. m_bExpanded = !m_bExpanded;
  1029. // Allow for quick bounce-back if they click while we're already animating
  1030. float flEndTime = RemapValClamped( GetPercentAnimated(), 0.f, 1.f, 0.f, m_flResizeTime );
  1031. m_flAnimEndTime = Plat_FloatTime() + flEndTime;
  1032. OnToggleCollapse( m_bExpanded );
  1033. }
  1034. //-----------------------------------------------------------------------------
  1035. // Toggle collapsed state
  1036. //-----------------------------------------------------------------------------
  1037. void CExpandablePanel::OnCommand( const char *command )
  1038. {
  1039. if ( FStrEq( "toggle_collapse", command ) )
  1040. {
  1041. ToggleCollapse();
  1042. return;
  1043. }
  1044. BaseClass::OnCommand( command );
  1045. }
  1046. //-----------------------------------------------------------------------------
  1047. // Do collapsing interpolation
  1048. //-----------------------------------------------------------------------------
  1049. void CExpandablePanel::OnThink()
  1050. {
  1051. BaseClass::OnThink();
  1052. float flTimeProgress = Gain( GetPercentAnimated(), 0.8f );
  1053. const int& nStartHeight = m_bExpanded ? m_nCollapsedHeight : m_nExpandedHeight;
  1054. const int& nEndHeight = m_bExpanded ? m_nExpandedHeight : m_nCollapsedHeight;
  1055. int nCurrentHeight = RemapValClamped( flTimeProgress, 0.f, 1.f, nStartHeight, nEndHeight );
  1056. if ( nCurrentHeight != GetTall() )
  1057. {
  1058. SetTall( nCurrentHeight );
  1059. Panel* pParent = GetParent();
  1060. if ( pParent )
  1061. {
  1062. pParent->InvalidateLayout();
  1063. }
  1064. }
  1065. }
  1066. //-----------------------------------------------------------------------------
  1067. // Where we're at in our interpolation
  1068. //-----------------------------------------------------------------------------
  1069. float CExpandablePanel::GetPercentAnimated() const
  1070. {
  1071. return RemapValClamped( Plat_FloatTime() - ( m_flAnimEndTime - m_flResizeTime ), 0.f, m_flResizeTime, 0.f, 1.f );
  1072. }