source-engine/game/client/game_controls/navigationpanel.cpp

325 lines
8.6 KiB
C++
Raw Normal View History

2020-04-22 16:56:21 +00:00
//========= 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