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.
325 lines
8.6 KiB
325 lines
8.6 KiB
![]()
4 years ago
|
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||
|
//
|
||
|
//=======================================================================================//
|
||
|
|
||
|
#include "cbase.h"
|
||
|
#include "game_controls/navigationpanel.h"
|
||
|
#include "econ/econ_controls.h"
|
||
|
#include "vgui_controls/Frame.h"
|
||
|
#include "vgui/IInput.h"
|
||
|
|
||
|
// memdbgon must be the last include file in a .cpp file!!!
|
||
|
#include "tier0/memdbgon.h"
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
using namespace vgui;
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
DECLARE_BUILD_FACTORY( CNavigationPanel );
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
class CNavButton : public CExImageButton
|
||
|
{
|
||
|
DECLARE_CLASS_SIMPLE( CNavButton, CExImageButton );
|
||
|
public:
|
||
|
CNavButton( Panel *parent, const char *name, const char *text = "", Panel *pActionSignalTarget = NULL, const char *cmd = NULL )
|
||
|
: CExImageButton( parent, name, text, pActionSignalTarget, cmd ), m_iUserData( -1 ) {}
|
||
|
|
||
|
CNavButton( Panel *parent, const char *name, const wchar_t *wszText = L"", Panel *pActionSignalTarget = NULL, const char *cmd = NULL )
|
||
|
: CExImageButton( parent, name, wszText, pActionSignalTarget, cmd ) , m_iUserData( -1 ) {}
|
||
|
|
||
|
virtual void ApplySettings( KeyValues *pInResourceData )
|
||
|
{
|
||
|
BaseClass::ApplySettings( pInResourceData );
|
||
|
|
||
|
if ( m_iUserData < 0 )
|
||
|
{
|
||
|
m_iUserData = pInResourceData->GetInt( "userdata", -1 ); AssertMsg( m_iUserData != -1, "Any messages sent for this button will have invalid user data!" );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int m_iUserData;
|
||
|
};
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
CNavigationPanel::CNavigationPanel( Panel *pParent, const char *pName, bool bAddParentAsActionSignalTarget/*=true*/ )
|
||
|
: BaseClass( pParent, pName ),
|
||
|
m_bAutoLayout( false ),
|
||
|
m_bAutoScale( true ),
|
||
|
m_bDisplayVertical( false ),
|
||
|
m_iSelectedButton( 0 ),
|
||
|
// m_nAlignment( ALIGN_CENTER ),
|
||
|
m_pKVButtonSettings( NULL )
|
||
|
{
|
||
|
if ( bAddParentAsActionSignalTarget && pParent )
|
||
|
{
|
||
|
AddActionSignalTarget( pParent );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CNavigationPanel::~CNavigationPanel()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
void CNavigationPanel::AddButton( int iUserData, const char *pTextToken )
|
||
|
{
|
||
|
const int i = m_vecButtons.Count();
|
||
|
CNavButton *pNewButton = new CNavButton( this, CFmtStr( "button_%i", i ).Access(), pTextToken );
|
||
|
pNewButton->m_iUserData = iUserData;
|
||
|
pNewButton->InvalidateLayout( true, false );
|
||
|
pNewButton->SetCommand( CFmtStr( "select_%i", i ).Access() );
|
||
|
m_vecButtons.AddToTail( pNewButton );
|
||
|
}
|
||
|
|
||
|
CExImageButton *CNavigationPanel::GetButton( int index )
|
||
|
{
|
||
|
return m_vecButtons[ index ];
|
||
|
}
|
||
|
|
||
|
void CNavigationPanel::ApplySettings( KeyValues *pInResourceData )
|
||
|
{
|
||
|
BaseClass::ApplySettings( pInResourceData );
|
||
|
|
||
|
/*
|
||
|
const char *pAlignment = pInResourceData->GetString( "align", NULL );
|
||
|
if ( pAlignment )
|
||
|
{
|
||
|
if ( !V_strnicmp( pAlignment, "west", 4 ) )
|
||
|
{
|
||
|
m_nAlignment = ALIGN_WEST;
|
||
|
}
|
||
|
else if ( !V_strnicmp( pAlignment, "center", 6 ) )
|
||
|
{
|
||
|
m_nAlignment = ALIGN_CENTER;
|
||
|
}
|
||
|
else if ( !V_strnicmp( pAlignment, "east", 4 ) )
|
||
|
{
|
||
|
AssertMsg( 0, "This type of alignment is not supported." );
|
||
|
}
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
m_bAutoLayout = pInResourceData->GetBool( "auto_layout", false );
|
||
|
m_bAutoScale = pInResourceData->GetBool( "auto_scale", true );
|
||
|
m_bDisplayVertical = pInResourceData->GetBool( "display_vertically", false );
|
||
|
|
||
|
KeyValues *pKVButtonSettings = pInResourceData->FindKey( "ButtonSettings" ); AssertMsg( pKVButtonSettings, "This is required" );
|
||
|
if ( !pKVButtonSettings )
|
||
|
{
|
||
|
AssertMsg( 0, "No button settings specified. CNavigationPanel is useless without this data." );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Cache this off for later
|
||
|
if ( m_pKVButtonSettings )
|
||
|
{
|
||
|
m_pKVButtonSettings->deleteThis();
|
||
|
m_pKVButtonSettings = NULL;
|
||
|
}
|
||
|
m_pKVButtonSettings = pKVButtonSettings->MakeCopy();
|
||
|
|
||
|
// Get individual button data and apply now
|
||
|
KeyValues *pKVButtons = pInResourceData->FindKey( "Buttons" );
|
||
|
if ( !pKVButtons )
|
||
|
return;
|
||
|
|
||
|
// Go through each image description and create a button
|
||
|
if ( m_vecButtons.Count() )
|
||
|
return;
|
||
|
|
||
|
int i = 0;
|
||
|
FOR_EACH_SUBKEY( pKVButtons, pKVCurButton )
|
||
|
{
|
||
|
CNavButton *pNewButton = new CNavButton( this, pKVCurButton->GetString( "FieldName", pKVCurButton->GetName() ), L"" );
|
||
|
pNewButton->ApplySettings( pKVCurButton );
|
||
|
pNewButton->InvalidateLayout( true, false );
|
||
|
pNewButton->SetCommand( CFmtStr( "select_%i", i ).Access() );
|
||
|
m_vecButtons.AddToTail( pNewButton );
|
||
|
++i;
|
||
|
}
|
||
|
|
||
|
if ( m_vecButtons.IsValidIndex( m_iSelectedButtonDefault ) )
|
||
|
{
|
||
|
UpdateButtonSelectionStates( m_iSelectedButtonDefault );
|
||
|
m_vecButtons[ m_iSelectedButtonDefault ]->InvalidateLayout( true );
|
||
|
|
||
|
const int iUserData = m_vecButtons[ m_iSelectedButtonDefault ]->m_iUserData;
|
||
|
PostActionSignal( new KeyValues( "NavButtonSelected", "userdata", iUserData ) );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CNavigationPanel::ApplySchemeSettings( IScheme *pScheme )
|
||
|
{
|
||
|
BaseClass::ApplySchemeSettings( pScheme );
|
||
|
}
|
||
|
|
||
|
void CNavigationPanel::PerformLayout()
|
||
|
{
|
||
|
if ( !m_vecButtons.Count() )
|
||
|
return;
|
||
|
|
||
|
if ( !m_pKVButtonSettings )
|
||
|
return;
|
||
|
|
||
|
BaseClass::PerformLayout();
|
||
|
|
||
|
// Get from settings
|
||
|
int nSettingWidth = m_pKVButtonSettings->GetInt( "wide" );
|
||
|
int nSettingHeight = m_pKVButtonSettings->GetInt( "tall" );
|
||
|
|
||
|
// Button dimensions for setting positions
|
||
|
int nButtonWidth = nSettingWidth;
|
||
|
int nButtonHeight = nSettingHeight;
|
||
|
|
||
|
if ( m_bAutoScale )
|
||
|
{
|
||
|
// Get image size
|
||
|
int nImageW, nImageH;
|
||
|
m_vecButtons[0]->GetImage()->GetSize( nImageW, nImageH );
|
||
|
|
||
|
int nWidth, nHeight;
|
||
|
if ( m_bDisplayVertical )
|
||
|
{
|
||
|
nWidth = GetWide();
|
||
|
nHeight = nSettingHeight * nWidth / ( nSettingWidth > 0 ? nSettingWidth : 1 );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
nHeight = GetTall();
|
||
|
nWidth = nSettingWidth * nHeight / ( nSettingHeight > 0 ? nSettingHeight : 1 );
|
||
|
}
|
||
|
|
||
|
// Update button dimensions to scaled versions
|
||
|
nButtonWidth = nWidth;
|
||
|
nButtonHeight = nHeight;
|
||
|
}
|
||
|
|
||
|
FOR_EACH_VEC( m_vecButtons, i )
|
||
|
{
|
||
|
if ( m_vecButtons[i] && m_pKVButtonSettings )
|
||
|
{
|
||
|
// Apply generic settings
|
||
|
m_vecButtons[i]->ApplySettings( m_pKVButtonSettings );
|
||
|
}
|
||
|
|
||
|
if ( m_bAutoLayout )
|
||
|
{
|
||
|
// Display buttons vertically or horizontally?
|
||
|
if ( m_bDisplayVertical )
|
||
|
{
|
||
|
m_vecButtons[i]->SetPos( 0, i * ( nButtonHeight + m_nVerticalBuffer ) );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
const int nStartX = 0;//0.5f * ( GetWide() - NumButtons() * ( nButtonWidth + m_nHorizontalBuffer ) );
|
||
|
m_vecButtons[i]->SetPos( nStartX + i * ( nButtonWidth + m_nHorizontalBuffer ), 0 );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( m_bAutoScale )
|
||
|
{
|
||
|
m_vecButtons[i]->SetSize( nButtonWidth, nButtonHeight );
|
||
|
m_vecButtons[i]->GetImage()->SetSize( nButtonWidth, nButtonHeight );
|
||
|
}
|
||
|
|
||
|
m_vecButtons[i]->SetVisible( true );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CNavigationPanel::OnCommand( const char *pCommand )
|
||
|
{
|
||
|
if ( !V_strnicmp( pCommand, "select_", 7 ) )
|
||
|
{
|
||
|
const int iButton = atoi( pCommand + 7 ); AssertMsg( m_vecButtons.IsValidIndex( iButton ), "Button index out of range!" );
|
||
|
if ( !m_vecButtons.IsValidIndex( iButton ) )
|
||
|
return;
|
||
|
|
||
|
UpdateButtonSelectionStates( iButton );
|
||
|
|
||
|
const int iUserData = m_vecButtons[ iButton ]->m_iUserData;
|
||
|
PostActionSignal( new KeyValues( "NavButtonSelected", "userdata", iUserData ) );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
BaseClass::OnCommand( pCommand );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CNavigationPanel::OnThink()
|
||
|
{
|
||
|
BaseClass::OnThink();
|
||
|
|
||
|
// Make sure we only ever have one button in the selection state, since it's
|
||
|
// possible to do this if you select a button, then click and drag on another
|
||
|
// button, and release the mouse elsewhere.
|
||
|
if ( !vgui::input()->IsMouseDown( MOUSE_LEFT ) )
|
||
|
{
|
||
|
UpdateButtonSelectionStates( m_iSelectedButton );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void CNavigationPanel::UpdateButtonSelectionStates( int iButton )
|
||
|
{
|
||
|
if ( m_iSelectedButton != iButton )
|
||
|
{
|
||
|
m_iSelectedButton = iButton;
|
||
|
}
|
||
|
|
||
|
// Set the correct button as selected, all other buttons as not selected
|
||
|
for ( int i = 0; i < NumButtons(); ++i )
|
||
|
{
|
||
|
CNavButton *pCurButton = m_vecButtons[ i ];
|
||
|
if ( !pCurButton )
|
||
|
continue;
|
||
|
|
||
|
bool bShouldSelect = iButton == i;
|
||
|
pCurButton->SetSelected( bShouldSelect );
|
||
|
pCurButton->InvalidateLayout();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
|
||
|
class CNavPanelTest : public Frame
|
||
|
{
|
||
|
DECLARE_CLASS_SIMPLE( CNavPanelTest, Frame );
|
||
|
|
||
|
public:
|
||
|
CNavPanelTest( vgui::Panel *pParent )
|
||
|
: Frame( pParent, "NavPanelTest" )
|
||
|
{
|
||
|
SetProportional( true );
|
||
|
LoadControlSettings( "Resource/UI/NavigationPanelTest.res" );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
CON_COMMAND( open_navpanel_test, "" )
|
||
|
{
|
||
|
CNavPanelTest *pPanel = SETUP_PANEL( new CNavPanelTest( NULL ) );
|
||
|
pPanel->SetVisible( true );
|
||
|
pPanel->InvalidateLayout( false, true );
|
||
|
|
||
|
engine->ClientCmd_Unrestricted( "gameui_activate" );
|
||
|
|
||
|
const int nWidth = XRES( 300 );
|
||
|
const int nHeight = YRES( 300 );
|
||
|
|
||
|
pPanel->SetBounds(
|
||
|
( ScreenWidth() - nWidth ) / 2,
|
||
|
( ScreenHeight() - nHeight ) / 2,
|
||
|
nWidth,
|
||
|
nHeight
|
||
|
);
|
||
|
|
||
|
pPanel->Activate();
|
||
|
}
|
||
|
|
||
|
#endif // _DEBUG
|