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.

324 lines
8.6 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. //=======================================================================================//
  4. #include "cbase.h"
  5. #include "game_controls/navigationpanel.h"
  6. #include "econ/econ_controls.h"
  7. #include "vgui_controls/Frame.h"
  8. #include "vgui/IInput.h"
  9. // memdbgon must be the last include file in a .cpp file!!!
  10. #include "tier0/memdbgon.h"
  11. //-----------------------------------------------------------------------------
  12. using namespace vgui;
  13. //-----------------------------------------------------------------------------
  14. DECLARE_BUILD_FACTORY( CNavigationPanel );
  15. //-----------------------------------------------------------------------------
  16. class CNavButton : public CExImageButton
  17. {
  18. DECLARE_CLASS_SIMPLE( CNavButton, CExImageButton );
  19. public:
  20. CNavButton( Panel *parent, const char *name, const char *text = "", Panel *pActionSignalTarget = NULL, const char *cmd = NULL )
  21. : CExImageButton( parent, name, text, pActionSignalTarget, cmd ), m_iUserData( -1 ) {}
  22. CNavButton( Panel *parent, const char *name, const wchar_t *wszText = L"", Panel *pActionSignalTarget = NULL, const char *cmd = NULL )
  23. : CExImageButton( parent, name, wszText, pActionSignalTarget, cmd ) , m_iUserData( -1 ) {}
  24. virtual void ApplySettings( KeyValues *pInResourceData )
  25. {
  26. BaseClass::ApplySettings( pInResourceData );
  27. if ( m_iUserData < 0 )
  28. {
  29. m_iUserData = pInResourceData->GetInt( "userdata", -1 ); AssertMsg( m_iUserData != -1, "Any messages sent for this button will have invalid user data!" );
  30. }
  31. }
  32. int m_iUserData;
  33. };
  34. //-----------------------------------------------------------------------------
  35. CNavigationPanel::CNavigationPanel( Panel *pParent, const char *pName, bool bAddParentAsActionSignalTarget/*=true*/ )
  36. : BaseClass( pParent, pName ),
  37. m_bAutoLayout( false ),
  38. m_bAutoScale( true ),
  39. m_bDisplayVertical( false ),
  40. m_iSelectedButton( 0 ),
  41. // m_nAlignment( ALIGN_CENTER ),
  42. m_pKVButtonSettings( NULL )
  43. {
  44. if ( bAddParentAsActionSignalTarget && pParent )
  45. {
  46. AddActionSignalTarget( pParent );
  47. }
  48. }
  49. CNavigationPanel::~CNavigationPanel()
  50. {
  51. }
  52. void CNavigationPanel::AddButton( int iUserData, const char *pTextToken )
  53. {
  54. const int i = m_vecButtons.Count();
  55. CNavButton *pNewButton = new CNavButton( this, CFmtStr( "button_%i", i ).Access(), pTextToken );
  56. pNewButton->m_iUserData = iUserData;
  57. pNewButton->InvalidateLayout( true, false );
  58. pNewButton->SetCommand( CFmtStr( "select_%i", i ).Access() );
  59. m_vecButtons.AddToTail( pNewButton );
  60. }
  61. CExImageButton *CNavigationPanel::GetButton( int index )
  62. {
  63. return m_vecButtons[ index ];
  64. }
  65. void CNavigationPanel::ApplySettings( KeyValues *pInResourceData )
  66. {
  67. BaseClass::ApplySettings( pInResourceData );
  68. /*
  69. const char *pAlignment = pInResourceData->GetString( "align", NULL );
  70. if ( pAlignment )
  71. {
  72. if ( !V_strnicmp( pAlignment, "west", 4 ) )
  73. {
  74. m_nAlignment = ALIGN_WEST;
  75. }
  76. else if ( !V_strnicmp( pAlignment, "center", 6 ) )
  77. {
  78. m_nAlignment = ALIGN_CENTER;
  79. }
  80. else if ( !V_strnicmp( pAlignment, "east", 4 ) )
  81. {
  82. AssertMsg( 0, "This type of alignment is not supported." );
  83. }
  84. }
  85. */
  86. m_bAutoLayout = pInResourceData->GetBool( "auto_layout", false );
  87. m_bAutoScale = pInResourceData->GetBool( "auto_scale", true );
  88. m_bDisplayVertical = pInResourceData->GetBool( "display_vertically", false );
  89. KeyValues *pKVButtonSettings = pInResourceData->FindKey( "ButtonSettings" ); AssertMsg( pKVButtonSettings, "This is required" );
  90. if ( !pKVButtonSettings )
  91. {
  92. AssertMsg( 0, "No button settings specified. CNavigationPanel is useless without this data." );
  93. return;
  94. }
  95. // Cache this off for later
  96. if ( m_pKVButtonSettings )
  97. {
  98. m_pKVButtonSettings->deleteThis();
  99. m_pKVButtonSettings = NULL;
  100. }
  101. m_pKVButtonSettings = pKVButtonSettings->MakeCopy();
  102. // Get individual button data and apply now
  103. KeyValues *pKVButtons = pInResourceData->FindKey( "Buttons" );
  104. if ( !pKVButtons )
  105. return;
  106. // Go through each image description and create a button
  107. if ( m_vecButtons.Count() )
  108. return;
  109. int i = 0;
  110. FOR_EACH_SUBKEY( pKVButtons, pKVCurButton )
  111. {
  112. CNavButton *pNewButton = new CNavButton( this, pKVCurButton->GetString( "FieldName", pKVCurButton->GetName() ), L"" );
  113. pNewButton->ApplySettings( pKVCurButton );
  114. pNewButton->InvalidateLayout( true, false );
  115. pNewButton->SetCommand( CFmtStr( "select_%i", i ).Access() );
  116. m_vecButtons.AddToTail( pNewButton );
  117. ++i;
  118. }
  119. if ( m_vecButtons.IsValidIndex( m_iSelectedButtonDefault ) )
  120. {
  121. UpdateButtonSelectionStates( m_iSelectedButtonDefault );
  122. m_vecButtons[ m_iSelectedButtonDefault ]->InvalidateLayout( true );
  123. const int iUserData = m_vecButtons[ m_iSelectedButtonDefault ]->m_iUserData;
  124. PostActionSignal( new KeyValues( "NavButtonSelected", "userdata", iUserData ) );
  125. }
  126. }
  127. void CNavigationPanel::ApplySchemeSettings( IScheme *pScheme )
  128. {
  129. BaseClass::ApplySchemeSettings( pScheme );
  130. }
  131. void CNavigationPanel::PerformLayout()
  132. {
  133. if ( !m_vecButtons.Count() )
  134. return;
  135. if ( !m_pKVButtonSettings )
  136. return;
  137. BaseClass::PerformLayout();
  138. // Get from settings
  139. int nSettingWidth = m_pKVButtonSettings->GetInt( "wide" );
  140. int nSettingHeight = m_pKVButtonSettings->GetInt( "tall" );
  141. // Button dimensions for setting positions
  142. int nButtonWidth = nSettingWidth;
  143. int nButtonHeight = nSettingHeight;
  144. if ( m_bAutoScale )
  145. {
  146. // Get image size
  147. int nImageW, nImageH;
  148. m_vecButtons[0]->GetImage()->GetSize( nImageW, nImageH );
  149. int nWidth, nHeight;
  150. if ( m_bDisplayVertical )
  151. {
  152. nWidth = GetWide();
  153. nHeight = nSettingHeight * nWidth / ( nSettingWidth > 0 ? nSettingWidth : 1 );
  154. }
  155. else
  156. {
  157. nHeight = GetTall();
  158. nWidth = nSettingWidth * nHeight / ( nSettingHeight > 0 ? nSettingHeight : 1 );
  159. }
  160. // Update button dimensions to scaled versions
  161. nButtonWidth = nWidth;
  162. nButtonHeight = nHeight;
  163. }
  164. FOR_EACH_VEC( m_vecButtons, i )
  165. {
  166. if ( m_vecButtons[i] && m_pKVButtonSettings )
  167. {
  168. // Apply generic settings
  169. m_vecButtons[i]->ApplySettings( m_pKVButtonSettings );
  170. }
  171. if ( m_bAutoLayout )
  172. {
  173. // Display buttons vertically or horizontally?
  174. if ( m_bDisplayVertical )
  175. {
  176. m_vecButtons[i]->SetPos( 0, i * ( nButtonHeight + m_nVerticalBuffer ) );
  177. }
  178. else
  179. {
  180. const int nStartX = 0;//0.5f * ( GetWide() - NumButtons() * ( nButtonWidth + m_nHorizontalBuffer ) );
  181. m_vecButtons[i]->SetPos( nStartX + i * ( nButtonWidth + m_nHorizontalBuffer ), 0 );
  182. }
  183. }
  184. if ( m_bAutoScale )
  185. {
  186. m_vecButtons[i]->SetSize( nButtonWidth, nButtonHeight );
  187. m_vecButtons[i]->GetImage()->SetSize( nButtonWidth, nButtonHeight );
  188. }
  189. m_vecButtons[i]->SetVisible( true );
  190. }
  191. }
  192. void CNavigationPanel::OnCommand( const char *pCommand )
  193. {
  194. if ( !V_strnicmp( pCommand, "select_", 7 ) )
  195. {
  196. const int iButton = atoi( pCommand + 7 ); AssertMsg( m_vecButtons.IsValidIndex( iButton ), "Button index out of range!" );
  197. if ( !m_vecButtons.IsValidIndex( iButton ) )
  198. return;
  199. UpdateButtonSelectionStates( iButton );
  200. const int iUserData = m_vecButtons[ iButton ]->m_iUserData;
  201. PostActionSignal( new KeyValues( "NavButtonSelected", "userdata", iUserData ) );
  202. }
  203. else
  204. {
  205. BaseClass::OnCommand( pCommand );
  206. }
  207. }
  208. void CNavigationPanel::OnThink()
  209. {
  210. BaseClass::OnThink();
  211. // Make sure we only ever have one button in the selection state, since it's
  212. // possible to do this if you select a button, then click and drag on another
  213. // button, and release the mouse elsewhere.
  214. if ( !vgui::input()->IsMouseDown( MOUSE_LEFT ) )
  215. {
  216. UpdateButtonSelectionStates( m_iSelectedButton );
  217. }
  218. }
  219. void CNavigationPanel::UpdateButtonSelectionStates( int iButton )
  220. {
  221. if ( m_iSelectedButton != iButton )
  222. {
  223. m_iSelectedButton = iButton;
  224. }
  225. // Set the correct button as selected, all other buttons as not selected
  226. for ( int i = 0; i < NumButtons(); ++i )
  227. {
  228. CNavButton *pCurButton = m_vecButtons[ i ];
  229. if ( !pCurButton )
  230. continue;
  231. bool bShouldSelect = iButton == i;
  232. pCurButton->SetSelected( bShouldSelect );
  233. pCurButton->InvalidateLayout();
  234. }
  235. }
  236. //-----------------------------------------------------------------------------
  237. #ifdef _DEBUG
  238. class CNavPanelTest : public Frame
  239. {
  240. DECLARE_CLASS_SIMPLE( CNavPanelTest, Frame );
  241. public:
  242. CNavPanelTest( vgui::Panel *pParent )
  243. : Frame( pParent, "NavPanelTest" )
  244. {
  245. SetProportional( true );
  246. LoadControlSettings( "Resource/UI/NavigationPanelTest.res" );
  247. }
  248. };
  249. CON_COMMAND( open_navpanel_test, "" )
  250. {
  251. CNavPanelTest *pPanel = SETUP_PANEL( new CNavPanelTest( NULL ) );
  252. pPanel->SetVisible( true );
  253. pPanel->InvalidateLayout( false, true );
  254. engine->ClientCmd_Unrestricted( "gameui_activate" );
  255. const int nWidth = XRES( 300 );
  256. const int nHeight = YRES( 300 );
  257. pPanel->SetBounds(
  258. ( ScreenWidth() - nWidth ) / 2,
  259. ( ScreenHeight() - nHeight ) / 2,
  260. nWidth,
  261. nHeight
  262. );
  263. pPanel->Activate();
  264. }
  265. #endif // _DEBUG