diff options
Diffstat (limited to 'vgui2/dme_controls/particlesystempropertiespanel.cpp')
| -rw-r--r-- | vgui2/dme_controls/particlesystempropertiespanel.cpp | 1149 |
1 files changed, 1149 insertions, 0 deletions
diff --git a/vgui2/dme_controls/particlesystempropertiespanel.cpp b/vgui2/dme_controls/particlesystempropertiespanel.cpp new file mode 100644 index 0000000..fb795e7 --- /dev/null +++ b/vgui2/dme_controls/particlesystempropertiespanel.cpp @@ -0,0 +1,1149 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Dialog used to edit properties of a particle system definition +// +//===========================================================================// + +#include "dme_controls/ParticleSystemPropertiesPanel.h" +#include "tier1/KeyValues.h" +#include "tier1/utlbuffer.h" +#include "vgui/IVGui.h" +#include "vgui_controls/button.h" +#include "vgui_controls/listpanel.h" +#include "vgui_controls/splitter.h" +#include "vgui_controls/messagebox.h" +#include "vgui_controls/combobox.h" +#include "datamodel/dmelement.h" +#include "movieobjects/dmeparticlesystemdefinition.h" +#include "dme_controls/elementpropertiestree.h" +#include "matsys_controls/picker.h" +#include "dme_controls/dmecontrols_utils.h" +#include "dme_controls/particlesystempanel.h" +#include "dme_controls/dmepanel.h" + + +// memdbgon must be the last include file in a .cpp file!!! +#include <tier0/memdbgon.h> + +using namespace vgui; + + +//----------------------------------------------------------------------------- +// +// Purpose: Picker for particle functions +// +//----------------------------------------------------------------------------- +class CParticleFunctionPickerFrame : public vgui::Frame +{ + DECLARE_CLASS_SIMPLE( CParticleFunctionPickerFrame, vgui::Frame ); + +public: + CParticleFunctionPickerFrame( vgui::Panel *pParent, const char *pTitle ); + ~CParticleFunctionPickerFrame(); + + // Sets the current scene + animation list + void DoModal( CDmeParticleSystemDefinition *pParticleSystem, ParticleFunctionType_t type, KeyValues *pContextKeyValues ); + + // Inherited from Frame + virtual void OnCommand( const char *pCommand ); + +private: + // Refreshes the list of particle functions + void RefreshParticleFunctions( CDmeParticleSystemDefinition *pDefinition, ParticleFunctionType_t type ); + void CleanUpMessage(); + + vgui::ListPanel *m_pFunctionList; + vgui::Button *m_pOpenButton; + vgui::Button *m_pCancelButton; + KeyValues *m_pContextKeyValues; +}; + +static int __cdecl ParticleFunctionNameSortFunc( vgui::ListPanel *pPanel, const vgui::ListPanelItem &item1, const vgui::ListPanelItem &item2 ) +{ + const char *string1 = item1.kv->GetString( "name" ); + const char *string2 = item2.kv->GetString( "name" ); + return Q_stricmp( string1, string2 ); +} + +CParticleFunctionPickerFrame::CParticleFunctionPickerFrame( vgui::Panel *pParent, const char *pTitle ) : + BaseClass( pParent, "ParticleFunctionPickerFrame" ) +{ + SetDeleteSelfOnClose( true ); + m_pContextKeyValues = NULL; + + m_pFunctionList = new vgui::ListPanel( this, "ParticleFunctionList" ); + m_pFunctionList->AddColumnHeader( 0, "name", "Particle Function Name", 52, 0 ); + m_pFunctionList->SetSelectIndividualCells( false ); + m_pFunctionList->SetMultiselectEnabled( false ); + m_pFunctionList->SetEmptyListText( "No particle functions" ); + m_pFunctionList->AddActionSignalTarget( this ); + m_pFunctionList->SetSortFunc( 0, ParticleFunctionNameSortFunc ); + m_pFunctionList->SetSortColumn( 0 ); + + m_pOpenButton = new vgui::Button( this, "OkButton", "#MessageBox_OK", this, "Ok" ); + m_pCancelButton = new vgui::Button( this, "CancelButton", "#MessageBox_Cancel", this, "Cancel" ); + SetBlockDragChaining( true ); + + LoadControlSettingsAndUserConfig( "resource/particlefunctionpicker.res" ); + + SetTitle( pTitle, false ); +} + +CParticleFunctionPickerFrame::~CParticleFunctionPickerFrame() +{ + CleanUpMessage(); +} + + +//----------------------------------------------------------------------------- +// Refreshes the list of raw controls +//----------------------------------------------------------------------------- +void CParticleFunctionPickerFrame::RefreshParticleFunctions( CDmeParticleSystemDefinition *pParticleSystem, ParticleFunctionType_t type ) +{ + m_pFunctionList->RemoveAll(); + if ( !pParticleSystem ) + return; + + CUtlVector< IParticleOperatorDefinition *> &list = g_pParticleSystemMgr->GetAvailableParticleOperatorList( type ); + int nCount = list.Count(); + + // Build a list of used operator IDs + bool pUsedIDs[OPERATOR_ID_COUNT]; + memset( pUsedIDs, 0, sizeof(pUsedIDs) ); + + int nFunctionCount = pParticleSystem->GetParticleFunctionCount( type ); + for ( int i = 0; i < nFunctionCount; ++i ) + { + const char *pFunctionName = pParticleSystem->GetParticleFunction( type, i )->GetName(); + for ( int j = 0; j < nCount; ++j ) + { + if ( Q_stricmp( pFunctionName, list[j]->GetName() ) ) + continue; + + if ( list[j]->GetId() >= 0 ) + { + pUsedIDs[ list[j]->GetId() ] = true; + } + break; + } + } + + for ( int i = 0; i < nCount; ++i ) + { + const char *pFunctionName = list[i]->GetName(); + + // Look to see if this is in a special operator group + if ( list[i]->GetId() >= 0 ) + { + // Don't display ones that are already in the particle system + if ( pUsedIDs[ list[i]->GetId() ] ) + continue; + } + + if ( list[i]->GetId() == OPERATOR_SINGLETON ) + { + // Don't display ones that are already in the particle system + if ( pParticleSystem->FindFunction( type, pFunctionName ) >= 0 ) + continue; + } + + // Don't display obsolete operators + if ( list[i]->IsObsolete() ) + continue; + + KeyValues *kv = new KeyValues( "node", "name", pFunctionName ); + m_pFunctionList->AddItem( kv, 0, false, false ); + } + + m_pFunctionList->SortList(); +} + + +//----------------------------------------------------------------------------- +// Deletes the message +//----------------------------------------------------------------------------- +void CParticleFunctionPickerFrame::CleanUpMessage() +{ + if ( m_pContextKeyValues ) + { + m_pContextKeyValues->deleteThis(); + m_pContextKeyValues = NULL; + } +} + + +//----------------------------------------------------------------------------- +// Sets the current scene + animation list +//----------------------------------------------------------------------------- +void CParticleFunctionPickerFrame::DoModal( CDmeParticleSystemDefinition *pParticleSystem, ParticleFunctionType_t type, KeyValues *pContextKeyValues ) +{ + CleanUpMessage(); + RefreshParticleFunctions( pParticleSystem, type ); + m_pContextKeyValues = pContextKeyValues; + BaseClass::DoModal(); +} + + +//----------------------------------------------------------------------------- +// On command +//----------------------------------------------------------------------------- +void CParticleFunctionPickerFrame::OnCommand( const char *pCommand ) +{ + if ( !Q_stricmp( pCommand, "Ok" ) ) + { + int nSelectedItemCount = m_pFunctionList->GetSelectedItemsCount(); + if ( nSelectedItemCount == 0 ) + return; + + Assert( nSelectedItemCount == 1 ); + int nItemID = m_pFunctionList->GetSelectedItem( 0 ); + KeyValues *pKeyValues = m_pFunctionList->GetItem( nItemID ); + + KeyValues *pActionKeys = new KeyValues( "ParticleFunctionPicked" ); + pActionKeys->SetString( "name", pKeyValues->GetString( "name" ) ); + + if ( m_pContextKeyValues ) + { + pActionKeys->AddSubKey( m_pContextKeyValues ); + + // This prevents them from being deleted later + m_pContextKeyValues = NULL; + } + + PostActionSignal( pActionKeys ); + CloseModal(); + return; + } + + if ( !Q_stricmp( pCommand, "Cancel" ) ) + { + CloseModal(); + return; + } + + BaseClass::OnCommand( pCommand ); +} + + + +//----------------------------------------------------------------------------- +// +// Purpose: Picker for child particle systems +// +//----------------------------------------------------------------------------- +class CParticleChildrenPickerFrame : public vgui::Frame +{ + DECLARE_CLASS_SIMPLE( CParticleChildrenPickerFrame, vgui::Frame ); + +public: + CParticleChildrenPickerFrame( vgui::Panel *pParent, const char *pTitle, IParticleSystemPropertiesPanelQuery *pQuery ); + ~CParticleChildrenPickerFrame(); + + // Sets the current scene + animation list + void DoModal( CDmeParticleSystemDefinition *pParticleSystem, KeyValues *pContextKeyValues ); + + // Inherited from Frame + virtual void OnCommand( const char *pCommand ); + +private: + // Refreshes the list of children particle systems + void RefreshChildrenList( CDmeParticleSystemDefinition *pDefinition ); + void CleanUpMessage(); + + IParticleSystemPropertiesPanelQuery *m_pQuery; + vgui::ListPanel *m_pChildrenList; + vgui::Button *m_pOpenButton; + vgui::Button *m_pCancelButton; + KeyValues *m_pContextKeyValues; +}; + +static int __cdecl ParticleChildrenNameSortFunc( vgui::ListPanel *pPanel, const vgui::ListPanelItem &item1, const vgui::ListPanelItem &item2 ) +{ + const char *string1 = item1.kv->GetString( "name" ); + const char *string2 = item2.kv->GetString( "name" ); + return Q_stricmp( string1, string2 ); +} + +CParticleChildrenPickerFrame::CParticleChildrenPickerFrame( vgui::Panel *pParent, const char *pTitle, IParticleSystemPropertiesPanelQuery *pQuery ) : + BaseClass( pParent, "ParticleChildrenPickerFrame" ), m_pQuery( pQuery ) +{ + SetDeleteSelfOnClose( true ); + m_pContextKeyValues = NULL; + + m_pChildrenList = new vgui::ListPanel( this, "ParticleChildrenList" ); + m_pChildrenList->AddColumnHeader( 0, "name", "Particle System Name", 52, 0 ); + m_pChildrenList->SetSelectIndividualCells( false ); + m_pChildrenList->SetMultiselectEnabled( false ); + m_pChildrenList->SetEmptyListText( "No particle systems" ); + m_pChildrenList->AddActionSignalTarget( this ); + m_pChildrenList->SetSortFunc( 0, ParticleChildrenNameSortFunc ); + m_pChildrenList->SetSortColumn( 0 ); + + m_pOpenButton = new vgui::Button( this, "OkButton", "#MessageBox_OK", this, "Ok" ); + m_pCancelButton = new vgui::Button( this, "CancelButton", "#MessageBox_Cancel", this, "Cancel" ); + SetBlockDragChaining( true ); + + LoadControlSettingsAndUserConfig( "resource/particlechildrenpicker.res" ); + + SetTitle( pTitle, false ); +} + +CParticleChildrenPickerFrame::~CParticleChildrenPickerFrame() +{ + CleanUpMessage(); +} + + +//----------------------------------------------------------------------------- +// Refreshes the list of raw controls +//----------------------------------------------------------------------------- +void CParticleChildrenPickerFrame::RefreshChildrenList( CDmeParticleSystemDefinition *pCurrentParticleSystem ) +{ + m_pChildrenList->RemoveAll(); + + CUtlVector< CDmeParticleSystemDefinition* > definitions; + if ( m_pQuery ) + { + m_pQuery->GetKnownParticleDefinitions( definitions ); + } + int nCount = definitions.Count(); + if ( nCount == 0 ) + return; + + for ( int i = 0; i < nCount; ++i ) + { + CDmeParticleSystemDefinition *pParticleSystem = definitions[i]; + if ( pParticleSystem == pCurrentParticleSystem ) + continue; + + const char *pName = pParticleSystem->GetName(); + if ( !pName || !pName[0] ) + { + pName = "<no name>"; + } + + KeyValues *kv = new KeyValues( "node" ); + kv->SetString( "name", pName ); + SetElementKeyValue( kv, "particleSystem", pParticleSystem ); + + m_pChildrenList->AddItem( kv, 0, false, false ); + } + m_pChildrenList->SortList(); +} + + +//----------------------------------------------------------------------------- +// Deletes the message +//----------------------------------------------------------------------------- +void CParticleChildrenPickerFrame::CleanUpMessage() +{ + if ( m_pContextKeyValues ) + { + m_pContextKeyValues->deleteThis(); + m_pContextKeyValues = NULL; + } +} + + +//----------------------------------------------------------------------------- +// Sets the current scene + animation list +//----------------------------------------------------------------------------- +void CParticleChildrenPickerFrame::DoModal( CDmeParticleSystemDefinition *pParticleSystem, KeyValues *pContextKeyValues ) +{ + CleanUpMessage(); + RefreshChildrenList( pParticleSystem ); + m_pContextKeyValues = pContextKeyValues; + BaseClass::DoModal(); +} + + +//----------------------------------------------------------------------------- +// On command +//----------------------------------------------------------------------------- +void CParticleChildrenPickerFrame::OnCommand( const char *pCommand ) +{ + if ( !Q_stricmp( pCommand, "Ok" ) ) + { + int nSelectedItemCount = m_pChildrenList->GetSelectedItemsCount(); + if ( nSelectedItemCount == 0 ) + return; + + Assert( nSelectedItemCount == 1 ); + int nItemID = m_pChildrenList->GetSelectedItem( 0 ); + KeyValues *pKeyValues = m_pChildrenList->GetItem( nItemID ); + CDmeParticleSystemDefinition *pParticleSystem = GetElementKeyValue<CDmeParticleSystemDefinition>( pKeyValues, "particleSystem" ); + + KeyValues *pActionKeys = new KeyValues( "ParticleChildPicked" ); + SetElementKeyValue( pActionKeys, "particleSystem", pParticleSystem ); + + if ( m_pContextKeyValues ) + { + pActionKeys->AddSubKey( m_pContextKeyValues ); + + // This prevents them from being deleted later + m_pContextKeyValues = NULL; + } + + PostActionSignal( pActionKeys ); + CloseModal(); + return; + } + + if ( !Q_stricmp( pCommand, "Cancel" ) ) + { + CloseModal(); + return; + } + + BaseClass::OnCommand( pCommand ); +} + + +//----------------------------------------------------------------------------- +// Browser of various particle functions +//----------------------------------------------------------------------------- +class CParticleFunctionBrowser : public vgui::EditablePanel +{ + DECLARE_CLASS_SIMPLE( CParticleFunctionBrowser, vgui::EditablePanel ); + +public: + // constructor, destructor + CParticleFunctionBrowser( vgui::Panel *pParent, const char *pName, ParticleFunctionType_t type, IParticleSystemPropertiesPanelQuery *pQuery ); + virtual ~CParticleFunctionBrowser(); + + // Inherited from Panel + virtual void OnKeyCodeTyped( vgui::KeyCode code ); + + void SetParticleFunctionProperties( CDmeElementPanel *pPanel ); + void SetParticleSystem( CDmeParticleSystemDefinition *pOp ); + void RefreshParticleFunctionList(); + void SelectDefaultFunction(); + + // Called when a list panel's selection changes + void RefreshParticleFunctionProperties( ); + +private: + MESSAGE_FUNC_PARAMS( OnOpenContextMenu, "OpenContextMenu", kv ); + MESSAGE_FUNC_PARAMS( OnItemSelected, "ItemSelected", kv ); + MESSAGE_FUNC_PARAMS( OnItemDeselected, "ItemDeselected", kv ); + MESSAGE_FUNC( OnAdd, "Add" ); + MESSAGE_FUNC( OnRemove, "Remove" ); + MESSAGE_FUNC( OnRename, "Rename" ); + MESSAGE_FUNC( OnMoveUp, "MoveUp" ); + MESSAGE_FUNC( OnMoveDown, "MoveDown" ); + MESSAGE_FUNC_PARAMS( OnInputCompleted, "InputCompleted", kv ); + MESSAGE_FUNC_PARAMS( OnParticleFunctionPicked, "ParticleFunctionPicked", kv ); + MESSAGE_FUNC_PARAMS( OnParticleChildPicked, "ParticleChildPicked", kv ); + + // Cleans up the context menu + void CleanupContextMenu(); + + // Returns the selected particle function + CDmeParticleFunction* GetSelectedFunction( ); + + // Returns the selected particle function + CDmeParticleFunction* GetSelectedFunction( int nIndex ); + + // Select a particular particle function + void SelectParticleFunction( CDmeParticleFunction *pFind ); + + IParticleSystemPropertiesPanelQuery *m_pQuery; + CDmeHandle< CDmeParticleSystemDefinition > m_hParticleSystem; + vgui::ListPanel *m_pFunctionList; + ParticleFunctionType_t m_FuncType; + vgui::DHANDLE< vgui::Menu > m_hContextMenu; + CDmeElementPanel *m_pParticleFunctionProperties; +}; + + +//----------------------------------------------------------------------------- +// Sort functions for list panel +//----------------------------------------------------------------------------- +static int __cdecl ParticleFunctionSortFunc( vgui::ListPanel *pPanel, const vgui::ListPanelItem &item1, const vgui::ListPanelItem &item2 ) +{ + int i1 = item1.kv->GetInt( "index" ); + int i2 = item2.kv->GetInt( "index" ); + return i1 - i2; +} + + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- +CParticleFunctionBrowser::CParticleFunctionBrowser( vgui::Panel *pParent, const char *pName, ParticleFunctionType_t type, IParticleSystemPropertiesPanelQuery *pQuery ) : + BaseClass( pParent, pName ), m_pQuery( pQuery ) +{ + SetKeyBoardInputEnabled( true ); + + m_FuncType = type; + + m_pFunctionList = new vgui::ListPanel( this, "FunctionList" ); + if ( m_FuncType != FUNCTION_CHILDREN ) + { + m_pFunctionList->AddColumnHeader( 0, "name", "Function Name", 150, 0 ); + m_pFunctionList->AddColumnHeader( 1, "type", "Function Type", 150, 0 ); + m_pFunctionList->SetEmptyListText( "No particle functions" ); + } + else + { + m_pFunctionList->AddColumnHeader( 0, "name", "Label", 150, 0 ); + m_pFunctionList->AddColumnHeader( 1, "type", "Child Name", 150, 0 ); + m_pFunctionList->SetEmptyListText( "No children" ); + } + m_pFunctionList->SetSelectIndividualCells( false ); + m_pFunctionList->SetMultiselectEnabled( true ); + m_pFunctionList->AddActionSignalTarget( this ); + m_pFunctionList->SetSortFunc( 0, ParticleFunctionSortFunc ); + m_pFunctionList->SetSortColumn( 0 ); + m_pFunctionList->AddActionSignalTarget( this ); + + LoadControlSettings( "resource/particlefunctionbrowser.res" ); +} + +CParticleFunctionBrowser::~CParticleFunctionBrowser() +{ + CleanupContextMenu(); + SaveUserConfig(); +} + + +//----------------------------------------------------------------------------- +// Cleans up the context menu +//----------------------------------------------------------------------------- +void CParticleFunctionBrowser::CleanupContextMenu() +{ + if ( m_hContextMenu.Get() ) + { + m_hContextMenu->MarkForDeletion(); + m_hContextMenu = NULL; + } +} + + +//----------------------------------------------------------------------------- +// Selects a particular function by default +//----------------------------------------------------------------------------- +void CParticleFunctionBrowser::SelectDefaultFunction() +{ + if ( m_pFunctionList->GetSelectedItemsCount() == 0 && m_pFunctionList->GetItemCount() > 0 ) + { + int nItemID = m_pFunctionList->GetItemIDFromRow( 0 ); + m_pFunctionList->SetSingleSelectedItem( nItemID ); + } +} + + +//----------------------------------------------------------------------------- +// Sets the particle system properties panel +//----------------------------------------------------------------------------- +void CParticleFunctionBrowser::SetParticleFunctionProperties( CDmeElementPanel *pPanel ) +{ + m_pParticleFunctionProperties = pPanel; +} + + +//----------------------------------------------------------------------------- +// Sets/gets the particle system +//----------------------------------------------------------------------------- +void CParticleFunctionBrowser::SetParticleSystem( CDmeParticleSystemDefinition *pParticleSystem ) +{ + if ( pParticleSystem != m_hParticleSystem.Get() ) + { + m_hParticleSystem = pParticleSystem; + RefreshParticleFunctionList(); + SelectDefaultFunction(); + } +} + + +//----------------------------------------------------------------------------- +// Builds the particle function list for the particle system +//----------------------------------------------------------------------------- +void CParticleFunctionBrowser::RefreshParticleFunctionList() +{ + if ( !m_hParticleSystem.Get() ) + return; + + // Maintain selection if possible + CUtlVector< CDmeParticleFunction* > selectedItems; + int nCount = m_pFunctionList->GetSelectedItemsCount(); + for ( int i = 0; i < nCount; ++i ) + { + selectedItems.AddToTail( GetSelectedFunction( i ) ); + } + + m_pFunctionList->RemoveAll(); + + int nSelectedCount = selectedItems.Count(); + nCount = m_hParticleSystem->GetParticleFunctionCount( m_FuncType ); + for ( int i = 0; i < nCount; ++i ) + { + CDmeParticleFunction *pFunction = m_hParticleSystem->GetParticleFunction( m_FuncType, i ); + KeyValues *kv = new KeyValues( "node", "name", pFunction->GetName() ); + kv->SetString( "type", pFunction->GetFunctionType() ); + kv->SetInt( "index", i ); + SetElementKeyValue( kv, "particleFunction", pFunction ); + int nItemID = m_pFunctionList->AddItem( kv, 0, false, false ); + + for ( int j = 0; j < nSelectedCount; ++j ) + { + if ( selectedItems[j] == pFunction ) + { + m_pFunctionList->AddSelectedItem( nItemID ); + selectedItems.FastRemove( j ); + --nSelectedCount; + break; + } + } + } + + m_pFunctionList->SortList(); +} + + +//----------------------------------------------------------------------------- +// Returns the selected particle function +//----------------------------------------------------------------------------- +CDmeParticleFunction* CParticleFunctionBrowser::GetSelectedFunction( int nIndex ) +{ + if ( !m_hParticleSystem.Get() ) + return NULL; + + int nSelectedItemCount = m_pFunctionList->GetSelectedItemsCount(); + if ( nSelectedItemCount <= nIndex ) + return NULL; + + int nItemID = m_pFunctionList->GetSelectedItem( nIndex ); + KeyValues *pKeyValues = m_pFunctionList->GetItem( nItemID ); + return GetElementKeyValue<CDmeParticleFunction>( pKeyValues, "particleFunction" ); +} + + +//----------------------------------------------------------------------------- +// Returns the selected particle function +//----------------------------------------------------------------------------- +CDmeParticleFunction* CParticleFunctionBrowser::GetSelectedFunction( ) +{ + if ( !m_hParticleSystem.Get() ) + return NULL; + + int nSelectedItemCount = m_pFunctionList->GetSelectedItemsCount(); + if ( nSelectedItemCount != 1 ) + return NULL; + + int nItemID = m_pFunctionList->GetSelectedItem( 0 ); + KeyValues *pKeyValues = m_pFunctionList->GetItem( nItemID ); + return GetElementKeyValue<CDmeParticleFunction>( pKeyValues, "particleFunction" ); +} + +void CParticleFunctionBrowser::OnMoveUp( ) +{ + CDmeParticleFunction* pFunction = GetSelectedFunction( ); + if ( !pFunction ) + return; + + { + CUndoScopeGuard guard( 0, NOTIFY_SETDIRTYFLAG, "Move Function Up", "Move Function Up" ); + m_hParticleSystem->MoveFunctionUp( m_FuncType, pFunction ); + } + PostActionSignal( new KeyValues( "ParticleSystemModified" ) ); +} + +void CParticleFunctionBrowser::OnMoveDown( ) +{ + CDmeParticleFunction* pFunction = GetSelectedFunction( ); + if ( !pFunction ) + return; + + { + CUndoScopeGuard guard( 0, NOTIFY_SETDIRTYFLAG, "Move Function Down", "Move Function Down" ); + m_hParticleSystem->MoveFunctionDown( m_FuncType, pFunction ); + } + PostActionSignal( new KeyValues( "ParticleSystemModified" ) ); +} + + +//----------------------------------------------------------------------------- +// Select a particular particle function +//----------------------------------------------------------------------------- +void CParticleFunctionBrowser::SelectParticleFunction( CDmeParticleFunction *pFind ) +{ + m_pFunctionList->ClearSelectedItems(); + for ( int nItemID = m_pFunctionList->FirstItem(); nItemID != m_pFunctionList->InvalidItemID(); nItemID = m_pFunctionList->NextItem( nItemID ) ) + { + KeyValues *kv = m_pFunctionList->GetItem( nItemID ); + CDmeParticleFunction *pFunction = GetElementKeyValue<CDmeParticleFunction>( kv, "particleFunction" ); + if ( pFunction == pFind ) + { + m_pFunctionList->AddSelectedItem( nItemID ); + break; + } + } +} + + +//----------------------------------------------------------------------------- +// Add/remove functions +//----------------------------------------------------------------------------- +void CParticleFunctionBrowser::OnParticleChildPicked( KeyValues *pKeyValues ) +{ + CDmeParticleSystemDefinition *pParticleSystem = GetElementKeyValue<CDmeParticleSystemDefinition>( pKeyValues, "particleSystem" ); + if ( !pParticleSystem || ( m_FuncType != FUNCTION_CHILDREN ) ) + return; + + CDmeParticleFunction *pFunction; + { + CUndoScopeGuard guard( 0, NOTIFY_SETDIRTYFLAG, "Add Particle System Child", "Add Particle System Child" ); + pFunction = m_hParticleSystem->AddChild( pParticleSystem ); + } + PostActionSignal( new KeyValues( "ParticleSystemModified" ) ); + SelectParticleFunction( pFunction ); +} + +void CParticleFunctionBrowser::OnParticleFunctionPicked( KeyValues *pKeyValues ) +{ + if ( m_FuncType == FUNCTION_CHILDREN ) + return; + + const char *pParticleFuncName = pKeyValues->GetString( "name" ); + CDmeParticleFunction *pFunction; + { + CUndoScopeGuard guard( 0, NOTIFY_SETDIRTYFLAG, "Add Particle Function", "Add Particle Function" ); + pFunction = m_hParticleSystem->AddOperator( m_FuncType, pParticleFuncName ); + } + PostActionSignal( new KeyValues( "ParticleSystemModified" ) ); + SelectParticleFunction( pFunction ); +} + +void CParticleFunctionBrowser::OnAdd( ) +{ + if ( m_FuncType != FUNCTION_CHILDREN ) + { + CParticleFunctionPickerFrame *pPicker = new CParticleFunctionPickerFrame( this, "Select Particle Function" ); + pPicker->DoModal( m_hParticleSystem, m_FuncType, NULL ); + } + else + { + CParticleChildrenPickerFrame *pPicker = new CParticleChildrenPickerFrame( this, "Select Child Particle Systems", m_pQuery ); + pPicker->DoModal( m_hParticleSystem, NULL ); + } +} + +void CParticleFunctionBrowser::OnRemove( ) +{ + int iSel = m_pFunctionList->GetSelectedItem( 0 ); + int nRow = m_pFunctionList->GetItemCurrentRow( iSel ) - 1; + { + CUndoScopeGuard guard( 0, NOTIFY_SETDIRTYFLAG, "Remove Particle Function", "Remove Particle Function" ); + + // + // Build a list of objects to delete. + // + CUtlVector< CDmeParticleFunction* > itemsToDelete; + int nCount = m_pFunctionList->GetSelectedItemsCount(); + for (int i = 0; i < nCount; i++) + { + CDmeParticleFunction *pParticleFunction = GetSelectedFunction( i ); + if ( pParticleFunction ) + { + itemsToDelete.AddToTail( pParticleFunction ); + } + } + + nCount = itemsToDelete.Count(); + for ( int i = 0; i < nCount; ++i ) + { + m_hParticleSystem->RemoveFunction( m_FuncType, itemsToDelete[i] ); + } + } + + PostActionSignal( new KeyValues( "ParticleSystemModified" ) ); + + // Update the list box selection. + if ( m_pFunctionList->GetItemCount() > 0 ) + { + if ( nRow < 0 ) + { + nRow = 0; + } + else if ( nRow >= m_pFunctionList->GetItemCount() ) + { + nRow = m_pFunctionList->GetItemCount() - 1; + } + + iSel = m_pFunctionList->GetItemIDFromRow( nRow ); + m_pFunctionList->SetSingleSelectedItem( iSel ); + } + else + { + m_pFunctionList->ClearSelectedItems(); + } +} + + +//----------------------------------------------------------------------------- +// Rename a particle function +//----------------------------------------------------------------------------- +void CParticleFunctionBrowser::OnInputCompleted( KeyValues *pKeyValues ) +{ + const char *pName = pKeyValues->GetString( "text" ); + CDmeParticleFunction *pFunction = GetSelectedFunction(); + { + CUndoScopeGuard guard( 0, NOTIFY_SETDIRTYFLAG, "Rename Particle Function", "Rename Particle Function" ); + pFunction->SetName( pName ); + } + PostActionSignal( new KeyValues( "ParticleSystemModified" ) ); +} + + +//----------------------------------------------------------------------------- +// Rename a particle function +//----------------------------------------------------------------------------- +void CParticleFunctionBrowser::OnRename() +{ + int nSelectedItemCount = m_pFunctionList->GetSelectedItemsCount(); + if ( nSelectedItemCount != 1 ) + return; + + vgui::InputDialog *pInput = new vgui::InputDialog( this, "Rename Particle Function", "Enter new name of particle function" ); + pInput->SetMultiline( false ); + pInput->DoModal( ); +} + + +//----------------------------------------------------------------------------- +// Called when a list panel's selection changes +//----------------------------------------------------------------------------- +void CParticleFunctionBrowser::RefreshParticleFunctionProperties( ) +{ + if ( IsVisible() ) + { + CDmeParticleFunction *pFunction = GetSelectedFunction(); + if ( pFunction ) + { + m_pParticleFunctionProperties->SetTypeDictionary( pFunction->GetEditorTypeDictionary() ); + } + m_pParticleFunctionProperties->SetDmeElement( pFunction ); + + // Notify the outside world so we can get helpers to render correctly in the preview + KeyValues *pMessage = new KeyValues( "ParticleFunctionSelChanged" ); + SetElementKeyValue( pMessage, "function", pFunction ); + PostActionSignal( pMessage ); + } +} + + +//----------------------------------------------------------------------------- +// Called when a list panel's selection changes +//----------------------------------------------------------------------------- +void CParticleFunctionBrowser::OnItemSelected( KeyValues *kv ) +{ + Panel *pPanel = (Panel *)kv->GetPtr( "panel", NULL ); + if ( pPanel == m_pFunctionList ) + { + RefreshParticleFunctionProperties(); + return; + } +} + + +//----------------------------------------------------------------------------- +// Called when a list panel's selection changes +//----------------------------------------------------------------------------- +void CParticleFunctionBrowser::OnItemDeselected( KeyValues *kv ) +{ + Panel *pPanel = (Panel *)kv->GetPtr( "panel", NULL ); + if ( pPanel == m_pFunctionList ) + { + RefreshParticleFunctionProperties(); + return; + } +} + + +//----------------------------------------------------------------------------- +// Called to open a context-sensitive menu for a particular menu item +//----------------------------------------------------------------------------- +void CParticleFunctionBrowser::OnOpenContextMenu( KeyValues *kv ) +{ + CleanupContextMenu(); + if ( !m_hParticleSystem.Get() ) + return; + + Panel *pPanel = (Panel *)kv->GetPtr( "panel", NULL ); + if ( pPanel != m_pFunctionList ) + return; + + int nSelectedItemCount = m_pFunctionList->GetSelectedItemsCount(); + m_hContextMenu = new vgui::Menu( this, "ActionMenu" ); + m_hContextMenu->AddMenuItem( "#ParticleFunctionBrowser_Add", new KeyValues( "Add" ), this ); + if ( nSelectedItemCount >= 1 ) + { + m_hContextMenu->AddMenuItem( "#ParticleFunctionBrowser_Remove", new KeyValues( "Remove" ), this ); + } + if ( nSelectedItemCount == 1 ) + { + m_hContextMenu->AddMenuItem( "#ParticleFunctionBrowser_Rename", new KeyValues( "Rename" ), this ); + m_hContextMenu->AddSeparator(); + m_hContextMenu->AddMenuItem( "#ParticleFunctionBrowser_MoveUp", new KeyValues( "MoveUp" ), this ); + m_hContextMenu->AddMenuItem( "#ParticleFunctionBrowser_MoveDown", new KeyValues( "MoveDown" ), this ); + } + + vgui::Menu::PlaceContextMenu( this, m_hContextMenu.Get() ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CParticleFunctionBrowser::OnKeyCodeTyped( vgui::KeyCode code ) +{ + if ( code == KEY_DELETE ) + { + OnRemove(); + } + else + { + BaseClass::OnKeyCodeTyped( code ); + } +} + + + +//----------------------------------------------------------------------------- +// Strings +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CParticleSystemPropertiesPanel::CParticleSystemPropertiesPanel( IParticleSystemPropertiesPanelQuery *pQuery, vgui::Panel* pParent ) + : BaseClass( pParent, "ParticleSystemPropertiesPanel" ), m_pQuery( pQuery ) +{ + SetKeyBoardInputEnabled( true ); + + m_pSplitter = new vgui::Splitter( this, "Splitter", vgui::SPLITTER_MODE_VERTICAL, 1 ); + vgui::Panel *pSplitterLeftSide = m_pSplitter->GetChild( 0 ); + vgui::Panel *pSplitterRightSide = m_pSplitter->GetChild( 1 ); + + m_pFunctionBrowserArea = new vgui::EditablePanel( pSplitterLeftSide, "FunctionBrowserArea" ); + m_pFunctionTypeCombo = new vgui::ComboBox( pSplitterLeftSide, "FunctionTypeCombo", PARTICLE_FUNCTION_COUNT+1, false ); + m_pFunctionTypeCombo->AddItem( "Properties", new KeyValues( "choice", "index", -1 ) ); + m_pFunctionTypeCombo->AddActionSignalTarget( this ); + + m_pParticleFunctionProperties = new CDmeElementPanel( pSplitterRightSide, "FunctionProperties" ); + m_pParticleFunctionProperties->SetAutoResize( vgui::Panel::PIN_TOPLEFT, vgui::Panel::AUTORESIZE_DOWNANDRIGHT, 6, 6, -6, -6 ); + m_pParticleFunctionProperties->AddActionSignalTarget( this ); + + for ( int i = 0; i < PARTICLE_FUNCTION_COUNT; ++i ) + { + const char *pTypeName = GetParticleFunctionTypeName( (ParticleFunctionType_t)i ); + + m_pFunctionTypeCombo->AddItem( pTypeName, new KeyValues( "choice", "index", i ) ); + m_pParticleFunctionBrowser[i] = new CParticleFunctionBrowser( m_pFunctionBrowserArea, "FunctionBrowser", (ParticleFunctionType_t)i, m_pQuery ); + m_pParticleFunctionBrowser[i]->SetParticleFunctionProperties( m_pParticleFunctionProperties ); + m_pParticleFunctionBrowser[i]->AddActionSignalTarget( this ); + } + + m_pFunctionTypeCombo->ActivateItemByRow( 0 ); + LoadControlSettings( "resource/particlesystempropertiespanel.res" ); +} + + +//----------------------------------------------------------------------------- +// Sets the particle system to look at +//----------------------------------------------------------------------------- +void CParticleSystemPropertiesPanel::SetParticleSystem( CDmeParticleSystemDefinition *pParticleSystem ) +{ + m_hParticleSystem = pParticleSystem; + for ( int i = 0; i < PARTICLE_FUNCTION_COUNT; ++i ) + { + m_pParticleFunctionBrowser[i]->SetParticleSystem( pParticleSystem ); + } + + KeyValues *pKeyValues = m_pFunctionTypeCombo->GetActiveItemUserData(); + int nPage = pKeyValues->GetInt( "index" ); + if ( nPage < 0 ) + { + if ( m_hParticleSystem.Get() ) + { + m_pParticleFunctionProperties->SetTypeDictionary( m_hParticleSystem->GetEditorTypeDictionary() ); + } + m_pParticleFunctionProperties->SetDmeElement( m_hParticleSystem ); + } +} + + +//----------------------------------------------------------------------------- +// Called when something changes in the dmeelement panel +//----------------------------------------------------------------------------- +void CParticleSystemPropertiesPanel::OnDmeElementChanged( KeyValues *pKeyValues ) +{ + int nNotifyFlags = pKeyValues->GetInt( "notifyFlags" ); + OnParticleSystemModified(); + + if ( nNotifyFlags & ( NOTIFY_CHANGE_TOPOLOGICAL | NOTIFY_CHANGE_ATTRIBUTE_ARRAY_SIZE ) ) + { + for ( int i = 0; i < PARTICLE_FUNCTION_COUNT; ++i ) + { + m_pParticleFunctionBrowser[i]->RefreshParticleFunctionList(); + } + } + PostActionSignal( new KeyValues( "ParticleSystemModified" ) ); +} + +void CParticleSystemPropertiesPanel::OnParticleSystemModifiedInternal() +{ + OnParticleSystemModified(); + Refresh( false ); + PostActionSignal( new KeyValues( "ParticleSystemModified" ) ); +} + + +void CParticleSystemPropertiesPanel::OnParticleFunctionSelChanged( KeyValues *pParams ) +{ + // Notify the outside world so we can get helpers to render correctly in the preview + CDmeParticleFunction *pFunction = GetElementKeyValue<CDmeParticleFunction>( pParams, "function" ); + KeyValues *pMessage = new KeyValues( "ParticleFunctionSelChanged" ); + SetElementKeyValue( pMessage, "function", pFunction ); + PostActionSignal( pMessage ); +} + + +//----------------------------------------------------------------------------- +// Refreshes display +//----------------------------------------------------------------------------- +void CParticleSystemPropertiesPanel::Refresh( bool bValuesOnly ) +{ + for ( int i = 0; i < PARTICLE_FUNCTION_COUNT; ++i ) + { + m_pParticleFunctionBrowser[i]->RefreshParticleFunctionList(); + } + m_pParticleFunctionProperties->Refresh( bValuesOnly ? CElementPropertiesTreeInternal::REFRESH_VALUES_ONLY : + CElementPropertiesTreeInternal::REFRESH_TREE_VIEW ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Called when a page is shown +//----------------------------------------------------------------------------- +void CParticleSystemPropertiesPanel::OnTextChanged( ) +{ + for ( int i = 0; i < PARTICLE_FUNCTION_COUNT; ++i ) + { + m_pParticleFunctionBrowser[i]->SetVisible( false ); + } + + KeyValues *pKeyValues = m_pFunctionTypeCombo->GetActiveItemUserData(); + int nPage = pKeyValues->GetInt( "index" ); + if ( nPage < 0 ) + { + if ( m_hParticleSystem.Get() ) + { + m_pParticleFunctionProperties->SetTypeDictionary( m_hParticleSystem->GetEditorTypeDictionary() ); + } + m_pParticleFunctionProperties->SetDmeElement( m_hParticleSystem ); + return; + } + + m_pParticleFunctionBrowser[nPage]->SetVisible( true ); + m_pParticleFunctionBrowser[nPage]->SelectDefaultFunction(); + m_pParticleFunctionBrowser[nPage]->RefreshParticleFunctionProperties(); +} + + + + +//----------------------------------------------------------------------------- +// A little panel used as a DmePanel for particle systems +//----------------------------------------------------------------------------- +class CParticleSystemDmePanel : public vgui::EditablePanel +{ + DECLARE_CLASS_SIMPLE( CParticleSystemDmePanel, vgui::EditablePanel ); + +public: + // constructor, destructor + CParticleSystemDmePanel( vgui::Panel *pParent, const char *pName ); + virtual ~CParticleSystemDmePanel(); + + // Set the material to draw + void SetDmeElement( CDmeParticleSystemDefinition *pDef ); + +private: + MESSAGE_FUNC_INT( OnElementChangedExternally, "ElementChangedExternally", valuesOnly ); + MESSAGE_FUNC( OnParticleSystemModified, "ParticleSystemModified" ); + MESSAGE_FUNC_PARAMS( OnParticleFunctionSelChanged, "ParticleFunctionSelChanged", params ); + + vgui::Splitter *m_Splitter; + CParticleSystemPropertiesPanel *m_pProperties; + CParticleSystemPreviewPanel *m_pPreview; +}; + + +//----------------------------------------------------------------------------- +// Dme panel connection +//----------------------------------------------------------------------------- +IMPLEMENT_DMEPANEL_FACTORY( CParticleSystemDmePanel, DmeParticleSystemDefinition, "DmeParticleSystemDefinitionEditor", "Particle System Editor", true ); + + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- +CParticleSystemDmePanel::CParticleSystemDmePanel( vgui::Panel *pParent, const char *pName ) : + BaseClass( pParent, pName ) +{ + m_Splitter = new vgui::Splitter( this, "Splitter", SPLITTER_MODE_HORIZONTAL, 1 ); + vgui::Panel *pSplitterTopSide = m_Splitter->GetChild( 0 ); + vgui::Panel *pSplitterBottomSide = m_Splitter->GetChild( 1 ); + m_Splitter->SetAutoResize( PIN_TOPLEFT, AUTORESIZE_DOWNANDRIGHT, 0, 0, 0, 0 ); + + m_pProperties = new CParticleSystemPropertiesPanel( NULL, pSplitterBottomSide ); + m_pProperties->AddActionSignalTarget( this ); + m_pProperties->SetAutoResize( PIN_TOPLEFT, AUTORESIZE_DOWNANDRIGHT, 0, 0, 0, 0 ); + + m_pPreview = new CParticleSystemPreviewPanel( pSplitterTopSide, "Preview" ); + m_pPreview->SetAutoResize( PIN_TOPLEFT, AUTORESIZE_DOWNANDRIGHT, 0, 0, 0, 0 ); +} + +CParticleSystemDmePanel::~CParticleSystemDmePanel() +{ +} + + +//----------------------------------------------------------------------------- +// Layout +//----------------------------------------------------------------------------- +void CParticleSystemDmePanel::SetDmeElement( CDmeParticleSystemDefinition *pDef ) +{ + m_pProperties->SetParticleSystem( pDef ); + m_pPreview->SetParticleSystem( pDef ); +} + + +//----------------------------------------------------------------------------- +// Particle system modified externally to the editor +//----------------------------------------------------------------------------- +void CParticleSystemDmePanel::OnElementChangedExternally( int valuesOnly ) +{ + m_pProperties->Refresh( valuesOnly != 0 ); +} + + +//----------------------------------------------------------------------------- +// Called when the selected particle function changes +//----------------------------------------------------------------------------- +void CParticleSystemDmePanel::OnParticleFunctionSelChanged( KeyValues *pParams ) +{ + CDmeParticleFunction *pFunction = GetElementKeyValue<CDmeParticleFunction>( pParams, "function" ); + m_pPreview->SetParticleFunction( pFunction ); +} + + +//----------------------------------------------------------------------------- +// Communicate to the owning DmePanel +//----------------------------------------------------------------------------- +void CParticleSystemDmePanel::OnParticleSystemModified() +{ + PostActionSignal( new KeyValues( "DmeElementChanged" ) ); +} |