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.
321 lines
8.5 KiB
321 lines
8.5 KiB
1 year ago
|
//============ Copyright (c) Valve Corporation, All rights reserved. ============
|
||
|
//
|
||
|
// Base class for panels used to edit nodes in layout system definitions.
|
||
|
//
|
||
|
//===============================================================================
|
||
|
|
||
|
#include "vgui_controls/Panel.h"
|
||
|
#include "vgui_controls/Label.h"
|
||
|
#include "vgui_controls/Button.h"
|
||
|
#include "vgui_controls/TextEntry.h"
|
||
|
#include "KeyValues.h"
|
||
|
#include "layout_system_editor/layout_system_kv_editor.h"
|
||
|
#include "layout_system_editor/rule_instance_node_panel.h"
|
||
|
#include "layout_system_editor/state_node_panel.h"
|
||
|
#include "node_panel.h"
|
||
|
|
||
|
using namespace vgui;
|
||
|
|
||
|
CNodePanel::CNodePanel( Panel *pParent, const char *pName ) :
|
||
|
BaseClass( pParent, pName ),
|
||
|
m_pNodeKV( NULL ),
|
||
|
m_pEditor( NULL ),
|
||
|
m_bShowNameEditBox( false ),
|
||
|
m_bShowDeleteButton( false )
|
||
|
{
|
||
|
m_pLabel = new Label( this, "Label", "" );
|
||
|
m_pLabel->SetMouseInputEnabled( false );
|
||
|
m_pNameEditBox = new TextEntry( this, "TextEntry" );
|
||
|
m_NodeLabel[0] = '\0';
|
||
|
m_NodeName[0] = '\0';
|
||
|
|
||
|
m_pRootSizer = new CBoxSizer( ESLD_VERTICAL );
|
||
|
|
||
|
m_pLabelSizer = new CBoxSizer( ESLD_HORIZONTAL );
|
||
|
m_pLabelSizer->AddPanel( m_pLabel, SizerAddArgs_t().Padding( 2 ) );
|
||
|
m_pLabelSizer->AddPanel( m_pNameEditBox, SizerAddArgs_t().Padding( 2 ).MinSize( 200, 20 ) );
|
||
|
m_pRootSizer->AddSizer( m_pLabelSizer, SizerAddArgs_t().Padding( 5 ) );
|
||
|
|
||
|
m_pHeadingSizer = new CBoxSizer( ESLD_HORIZONTAL );
|
||
|
m_pLabelSizer->AddSizer( m_pHeadingSizer, SizerAddArgs_t().Padding( 0 ).Expand( 1.0f ) );
|
||
|
|
||
|
m_pDeleteSelfButton = new Button( this, "DeleteSelf", "X", this, "DeleteSelf" );
|
||
|
m_pLabelSizer->AddPanel( m_pDeleteSelfButton, SizerAddArgs_t().Padding( 2 ) );
|
||
|
|
||
|
m_pChildSizer = new CBoxSizer( ESLD_VERTICAL );
|
||
|
m_pChildIndentSizer = new CBoxSizer( ESLD_HORIZONTAL );
|
||
|
m_pChildIndentSizer->AddSpacer( SizerAddArgs_t().MinSize( 0, 0 ).Padding( 0 ) );
|
||
|
m_pChildIndentSizer->AddSizer( m_pChildSizer, SizerAddArgs_t().Padding( 0 ).Expand( 1.0f ) );
|
||
|
m_pRootSizer->AddSizer( m_pChildIndentSizer, SizerAddArgs_t().Padding( 0 ).Expand( 1.0f ) );
|
||
|
|
||
|
SetSizer( m_pRootSizer );
|
||
|
|
||
|
// We want a transparent background for the label.
|
||
|
m_pLabel->SetPaintBackgroundEnabled( false );
|
||
|
}
|
||
|
|
||
|
void CNodePanel::ApplySchemeSettings( vgui::IScheme *pScheme )
|
||
|
{
|
||
|
BaseClass::ApplySchemeSettings( pScheme );
|
||
|
SetBorder( pScheme->GetBorder( "RaisedBorder" ) );
|
||
|
}
|
||
|
|
||
|
void CNodePanel::OnCommand( const char *pCommand )
|
||
|
{
|
||
|
if ( Q_stricmp( pCommand, "DeleteSelf" ) == 0 )
|
||
|
{
|
||
|
DeleteSelf();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
BaseClass::OnCommand( pCommand );
|
||
|
}
|
||
|
|
||
|
void CNodePanel::OnAddRule( KeyValues *pKV )
|
||
|
{
|
||
|
int nIndex = pKV->GetInt( "index", -1 );
|
||
|
Assert( nIndex != -1 );
|
||
|
InsertChildData( nIndex, new KeyValues( "rule_instance", NULL, "<null>" ) );
|
||
|
}
|
||
|
|
||
|
void CNodePanel::OnAddState( KeyValues *pKV )
|
||
|
{
|
||
|
int nIndex = pKV->GetInt( "index", -1 );
|
||
|
Assert( nIndex != -1 );
|
||
|
InsertChildData( nIndex, new KeyValues( "state", "name", "MyNewState" ) );
|
||
|
}
|
||
|
|
||
|
void CNodePanel::OnTextChanged( vgui::Panel *pPanel )
|
||
|
{
|
||
|
Assert( pPanel == m_pNameEditBox );
|
||
|
const int nMaxTextLength = 2048;
|
||
|
char buf[nMaxTextLength];
|
||
|
m_pNameEditBox->GetText( buf, nMaxTextLength );
|
||
|
buf[nMaxTextLength - 1] = '\0';
|
||
|
SetNodeName( buf );
|
||
|
}
|
||
|
|
||
|
void CNodePanel::SetData( KeyValues *pNodeKV )
|
||
|
{
|
||
|
if ( m_pNodeKV != NULL && m_pNodeKV != pNodeKV )
|
||
|
{
|
||
|
CNodePanel *pParentNodePanel = dynamic_cast< CNodePanel * >( GetParent() );
|
||
|
if ( pParentNodePanel != NULL )
|
||
|
{
|
||
|
Assert( pParentNodePanel->m_pNodeKV->ContainsSubKey( m_pNodeKV ) );
|
||
|
|
||
|
if ( pNodeKV != NULL )
|
||
|
{
|
||
|
// Must replace parent's sub key with ours
|
||
|
pParentNodePanel->m_pNodeKV->SwapSubKey( m_pNodeKV, pNodeKV );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Just remove the parent's sub key
|
||
|
pParentNodePanel->m_pNodeKV->RemoveSubKey( m_pNodeKV );
|
||
|
}
|
||
|
|
||
|
}
|
||
|
m_pNodeKV->deleteThis();
|
||
|
}
|
||
|
|
||
|
m_pNodeKV = pNodeKV;
|
||
|
|
||
|
RecreateControls();
|
||
|
}
|
||
|
|
||
|
void CNodePanel::RecreateControls()
|
||
|
{
|
||
|
ClearHeading();
|
||
|
ClearChildren();
|
||
|
|
||
|
CreatePanelContents();
|
||
|
|
||
|
UpdateState();
|
||
|
}
|
||
|
|
||
|
void CNodePanel::UpdateState()
|
||
|
{
|
||
|
if ( m_NodeLabel[0] != '\0' )
|
||
|
{
|
||
|
m_pLabel->SetText( m_NodeLabel );
|
||
|
m_pLabel->SetVisible( true );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_pLabel->SetText( "" );
|
||
|
m_pLabel->SetVisible( false );
|
||
|
}
|
||
|
|
||
|
if ( m_bShowNameEditBox )
|
||
|
{
|
||
|
m_pNameEditBox->SetText( m_NodeName );
|
||
|
}
|
||
|
m_pNameEditBox->SetVisible( m_bShowNameEditBox );
|
||
|
m_pDeleteSelfButton->SetVisible( m_bShowDeleteButton );
|
||
|
|
||
|
// Show or hide the "add" buttons on the CNewElementPanel objects
|
||
|
for ( int i = 0; i < m_pChildSizer->GetElementCount(); ++ i )
|
||
|
{
|
||
|
if ( m_pChildSizer->GetElementType( i ) == ESET_PANEL )
|
||
|
{
|
||
|
CNewElementPanel *pNewElementPanel = dynamic_cast< CNewElementPanel * >( m_pChildSizer->GetPanel( i ) );
|
||
|
if ( pNewElementPanel != NULL )
|
||
|
{
|
||
|
pNewElementPanel->SetVisible( GetEditor()->ShouldShowAddButtons() );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Update state on all children
|
||
|
for ( int i = 0; i < m_ChildPanels.Count(); ++ i )
|
||
|
{
|
||
|
m_ChildPanels[i]->UpdateState();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CNodePanel::InvalidateEditorLayout()
|
||
|
{
|
||
|
if ( m_pEditor != NULL )
|
||
|
{
|
||
|
m_pEditor->InvalidateLayout();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CNodePanel::ClearHeading()
|
||
|
{
|
||
|
m_pHeadingSizer->RemoveAllMembers( true );
|
||
|
InvalidateEditorLayout();
|
||
|
}
|
||
|
|
||
|
void CNodePanel::AddHeadingElement( Panel *pPanel, float flExpandFactor, int nPadding )
|
||
|
{
|
||
|
m_pHeadingSizer->AddPanel( pPanel, SizerAddArgs_t().Padding( nPadding ).Expand( flExpandFactor ) );
|
||
|
InvalidateEditorLayout();
|
||
|
}
|
||
|
|
||
|
void CNodePanel::AddHeadingSpacer()
|
||
|
{
|
||
|
m_pHeadingSizer->AddSpacer( SizerAddArgs_t().Padding( 0 ).Expand( 1.0f ) );
|
||
|
InvalidateEditorLayout();
|
||
|
}
|
||
|
|
||
|
void CNodePanel::SetChildIndent( int nIndent )
|
||
|
{
|
||
|
m_pChildIndentSizer->SetElementArgs( 0, SizerAddArgs_t().MinSize( nIndent, 0 ).Padding( 0 ) );
|
||
|
InvalidateEditorLayout();
|
||
|
}
|
||
|
|
||
|
void CNodePanel::ClearChildren()
|
||
|
{
|
||
|
m_ChildPanels.RemoveAll();
|
||
|
m_pChildSizer->RemoveAllMembers( true );
|
||
|
InvalidateEditorLayout();
|
||
|
}
|
||
|
|
||
|
void CNodePanel::AddChild( CNodePanel *pPanel, int nPadding )
|
||
|
{
|
||
|
m_ChildPanels.AddToTail( pPanel );
|
||
|
AddChild( ( Panel * )pPanel, nPadding );
|
||
|
}
|
||
|
|
||
|
void CNodePanel::AddChild( Panel *pPanel, int nPadding )
|
||
|
{
|
||
|
m_pChildSizer->AddPanel( pPanel, SizerAddArgs_t().Padding( nPadding ) );
|
||
|
InvalidateEditorLayout();
|
||
|
}
|
||
|
|
||
|
void CNodePanel::InsertChildData( int nIndex, KeyValues *pKeyValues )
|
||
|
{
|
||
|
KeyValues *pNodeKV = GetData();
|
||
|
pNodeKV->InsertSubKey( nIndex, pKeyValues );
|
||
|
RecreateControls();
|
||
|
}
|
||
|
|
||
|
// Register new panel types here. There probably won't be that many kinds,
|
||
|
// so there's no reason to have a general purpose factory function.
|
||
|
CNodePanel *CNodePanel::CreateChild( KeyValues *pKey )
|
||
|
{
|
||
|
CNodePanel *pNodePanel = NULL;
|
||
|
const char *pPanelType = pKey->GetName();
|
||
|
|
||
|
if ( Q_stricmp( pPanelType, "state" ) == 0 )
|
||
|
{
|
||
|
pNodePanel = new CStateNodePanel( this, "state_panel" );
|
||
|
}
|
||
|
else if ( Q_stricmp( pPanelType, "rule_instance" ) == 0 )
|
||
|
{
|
||
|
pNodePanel = new CRuleInstanceNodePanel( this, "rule_instance_panel" );
|
||
|
}
|
||
|
|
||
|
if ( pNodePanel == NULL )
|
||
|
{
|
||
|
Log_Warning( LOG_TilegenLayoutSystem, "Unrecognized node type (cannot create panel): %s.\n", pPanelType );
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
pNodePanel->SetEditor( m_pEditor );
|
||
|
pNodePanel->SetData( pKey );
|
||
|
|
||
|
return pNodePanel;
|
||
|
}
|
||
|
|
||
|
void CNodePanel::DeleteSelf()
|
||
|
{
|
||
|
CNodePanel *pParent = dynamic_cast< CNodePanel * >( GetParent() );
|
||
|
Assert( pParent != NULL );
|
||
|
|
||
|
KeyValues *pParentKV = pParent->GetData();
|
||
|
Assert( pParentKV->ContainsSubKey( m_pNodeKV ) );
|
||
|
pParentKV->RemoveSubKey( m_pNodeKV );
|
||
|
m_pNodeKV->deleteThis();
|
||
|
m_pNodeKV = NULL;
|
||
|
|
||
|
// Refresh parent's panel contents.
|
||
|
pParent->RecreateControls();
|
||
|
}
|
||
|
|
||
|
void CNodePanel::AddNewElementPanel( int nIndex, bool bAllowRules, bool bAllowStates )
|
||
|
{
|
||
|
CNewElementPanel *pNewElementPanel = new CNewElementPanel( this, "NewElement", nIndex );
|
||
|
if ( bAllowRules )
|
||
|
{
|
||
|
pNewElementPanel->AddButton( "Add Rule", "AddRule" );
|
||
|
}
|
||
|
if ( bAllowStates )
|
||
|
{
|
||
|
pNewElementPanel->AddButton( "Add State", "AddState" );
|
||
|
}
|
||
|
AddChild( pNewElementPanel, 5 );
|
||
|
}
|
||
|
|
||
|
void CNodePanel::SetNodeName( const char *pNodeName )
|
||
|
{
|
||
|
KeyValues *pNodeKV = GetData();
|
||
|
if ( pNodeKV != NULL )
|
||
|
{
|
||
|
pNodeKV->SetString( "name", pNodeName );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CNewElementPanel::CNewElementPanel( Panel *pParent, const char *pName, int nIndex ) :
|
||
|
BaseClass( pParent, pName ),
|
||
|
m_nIndex( nIndex )
|
||
|
{
|
||
|
m_pHorizontalSizer = new CBoxSizer( ESLD_HORIZONTAL );
|
||
|
SetSizer( m_pHorizontalSizer );
|
||
|
}
|
||
|
|
||
|
void CNewElementPanel::AddButton( const char *pButtonText, const char *pActionName )
|
||
|
{
|
||
|
Button *pButton = new Button( this, pActionName, pButtonText, GetParent(), pActionName );
|
||
|
|
||
|
KeyValues *pMessageKV = new KeyValues( pActionName );
|
||
|
KeyValues *pIndexKV = new KeyValues( "index" );
|
||
|
pIndexKV->SetInt( NULL, m_nIndex );
|
||
|
pMessageKV->AddSubKey( pIndexKV );
|
||
|
pButton->SetCommand( pMessageKV );
|
||
|
|
||
|
m_pHorizontalSizer->AddPanel( pButton, SizerAddArgs_t().MinSize( 50, 20 ).Padding( 0 ) );
|
||
|
InvalidateLayout();
|
||
|
}
|