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.

1149 lines
38 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Dialog used to edit properties of a particle system definition
  4. //
  5. //===========================================================================//
  6. #include "dme_controls/ParticleSystemPropertiesPanel.h"
  7. #include "tier1/KeyValues.h"
  8. #include "tier1/utlbuffer.h"
  9. #include "vgui/IVGui.h"
  10. #include "vgui_controls/button.h"
  11. #include "vgui_controls/listpanel.h"
  12. #include "vgui_controls/splitter.h"
  13. #include "vgui_controls/messagebox.h"
  14. #include "vgui_controls/combobox.h"
  15. #include "datamodel/dmelement.h"
  16. #include "movieobjects/dmeparticlesystemdefinition.h"
  17. #include "dme_controls/elementpropertiestree.h"
  18. #include "matsys_controls/picker.h"
  19. #include "dme_controls/dmecontrols_utils.h"
  20. #include "dme_controls/particlesystempanel.h"
  21. #include "dme_controls/dmepanel.h"
  22. // memdbgon must be the last include file in a .cpp file!!!
  23. #include <tier0/memdbgon.h>
  24. using namespace vgui;
  25. //-----------------------------------------------------------------------------
  26. //
  27. // Purpose: Picker for particle functions
  28. //
  29. //-----------------------------------------------------------------------------
  30. class CParticleFunctionPickerFrame : public vgui::Frame
  31. {
  32. DECLARE_CLASS_SIMPLE( CParticleFunctionPickerFrame, vgui::Frame );
  33. public:
  34. CParticleFunctionPickerFrame( vgui::Panel *pParent, const char *pTitle );
  35. ~CParticleFunctionPickerFrame();
  36. // Sets the current scene + animation list
  37. void DoModal( CDmeParticleSystemDefinition *pParticleSystem, ParticleFunctionType_t type, KeyValues *pContextKeyValues );
  38. // Inherited from Frame
  39. virtual void OnCommand( const char *pCommand );
  40. private:
  41. // Refreshes the list of particle functions
  42. void RefreshParticleFunctions( CDmeParticleSystemDefinition *pDefinition, ParticleFunctionType_t type );
  43. void CleanUpMessage();
  44. vgui::ListPanel *m_pFunctionList;
  45. vgui::Button *m_pOpenButton;
  46. vgui::Button *m_pCancelButton;
  47. KeyValues *m_pContextKeyValues;
  48. };
  49. static int __cdecl ParticleFunctionNameSortFunc( vgui::ListPanel *pPanel, const vgui::ListPanelItem &item1, const vgui::ListPanelItem &item2 )
  50. {
  51. const char *string1 = item1.kv->GetString( "name" );
  52. const char *string2 = item2.kv->GetString( "name" );
  53. return Q_stricmp( string1, string2 );
  54. }
  55. CParticleFunctionPickerFrame::CParticleFunctionPickerFrame( vgui::Panel *pParent, const char *pTitle ) :
  56. BaseClass( pParent, "ParticleFunctionPickerFrame" )
  57. {
  58. SetDeleteSelfOnClose( true );
  59. m_pContextKeyValues = NULL;
  60. m_pFunctionList = new vgui::ListPanel( this, "ParticleFunctionList" );
  61. m_pFunctionList->AddColumnHeader( 0, "name", "Particle Function Name", 52, 0 );
  62. m_pFunctionList->SetSelectIndividualCells( false );
  63. m_pFunctionList->SetMultiselectEnabled( false );
  64. m_pFunctionList->SetEmptyListText( "No particle functions" );
  65. m_pFunctionList->AddActionSignalTarget( this );
  66. m_pFunctionList->SetSortFunc( 0, ParticleFunctionNameSortFunc );
  67. m_pFunctionList->SetSortColumn( 0 );
  68. m_pOpenButton = new vgui::Button( this, "OkButton", "#MessageBox_OK", this, "Ok" );
  69. m_pCancelButton = new vgui::Button( this, "CancelButton", "#MessageBox_Cancel", this, "Cancel" );
  70. SetBlockDragChaining( true );
  71. LoadControlSettingsAndUserConfig( "resource/particlefunctionpicker.res" );
  72. SetTitle( pTitle, false );
  73. }
  74. CParticleFunctionPickerFrame::~CParticleFunctionPickerFrame()
  75. {
  76. CleanUpMessage();
  77. }
  78. //-----------------------------------------------------------------------------
  79. // Refreshes the list of raw controls
  80. //-----------------------------------------------------------------------------
  81. void CParticleFunctionPickerFrame::RefreshParticleFunctions( CDmeParticleSystemDefinition *pParticleSystem, ParticleFunctionType_t type )
  82. {
  83. m_pFunctionList->RemoveAll();
  84. if ( !pParticleSystem )
  85. return;
  86. CUtlVector< IParticleOperatorDefinition *> &list = g_pParticleSystemMgr->GetAvailableParticleOperatorList( type );
  87. int nCount = list.Count();
  88. // Build a list of used operator IDs
  89. bool pUsedIDs[OPERATOR_ID_COUNT];
  90. memset( pUsedIDs, 0, sizeof(pUsedIDs) );
  91. int nFunctionCount = pParticleSystem->GetParticleFunctionCount( type );
  92. for ( int i = 0; i < nFunctionCount; ++i )
  93. {
  94. const char *pFunctionName = pParticleSystem->GetParticleFunction( type, i )->GetName();
  95. for ( int j = 0; j < nCount; ++j )
  96. {
  97. if ( Q_stricmp( pFunctionName, list[j]->GetName() ) )
  98. continue;
  99. if ( list[j]->GetId() >= 0 )
  100. {
  101. pUsedIDs[ list[j]->GetId() ] = true;
  102. }
  103. break;
  104. }
  105. }
  106. for ( int i = 0; i < nCount; ++i )
  107. {
  108. const char *pFunctionName = list[i]->GetName();
  109. // Look to see if this is in a special operator group
  110. if ( list[i]->GetId() >= 0 )
  111. {
  112. // Don't display ones that are already in the particle system
  113. if ( pUsedIDs[ list[i]->GetId() ] )
  114. continue;
  115. }
  116. if ( list[i]->GetId() == OPERATOR_SINGLETON )
  117. {
  118. // Don't display ones that are already in the particle system
  119. if ( pParticleSystem->FindFunction( type, pFunctionName ) >= 0 )
  120. continue;
  121. }
  122. // Don't display obsolete operators
  123. if ( list[i]->IsObsolete() )
  124. continue;
  125. KeyValues *kv = new KeyValues( "node", "name", pFunctionName );
  126. m_pFunctionList->AddItem( kv, 0, false, false );
  127. }
  128. m_pFunctionList->SortList();
  129. }
  130. //-----------------------------------------------------------------------------
  131. // Deletes the message
  132. //-----------------------------------------------------------------------------
  133. void CParticleFunctionPickerFrame::CleanUpMessage()
  134. {
  135. if ( m_pContextKeyValues )
  136. {
  137. m_pContextKeyValues->deleteThis();
  138. m_pContextKeyValues = NULL;
  139. }
  140. }
  141. //-----------------------------------------------------------------------------
  142. // Sets the current scene + animation list
  143. //-----------------------------------------------------------------------------
  144. void CParticleFunctionPickerFrame::DoModal( CDmeParticleSystemDefinition *pParticleSystem, ParticleFunctionType_t type, KeyValues *pContextKeyValues )
  145. {
  146. CleanUpMessage();
  147. RefreshParticleFunctions( pParticleSystem, type );
  148. m_pContextKeyValues = pContextKeyValues;
  149. BaseClass::DoModal();
  150. }
  151. //-----------------------------------------------------------------------------
  152. // On command
  153. //-----------------------------------------------------------------------------
  154. void CParticleFunctionPickerFrame::OnCommand( const char *pCommand )
  155. {
  156. if ( !Q_stricmp( pCommand, "Ok" ) )
  157. {
  158. int nSelectedItemCount = m_pFunctionList->GetSelectedItemsCount();
  159. if ( nSelectedItemCount == 0 )
  160. return;
  161. Assert( nSelectedItemCount == 1 );
  162. int nItemID = m_pFunctionList->GetSelectedItem( 0 );
  163. KeyValues *pKeyValues = m_pFunctionList->GetItem( nItemID );
  164. KeyValues *pActionKeys = new KeyValues( "ParticleFunctionPicked" );
  165. pActionKeys->SetString( "name", pKeyValues->GetString( "name" ) );
  166. if ( m_pContextKeyValues )
  167. {
  168. pActionKeys->AddSubKey( m_pContextKeyValues );
  169. // This prevents them from being deleted later
  170. m_pContextKeyValues = NULL;
  171. }
  172. PostActionSignal( pActionKeys );
  173. CloseModal();
  174. return;
  175. }
  176. if ( !Q_stricmp( pCommand, "Cancel" ) )
  177. {
  178. CloseModal();
  179. return;
  180. }
  181. BaseClass::OnCommand( pCommand );
  182. }
  183. //-----------------------------------------------------------------------------
  184. //
  185. // Purpose: Picker for child particle systems
  186. //
  187. //-----------------------------------------------------------------------------
  188. class CParticleChildrenPickerFrame : public vgui::Frame
  189. {
  190. DECLARE_CLASS_SIMPLE( CParticleChildrenPickerFrame, vgui::Frame );
  191. public:
  192. CParticleChildrenPickerFrame( vgui::Panel *pParent, const char *pTitle, IParticleSystemPropertiesPanelQuery *pQuery );
  193. ~CParticleChildrenPickerFrame();
  194. // Sets the current scene + animation list
  195. void DoModal( CDmeParticleSystemDefinition *pParticleSystem, KeyValues *pContextKeyValues );
  196. // Inherited from Frame
  197. virtual void OnCommand( const char *pCommand );
  198. private:
  199. // Refreshes the list of children particle systems
  200. void RefreshChildrenList( CDmeParticleSystemDefinition *pDefinition );
  201. void CleanUpMessage();
  202. IParticleSystemPropertiesPanelQuery *m_pQuery;
  203. vgui::ListPanel *m_pChildrenList;
  204. vgui::Button *m_pOpenButton;
  205. vgui::Button *m_pCancelButton;
  206. KeyValues *m_pContextKeyValues;
  207. };
  208. static int __cdecl ParticleChildrenNameSortFunc( vgui::ListPanel *pPanel, const vgui::ListPanelItem &item1, const vgui::ListPanelItem &item2 )
  209. {
  210. const char *string1 = item1.kv->GetString( "name" );
  211. const char *string2 = item2.kv->GetString( "name" );
  212. return Q_stricmp( string1, string2 );
  213. }
  214. CParticleChildrenPickerFrame::CParticleChildrenPickerFrame( vgui::Panel *pParent, const char *pTitle, IParticleSystemPropertiesPanelQuery *pQuery ) :
  215. BaseClass( pParent, "ParticleChildrenPickerFrame" ), m_pQuery( pQuery )
  216. {
  217. SetDeleteSelfOnClose( true );
  218. m_pContextKeyValues = NULL;
  219. m_pChildrenList = new vgui::ListPanel( this, "ParticleChildrenList" );
  220. m_pChildrenList->AddColumnHeader( 0, "name", "Particle System Name", 52, 0 );
  221. m_pChildrenList->SetSelectIndividualCells( false );
  222. m_pChildrenList->SetMultiselectEnabled( false );
  223. m_pChildrenList->SetEmptyListText( "No particle systems" );
  224. m_pChildrenList->AddActionSignalTarget( this );
  225. m_pChildrenList->SetSortFunc( 0, ParticleChildrenNameSortFunc );
  226. m_pChildrenList->SetSortColumn( 0 );
  227. m_pOpenButton = new vgui::Button( this, "OkButton", "#MessageBox_OK", this, "Ok" );
  228. m_pCancelButton = new vgui::Button( this, "CancelButton", "#MessageBox_Cancel", this, "Cancel" );
  229. SetBlockDragChaining( true );
  230. LoadControlSettingsAndUserConfig( "resource/particlechildrenpicker.res" );
  231. SetTitle( pTitle, false );
  232. }
  233. CParticleChildrenPickerFrame::~CParticleChildrenPickerFrame()
  234. {
  235. CleanUpMessage();
  236. }
  237. //-----------------------------------------------------------------------------
  238. // Refreshes the list of raw controls
  239. //-----------------------------------------------------------------------------
  240. void CParticleChildrenPickerFrame::RefreshChildrenList( CDmeParticleSystemDefinition *pCurrentParticleSystem )
  241. {
  242. m_pChildrenList->RemoveAll();
  243. CUtlVector< CDmeParticleSystemDefinition* > definitions;
  244. if ( m_pQuery )
  245. {
  246. m_pQuery->GetKnownParticleDefinitions( definitions );
  247. }
  248. int nCount = definitions.Count();
  249. if ( nCount == 0 )
  250. return;
  251. for ( int i = 0; i < nCount; ++i )
  252. {
  253. CDmeParticleSystemDefinition *pParticleSystem = definitions[i];
  254. if ( pParticleSystem == pCurrentParticleSystem )
  255. continue;
  256. const char *pName = pParticleSystem->GetName();
  257. if ( !pName || !pName[0] )
  258. {
  259. pName = "<no name>";
  260. }
  261. KeyValues *kv = new KeyValues( "node" );
  262. kv->SetString( "name", pName );
  263. SetElementKeyValue( kv, "particleSystem", pParticleSystem );
  264. m_pChildrenList->AddItem( kv, 0, false, false );
  265. }
  266. m_pChildrenList->SortList();
  267. }
  268. //-----------------------------------------------------------------------------
  269. // Deletes the message
  270. //-----------------------------------------------------------------------------
  271. void CParticleChildrenPickerFrame::CleanUpMessage()
  272. {
  273. if ( m_pContextKeyValues )
  274. {
  275. m_pContextKeyValues->deleteThis();
  276. m_pContextKeyValues = NULL;
  277. }
  278. }
  279. //-----------------------------------------------------------------------------
  280. // Sets the current scene + animation list
  281. //-----------------------------------------------------------------------------
  282. void CParticleChildrenPickerFrame::DoModal( CDmeParticleSystemDefinition *pParticleSystem, KeyValues *pContextKeyValues )
  283. {
  284. CleanUpMessage();
  285. RefreshChildrenList( pParticleSystem );
  286. m_pContextKeyValues = pContextKeyValues;
  287. BaseClass::DoModal();
  288. }
  289. //-----------------------------------------------------------------------------
  290. // On command
  291. //-----------------------------------------------------------------------------
  292. void CParticleChildrenPickerFrame::OnCommand( const char *pCommand )
  293. {
  294. if ( !Q_stricmp( pCommand, "Ok" ) )
  295. {
  296. int nSelectedItemCount = m_pChildrenList->GetSelectedItemsCount();
  297. if ( nSelectedItemCount == 0 )
  298. return;
  299. Assert( nSelectedItemCount == 1 );
  300. int nItemID = m_pChildrenList->GetSelectedItem( 0 );
  301. KeyValues *pKeyValues = m_pChildrenList->GetItem( nItemID );
  302. CDmeParticleSystemDefinition *pParticleSystem = GetElementKeyValue<CDmeParticleSystemDefinition>( pKeyValues, "particleSystem" );
  303. KeyValues *pActionKeys = new KeyValues( "ParticleChildPicked" );
  304. SetElementKeyValue( pActionKeys, "particleSystem", pParticleSystem );
  305. if ( m_pContextKeyValues )
  306. {
  307. pActionKeys->AddSubKey( m_pContextKeyValues );
  308. // This prevents them from being deleted later
  309. m_pContextKeyValues = NULL;
  310. }
  311. PostActionSignal( pActionKeys );
  312. CloseModal();
  313. return;
  314. }
  315. if ( !Q_stricmp( pCommand, "Cancel" ) )
  316. {
  317. CloseModal();
  318. return;
  319. }
  320. BaseClass::OnCommand( pCommand );
  321. }
  322. //-----------------------------------------------------------------------------
  323. // Browser of various particle functions
  324. //-----------------------------------------------------------------------------
  325. class CParticleFunctionBrowser : public vgui::EditablePanel
  326. {
  327. DECLARE_CLASS_SIMPLE( CParticleFunctionBrowser, vgui::EditablePanel );
  328. public:
  329. // constructor, destructor
  330. CParticleFunctionBrowser( vgui::Panel *pParent, const char *pName, ParticleFunctionType_t type, IParticleSystemPropertiesPanelQuery *pQuery );
  331. virtual ~CParticleFunctionBrowser();
  332. // Inherited from Panel
  333. virtual void OnKeyCodeTyped( vgui::KeyCode code );
  334. void SetParticleFunctionProperties( CDmeElementPanel *pPanel );
  335. void SetParticleSystem( CDmeParticleSystemDefinition *pOp );
  336. void RefreshParticleFunctionList();
  337. void SelectDefaultFunction();
  338. // Called when a list panel's selection changes
  339. void RefreshParticleFunctionProperties( );
  340. private:
  341. MESSAGE_FUNC_PARAMS( OnOpenContextMenu, "OpenContextMenu", kv );
  342. MESSAGE_FUNC_PARAMS( OnItemSelected, "ItemSelected", kv );
  343. MESSAGE_FUNC_PARAMS( OnItemDeselected, "ItemDeselected", kv );
  344. MESSAGE_FUNC( OnAdd, "Add" );
  345. MESSAGE_FUNC( OnRemove, "Remove" );
  346. MESSAGE_FUNC( OnRename, "Rename" );
  347. MESSAGE_FUNC( OnMoveUp, "MoveUp" );
  348. MESSAGE_FUNC( OnMoveDown, "MoveDown" );
  349. MESSAGE_FUNC_PARAMS( OnInputCompleted, "InputCompleted", kv );
  350. MESSAGE_FUNC_PARAMS( OnParticleFunctionPicked, "ParticleFunctionPicked", kv );
  351. MESSAGE_FUNC_PARAMS( OnParticleChildPicked, "ParticleChildPicked", kv );
  352. // Cleans up the context menu
  353. void CleanupContextMenu();
  354. // Returns the selected particle function
  355. CDmeParticleFunction* GetSelectedFunction( );
  356. // Returns the selected particle function
  357. CDmeParticleFunction* GetSelectedFunction( int nIndex );
  358. // Select a particular particle function
  359. void SelectParticleFunction( CDmeParticleFunction *pFind );
  360. IParticleSystemPropertiesPanelQuery *m_pQuery;
  361. CDmeHandle< CDmeParticleSystemDefinition > m_hParticleSystem;
  362. vgui::ListPanel *m_pFunctionList;
  363. ParticleFunctionType_t m_FuncType;
  364. vgui::DHANDLE< vgui::Menu > m_hContextMenu;
  365. CDmeElementPanel *m_pParticleFunctionProperties;
  366. };
  367. //-----------------------------------------------------------------------------
  368. // Sort functions for list panel
  369. //-----------------------------------------------------------------------------
  370. static int __cdecl ParticleFunctionSortFunc( vgui::ListPanel *pPanel, const vgui::ListPanelItem &item1, const vgui::ListPanelItem &item2 )
  371. {
  372. int i1 = item1.kv->GetInt( "index" );
  373. int i2 = item2.kv->GetInt( "index" );
  374. return i1 - i2;
  375. }
  376. //-----------------------------------------------------------------------------
  377. // constructor, destructor
  378. //-----------------------------------------------------------------------------
  379. CParticleFunctionBrowser::CParticleFunctionBrowser( vgui::Panel *pParent, const char *pName, ParticleFunctionType_t type, IParticleSystemPropertiesPanelQuery *pQuery ) :
  380. BaseClass( pParent, pName ), m_pQuery( pQuery )
  381. {
  382. SetKeyBoardInputEnabled( true );
  383. m_FuncType = type;
  384. m_pFunctionList = new vgui::ListPanel( this, "FunctionList" );
  385. if ( m_FuncType != FUNCTION_CHILDREN )
  386. {
  387. m_pFunctionList->AddColumnHeader( 0, "name", "Function Name", 150, 0 );
  388. m_pFunctionList->AddColumnHeader( 1, "type", "Function Type", 150, 0 );
  389. m_pFunctionList->SetEmptyListText( "No particle functions" );
  390. }
  391. else
  392. {
  393. m_pFunctionList->AddColumnHeader( 0, "name", "Label", 150, 0 );
  394. m_pFunctionList->AddColumnHeader( 1, "type", "Child Name", 150, 0 );
  395. m_pFunctionList->SetEmptyListText( "No children" );
  396. }
  397. m_pFunctionList->SetSelectIndividualCells( false );
  398. m_pFunctionList->SetMultiselectEnabled( true );
  399. m_pFunctionList->AddActionSignalTarget( this );
  400. m_pFunctionList->SetSortFunc( 0, ParticleFunctionSortFunc );
  401. m_pFunctionList->SetSortColumn( 0 );
  402. m_pFunctionList->AddActionSignalTarget( this );
  403. LoadControlSettings( "resource/particlefunctionbrowser.res" );
  404. }
  405. CParticleFunctionBrowser::~CParticleFunctionBrowser()
  406. {
  407. CleanupContextMenu();
  408. SaveUserConfig();
  409. }
  410. //-----------------------------------------------------------------------------
  411. // Cleans up the context menu
  412. //-----------------------------------------------------------------------------
  413. void CParticleFunctionBrowser::CleanupContextMenu()
  414. {
  415. if ( m_hContextMenu.Get() )
  416. {
  417. m_hContextMenu->MarkForDeletion();
  418. m_hContextMenu = NULL;
  419. }
  420. }
  421. //-----------------------------------------------------------------------------
  422. // Selects a particular function by default
  423. //-----------------------------------------------------------------------------
  424. void CParticleFunctionBrowser::SelectDefaultFunction()
  425. {
  426. if ( m_pFunctionList->GetSelectedItemsCount() == 0 && m_pFunctionList->GetItemCount() > 0 )
  427. {
  428. int nItemID = m_pFunctionList->GetItemIDFromRow( 0 );
  429. m_pFunctionList->SetSingleSelectedItem( nItemID );
  430. }
  431. }
  432. //-----------------------------------------------------------------------------
  433. // Sets the particle system properties panel
  434. //-----------------------------------------------------------------------------
  435. void CParticleFunctionBrowser::SetParticleFunctionProperties( CDmeElementPanel *pPanel )
  436. {
  437. m_pParticleFunctionProperties = pPanel;
  438. }
  439. //-----------------------------------------------------------------------------
  440. // Sets/gets the particle system
  441. //-----------------------------------------------------------------------------
  442. void CParticleFunctionBrowser::SetParticleSystem( CDmeParticleSystemDefinition *pParticleSystem )
  443. {
  444. if ( pParticleSystem != m_hParticleSystem.Get() )
  445. {
  446. m_hParticleSystem = pParticleSystem;
  447. RefreshParticleFunctionList();
  448. SelectDefaultFunction();
  449. }
  450. }
  451. //-----------------------------------------------------------------------------
  452. // Builds the particle function list for the particle system
  453. //-----------------------------------------------------------------------------
  454. void CParticleFunctionBrowser::RefreshParticleFunctionList()
  455. {
  456. if ( !m_hParticleSystem.Get() )
  457. return;
  458. // Maintain selection if possible
  459. CUtlVector< CDmeParticleFunction* > selectedItems;
  460. int nCount = m_pFunctionList->GetSelectedItemsCount();
  461. for ( int i = 0; i < nCount; ++i )
  462. {
  463. selectedItems.AddToTail( GetSelectedFunction( i ) );
  464. }
  465. m_pFunctionList->RemoveAll();
  466. int nSelectedCount = selectedItems.Count();
  467. nCount = m_hParticleSystem->GetParticleFunctionCount( m_FuncType );
  468. for ( int i = 0; i < nCount; ++i )
  469. {
  470. CDmeParticleFunction *pFunction = m_hParticleSystem->GetParticleFunction( m_FuncType, i );
  471. KeyValues *kv = new KeyValues( "node", "name", pFunction->GetName() );
  472. kv->SetString( "type", pFunction->GetFunctionType() );
  473. kv->SetInt( "index", i );
  474. SetElementKeyValue( kv, "particleFunction", pFunction );
  475. int nItemID = m_pFunctionList->AddItem( kv, 0, false, false );
  476. for ( int j = 0; j < nSelectedCount; ++j )
  477. {
  478. if ( selectedItems[j] == pFunction )
  479. {
  480. m_pFunctionList->AddSelectedItem( nItemID );
  481. selectedItems.FastRemove( j );
  482. --nSelectedCount;
  483. break;
  484. }
  485. }
  486. }
  487. m_pFunctionList->SortList();
  488. }
  489. //-----------------------------------------------------------------------------
  490. // Returns the selected particle function
  491. //-----------------------------------------------------------------------------
  492. CDmeParticleFunction* CParticleFunctionBrowser::GetSelectedFunction( int nIndex )
  493. {
  494. if ( !m_hParticleSystem.Get() )
  495. return NULL;
  496. int nSelectedItemCount = m_pFunctionList->GetSelectedItemsCount();
  497. if ( nSelectedItemCount <= nIndex )
  498. return NULL;
  499. int nItemID = m_pFunctionList->GetSelectedItem( nIndex );
  500. KeyValues *pKeyValues = m_pFunctionList->GetItem( nItemID );
  501. return GetElementKeyValue<CDmeParticleFunction>( pKeyValues, "particleFunction" );
  502. }
  503. //-----------------------------------------------------------------------------
  504. // Returns the selected particle function
  505. //-----------------------------------------------------------------------------
  506. CDmeParticleFunction* CParticleFunctionBrowser::GetSelectedFunction( )
  507. {
  508. if ( !m_hParticleSystem.Get() )
  509. return NULL;
  510. int nSelectedItemCount = m_pFunctionList->GetSelectedItemsCount();
  511. if ( nSelectedItemCount != 1 )
  512. return NULL;
  513. int nItemID = m_pFunctionList->GetSelectedItem( 0 );
  514. KeyValues *pKeyValues = m_pFunctionList->GetItem( nItemID );
  515. return GetElementKeyValue<CDmeParticleFunction>( pKeyValues, "particleFunction" );
  516. }
  517. void CParticleFunctionBrowser::OnMoveUp( )
  518. {
  519. CDmeParticleFunction* pFunction = GetSelectedFunction( );
  520. if ( !pFunction )
  521. return;
  522. {
  523. CUndoScopeGuard guard( 0, NOTIFY_SETDIRTYFLAG, "Move Function Up", "Move Function Up" );
  524. m_hParticleSystem->MoveFunctionUp( m_FuncType, pFunction );
  525. }
  526. PostActionSignal( new KeyValues( "ParticleSystemModified" ) );
  527. }
  528. void CParticleFunctionBrowser::OnMoveDown( )
  529. {
  530. CDmeParticleFunction* pFunction = GetSelectedFunction( );
  531. if ( !pFunction )
  532. return;
  533. {
  534. CUndoScopeGuard guard( 0, NOTIFY_SETDIRTYFLAG, "Move Function Down", "Move Function Down" );
  535. m_hParticleSystem->MoveFunctionDown( m_FuncType, pFunction );
  536. }
  537. PostActionSignal( new KeyValues( "ParticleSystemModified" ) );
  538. }
  539. //-----------------------------------------------------------------------------
  540. // Select a particular particle function
  541. //-----------------------------------------------------------------------------
  542. void CParticleFunctionBrowser::SelectParticleFunction( CDmeParticleFunction *pFind )
  543. {
  544. m_pFunctionList->ClearSelectedItems();
  545. for ( int nItemID = m_pFunctionList->FirstItem(); nItemID != m_pFunctionList->InvalidItemID(); nItemID = m_pFunctionList->NextItem( nItemID ) )
  546. {
  547. KeyValues *kv = m_pFunctionList->GetItem( nItemID );
  548. CDmeParticleFunction *pFunction = GetElementKeyValue<CDmeParticleFunction>( kv, "particleFunction" );
  549. if ( pFunction == pFind )
  550. {
  551. m_pFunctionList->AddSelectedItem( nItemID );
  552. break;
  553. }
  554. }
  555. }
  556. //-----------------------------------------------------------------------------
  557. // Add/remove functions
  558. //-----------------------------------------------------------------------------
  559. void CParticleFunctionBrowser::OnParticleChildPicked( KeyValues *pKeyValues )
  560. {
  561. CDmeParticleSystemDefinition *pParticleSystem = GetElementKeyValue<CDmeParticleSystemDefinition>( pKeyValues, "particleSystem" );
  562. if ( !pParticleSystem || ( m_FuncType != FUNCTION_CHILDREN ) )
  563. return;
  564. CDmeParticleFunction *pFunction;
  565. {
  566. CUndoScopeGuard guard( 0, NOTIFY_SETDIRTYFLAG, "Add Particle System Child", "Add Particle System Child" );
  567. pFunction = m_hParticleSystem->AddChild( pParticleSystem );
  568. }
  569. PostActionSignal( new KeyValues( "ParticleSystemModified" ) );
  570. SelectParticleFunction( pFunction );
  571. }
  572. void CParticleFunctionBrowser::OnParticleFunctionPicked( KeyValues *pKeyValues )
  573. {
  574. if ( m_FuncType == FUNCTION_CHILDREN )
  575. return;
  576. const char *pParticleFuncName = pKeyValues->GetString( "name" );
  577. CDmeParticleFunction *pFunction;
  578. {
  579. CUndoScopeGuard guard( 0, NOTIFY_SETDIRTYFLAG, "Add Particle Function", "Add Particle Function" );
  580. pFunction = m_hParticleSystem->AddOperator( m_FuncType, pParticleFuncName );
  581. }
  582. PostActionSignal( new KeyValues( "ParticleSystemModified" ) );
  583. SelectParticleFunction( pFunction );
  584. }
  585. void CParticleFunctionBrowser::OnAdd( )
  586. {
  587. if ( m_FuncType != FUNCTION_CHILDREN )
  588. {
  589. CParticleFunctionPickerFrame *pPicker = new CParticleFunctionPickerFrame( this, "Select Particle Function" );
  590. pPicker->DoModal( m_hParticleSystem, m_FuncType, NULL );
  591. }
  592. else
  593. {
  594. CParticleChildrenPickerFrame *pPicker = new CParticleChildrenPickerFrame( this, "Select Child Particle Systems", m_pQuery );
  595. pPicker->DoModal( m_hParticleSystem, NULL );
  596. }
  597. }
  598. void CParticleFunctionBrowser::OnRemove( )
  599. {
  600. int iSel = m_pFunctionList->GetSelectedItem( 0 );
  601. int nRow = m_pFunctionList->GetItemCurrentRow( iSel ) - 1;
  602. {
  603. CUndoScopeGuard guard( 0, NOTIFY_SETDIRTYFLAG, "Remove Particle Function", "Remove Particle Function" );
  604. //
  605. // Build a list of objects to delete.
  606. //
  607. CUtlVector< CDmeParticleFunction* > itemsToDelete;
  608. int nCount = m_pFunctionList->GetSelectedItemsCount();
  609. for (int i = 0; i < nCount; i++)
  610. {
  611. CDmeParticleFunction *pParticleFunction = GetSelectedFunction( i );
  612. if ( pParticleFunction )
  613. {
  614. itemsToDelete.AddToTail( pParticleFunction );
  615. }
  616. }
  617. nCount = itemsToDelete.Count();
  618. for ( int i = 0; i < nCount; ++i )
  619. {
  620. m_hParticleSystem->RemoveFunction( m_FuncType, itemsToDelete[i] );
  621. }
  622. }
  623. PostActionSignal( new KeyValues( "ParticleSystemModified" ) );
  624. // Update the list box selection.
  625. if ( m_pFunctionList->GetItemCount() > 0 )
  626. {
  627. if ( nRow < 0 )
  628. {
  629. nRow = 0;
  630. }
  631. else if ( nRow >= m_pFunctionList->GetItemCount() )
  632. {
  633. nRow = m_pFunctionList->GetItemCount() - 1;
  634. }
  635. iSel = m_pFunctionList->GetItemIDFromRow( nRow );
  636. m_pFunctionList->SetSingleSelectedItem( iSel );
  637. }
  638. else
  639. {
  640. m_pFunctionList->ClearSelectedItems();
  641. }
  642. }
  643. //-----------------------------------------------------------------------------
  644. // Rename a particle function
  645. //-----------------------------------------------------------------------------
  646. void CParticleFunctionBrowser::OnInputCompleted( KeyValues *pKeyValues )
  647. {
  648. const char *pName = pKeyValues->GetString( "text" );
  649. CDmeParticleFunction *pFunction = GetSelectedFunction();
  650. {
  651. CUndoScopeGuard guard( 0, NOTIFY_SETDIRTYFLAG, "Rename Particle Function", "Rename Particle Function" );
  652. pFunction->SetName( pName );
  653. }
  654. PostActionSignal( new KeyValues( "ParticleSystemModified" ) );
  655. }
  656. //-----------------------------------------------------------------------------
  657. // Rename a particle function
  658. //-----------------------------------------------------------------------------
  659. void CParticleFunctionBrowser::OnRename()
  660. {
  661. int nSelectedItemCount = m_pFunctionList->GetSelectedItemsCount();
  662. if ( nSelectedItemCount != 1 )
  663. return;
  664. vgui::InputDialog *pInput = new vgui::InputDialog( this, "Rename Particle Function", "Enter new name of particle function" );
  665. pInput->SetMultiline( false );
  666. pInput->DoModal( );
  667. }
  668. //-----------------------------------------------------------------------------
  669. // Called when a list panel's selection changes
  670. //-----------------------------------------------------------------------------
  671. void CParticleFunctionBrowser::RefreshParticleFunctionProperties( )
  672. {
  673. if ( IsVisible() )
  674. {
  675. CDmeParticleFunction *pFunction = GetSelectedFunction();
  676. if ( pFunction )
  677. {
  678. m_pParticleFunctionProperties->SetTypeDictionary( pFunction->GetEditorTypeDictionary() );
  679. }
  680. m_pParticleFunctionProperties->SetDmeElement( pFunction );
  681. // Notify the outside world so we can get helpers to render correctly in the preview
  682. KeyValues *pMessage = new KeyValues( "ParticleFunctionSelChanged" );
  683. SetElementKeyValue( pMessage, "function", pFunction );
  684. PostActionSignal( pMessage );
  685. }
  686. }
  687. //-----------------------------------------------------------------------------
  688. // Called when a list panel's selection changes
  689. //-----------------------------------------------------------------------------
  690. void CParticleFunctionBrowser::OnItemSelected( KeyValues *kv )
  691. {
  692. Panel *pPanel = (Panel *)kv->GetPtr( "panel", NULL );
  693. if ( pPanel == m_pFunctionList )
  694. {
  695. RefreshParticleFunctionProperties();
  696. return;
  697. }
  698. }
  699. //-----------------------------------------------------------------------------
  700. // Called when a list panel's selection changes
  701. //-----------------------------------------------------------------------------
  702. void CParticleFunctionBrowser::OnItemDeselected( KeyValues *kv )
  703. {
  704. Panel *pPanel = (Panel *)kv->GetPtr( "panel", NULL );
  705. if ( pPanel == m_pFunctionList )
  706. {
  707. RefreshParticleFunctionProperties();
  708. return;
  709. }
  710. }
  711. //-----------------------------------------------------------------------------
  712. // Called to open a context-sensitive menu for a particular menu item
  713. //-----------------------------------------------------------------------------
  714. void CParticleFunctionBrowser::OnOpenContextMenu( KeyValues *kv )
  715. {
  716. CleanupContextMenu();
  717. if ( !m_hParticleSystem.Get() )
  718. return;
  719. Panel *pPanel = (Panel *)kv->GetPtr( "panel", NULL );
  720. if ( pPanel != m_pFunctionList )
  721. return;
  722. int nSelectedItemCount = m_pFunctionList->GetSelectedItemsCount();
  723. m_hContextMenu = new vgui::Menu( this, "ActionMenu" );
  724. m_hContextMenu->AddMenuItem( "#ParticleFunctionBrowser_Add", new KeyValues( "Add" ), this );
  725. if ( nSelectedItemCount >= 1 )
  726. {
  727. m_hContextMenu->AddMenuItem( "#ParticleFunctionBrowser_Remove", new KeyValues( "Remove" ), this );
  728. }
  729. if ( nSelectedItemCount == 1 )
  730. {
  731. m_hContextMenu->AddMenuItem( "#ParticleFunctionBrowser_Rename", new KeyValues( "Rename" ), this );
  732. m_hContextMenu->AddSeparator();
  733. m_hContextMenu->AddMenuItem( "#ParticleFunctionBrowser_MoveUp", new KeyValues( "MoveUp" ), this );
  734. m_hContextMenu->AddMenuItem( "#ParticleFunctionBrowser_MoveDown", new KeyValues( "MoveDown" ), this );
  735. }
  736. vgui::Menu::PlaceContextMenu( this, m_hContextMenu.Get() );
  737. }
  738. //-----------------------------------------------------------------------------
  739. // Purpose:
  740. //-----------------------------------------------------------------------------
  741. void CParticleFunctionBrowser::OnKeyCodeTyped( vgui::KeyCode code )
  742. {
  743. if ( code == KEY_DELETE )
  744. {
  745. OnRemove();
  746. }
  747. else
  748. {
  749. BaseClass::OnKeyCodeTyped( code );
  750. }
  751. }
  752. //-----------------------------------------------------------------------------
  753. // Strings
  754. //-----------------------------------------------------------------------------
  755. //-----------------------------------------------------------------------------
  756. // Constructor
  757. //-----------------------------------------------------------------------------
  758. CParticleSystemPropertiesPanel::CParticleSystemPropertiesPanel( IParticleSystemPropertiesPanelQuery *pQuery, vgui::Panel* pParent )
  759. : BaseClass( pParent, "ParticleSystemPropertiesPanel" ), m_pQuery( pQuery )
  760. {
  761. SetKeyBoardInputEnabled( true );
  762. m_pSplitter = new vgui::Splitter( this, "Splitter", vgui::SPLITTER_MODE_VERTICAL, 1 );
  763. vgui::Panel *pSplitterLeftSide = m_pSplitter->GetChild( 0 );
  764. vgui::Panel *pSplitterRightSide = m_pSplitter->GetChild( 1 );
  765. m_pFunctionBrowserArea = new vgui::EditablePanel( pSplitterLeftSide, "FunctionBrowserArea" );
  766. m_pFunctionTypeCombo = new vgui::ComboBox( pSplitterLeftSide, "FunctionTypeCombo", PARTICLE_FUNCTION_COUNT+1, false );
  767. m_pFunctionTypeCombo->AddItem( "Properties", new KeyValues( "choice", "index", -1 ) );
  768. m_pFunctionTypeCombo->AddActionSignalTarget( this );
  769. m_pParticleFunctionProperties = new CDmeElementPanel( pSplitterRightSide, "FunctionProperties" );
  770. m_pParticleFunctionProperties->SetAutoResize( vgui::Panel::PIN_TOPLEFT, vgui::Panel::AUTORESIZE_DOWNANDRIGHT, 6, 6, -6, -6 );
  771. m_pParticleFunctionProperties->AddActionSignalTarget( this );
  772. for ( int i = 0; i < PARTICLE_FUNCTION_COUNT; ++i )
  773. {
  774. const char *pTypeName = GetParticleFunctionTypeName( (ParticleFunctionType_t)i );
  775. m_pFunctionTypeCombo->AddItem( pTypeName, new KeyValues( "choice", "index", i ) );
  776. m_pParticleFunctionBrowser[i] = new CParticleFunctionBrowser( m_pFunctionBrowserArea, "FunctionBrowser", (ParticleFunctionType_t)i, m_pQuery );
  777. m_pParticleFunctionBrowser[i]->SetParticleFunctionProperties( m_pParticleFunctionProperties );
  778. m_pParticleFunctionBrowser[i]->AddActionSignalTarget( this );
  779. }
  780. m_pFunctionTypeCombo->ActivateItemByRow( 0 );
  781. LoadControlSettings( "resource/particlesystempropertiespanel.res" );
  782. }
  783. //-----------------------------------------------------------------------------
  784. // Sets the particle system to look at
  785. //-----------------------------------------------------------------------------
  786. void CParticleSystemPropertiesPanel::SetParticleSystem( CDmeParticleSystemDefinition *pParticleSystem )
  787. {
  788. m_hParticleSystem = pParticleSystem;
  789. for ( int i = 0; i < PARTICLE_FUNCTION_COUNT; ++i )
  790. {
  791. m_pParticleFunctionBrowser[i]->SetParticleSystem( pParticleSystem );
  792. }
  793. KeyValues *pKeyValues = m_pFunctionTypeCombo->GetActiveItemUserData();
  794. int nPage = pKeyValues->GetInt( "index" );
  795. if ( nPage < 0 )
  796. {
  797. if ( m_hParticleSystem.Get() )
  798. {
  799. m_pParticleFunctionProperties->SetTypeDictionary( m_hParticleSystem->GetEditorTypeDictionary() );
  800. }
  801. m_pParticleFunctionProperties->SetDmeElement( m_hParticleSystem );
  802. }
  803. }
  804. //-----------------------------------------------------------------------------
  805. // Called when something changes in the dmeelement panel
  806. //-----------------------------------------------------------------------------
  807. void CParticleSystemPropertiesPanel::OnDmeElementChanged( KeyValues *pKeyValues )
  808. {
  809. int nNotifyFlags = pKeyValues->GetInt( "notifyFlags" );
  810. OnParticleSystemModified();
  811. if ( nNotifyFlags & ( NOTIFY_CHANGE_TOPOLOGICAL | NOTIFY_CHANGE_ATTRIBUTE_ARRAY_SIZE ) )
  812. {
  813. for ( int i = 0; i < PARTICLE_FUNCTION_COUNT; ++i )
  814. {
  815. m_pParticleFunctionBrowser[i]->RefreshParticleFunctionList();
  816. }
  817. }
  818. PostActionSignal( new KeyValues( "ParticleSystemModified" ) );
  819. }
  820. void CParticleSystemPropertiesPanel::OnParticleSystemModifiedInternal()
  821. {
  822. OnParticleSystemModified();
  823. Refresh( false );
  824. PostActionSignal( new KeyValues( "ParticleSystemModified" ) );
  825. }
  826. void CParticleSystemPropertiesPanel::OnParticleFunctionSelChanged( KeyValues *pParams )
  827. {
  828. // Notify the outside world so we can get helpers to render correctly in the preview
  829. CDmeParticleFunction *pFunction = GetElementKeyValue<CDmeParticleFunction>( pParams, "function" );
  830. KeyValues *pMessage = new KeyValues( "ParticleFunctionSelChanged" );
  831. SetElementKeyValue( pMessage, "function", pFunction );
  832. PostActionSignal( pMessage );
  833. }
  834. //-----------------------------------------------------------------------------
  835. // Refreshes display
  836. //-----------------------------------------------------------------------------
  837. void CParticleSystemPropertiesPanel::Refresh( bool bValuesOnly )
  838. {
  839. for ( int i = 0; i < PARTICLE_FUNCTION_COUNT; ++i )
  840. {
  841. m_pParticleFunctionBrowser[i]->RefreshParticleFunctionList();
  842. }
  843. m_pParticleFunctionProperties->Refresh( bValuesOnly ? CElementPropertiesTreeInternal::REFRESH_VALUES_ONLY :
  844. CElementPropertiesTreeInternal::REFRESH_TREE_VIEW );
  845. }
  846. //-----------------------------------------------------------------------------
  847. // Purpose: Called when a page is shown
  848. //-----------------------------------------------------------------------------
  849. void CParticleSystemPropertiesPanel::OnTextChanged( )
  850. {
  851. for ( int i = 0; i < PARTICLE_FUNCTION_COUNT; ++i )
  852. {
  853. m_pParticleFunctionBrowser[i]->SetVisible( false );
  854. }
  855. KeyValues *pKeyValues = m_pFunctionTypeCombo->GetActiveItemUserData();
  856. int nPage = pKeyValues->GetInt( "index" );
  857. if ( nPage < 0 )
  858. {
  859. if ( m_hParticleSystem.Get() )
  860. {
  861. m_pParticleFunctionProperties->SetTypeDictionary( m_hParticleSystem->GetEditorTypeDictionary() );
  862. }
  863. m_pParticleFunctionProperties->SetDmeElement( m_hParticleSystem );
  864. return;
  865. }
  866. m_pParticleFunctionBrowser[nPage]->SetVisible( true );
  867. m_pParticleFunctionBrowser[nPage]->SelectDefaultFunction();
  868. m_pParticleFunctionBrowser[nPage]->RefreshParticleFunctionProperties();
  869. }
  870. //-----------------------------------------------------------------------------
  871. // A little panel used as a DmePanel for particle systems
  872. //-----------------------------------------------------------------------------
  873. class CParticleSystemDmePanel : public vgui::EditablePanel
  874. {
  875. DECLARE_CLASS_SIMPLE( CParticleSystemDmePanel, vgui::EditablePanel );
  876. public:
  877. // constructor, destructor
  878. CParticleSystemDmePanel( vgui::Panel *pParent, const char *pName );
  879. virtual ~CParticleSystemDmePanel();
  880. // Set the material to draw
  881. void SetDmeElement( CDmeParticleSystemDefinition *pDef );
  882. private:
  883. MESSAGE_FUNC_INT( OnElementChangedExternally, "ElementChangedExternally", valuesOnly );
  884. MESSAGE_FUNC( OnParticleSystemModified, "ParticleSystemModified" );
  885. MESSAGE_FUNC_PARAMS( OnParticleFunctionSelChanged, "ParticleFunctionSelChanged", params );
  886. vgui::Splitter *m_Splitter;
  887. CParticleSystemPropertiesPanel *m_pProperties;
  888. CParticleSystemPreviewPanel *m_pPreview;
  889. };
  890. //-----------------------------------------------------------------------------
  891. // Dme panel connection
  892. //-----------------------------------------------------------------------------
  893. IMPLEMENT_DMEPANEL_FACTORY( CParticleSystemDmePanel, DmeParticleSystemDefinition, "DmeParticleSystemDefinitionEditor", "Particle System Editor", true );
  894. //-----------------------------------------------------------------------------
  895. // constructor, destructor
  896. //-----------------------------------------------------------------------------
  897. CParticleSystemDmePanel::CParticleSystemDmePanel( vgui::Panel *pParent, const char *pName ) :
  898. BaseClass( pParent, pName )
  899. {
  900. m_Splitter = new vgui::Splitter( this, "Splitter", SPLITTER_MODE_HORIZONTAL, 1 );
  901. vgui::Panel *pSplitterTopSide = m_Splitter->GetChild( 0 );
  902. vgui::Panel *pSplitterBottomSide = m_Splitter->GetChild( 1 );
  903. m_Splitter->SetAutoResize( PIN_TOPLEFT, AUTORESIZE_DOWNANDRIGHT, 0, 0, 0, 0 );
  904. m_pProperties = new CParticleSystemPropertiesPanel( NULL, pSplitterBottomSide );
  905. m_pProperties->AddActionSignalTarget( this );
  906. m_pProperties->SetAutoResize( PIN_TOPLEFT, AUTORESIZE_DOWNANDRIGHT, 0, 0, 0, 0 );
  907. m_pPreview = new CParticleSystemPreviewPanel( pSplitterTopSide, "Preview" );
  908. m_pPreview->SetAutoResize( PIN_TOPLEFT, AUTORESIZE_DOWNANDRIGHT, 0, 0, 0, 0 );
  909. }
  910. CParticleSystemDmePanel::~CParticleSystemDmePanel()
  911. {
  912. }
  913. //-----------------------------------------------------------------------------
  914. // Layout
  915. //-----------------------------------------------------------------------------
  916. void CParticleSystemDmePanel::SetDmeElement( CDmeParticleSystemDefinition *pDef )
  917. {
  918. m_pProperties->SetParticleSystem( pDef );
  919. m_pPreview->SetParticleSystem( pDef );
  920. }
  921. //-----------------------------------------------------------------------------
  922. // Particle system modified externally to the editor
  923. //-----------------------------------------------------------------------------
  924. void CParticleSystemDmePanel::OnElementChangedExternally( int valuesOnly )
  925. {
  926. m_pProperties->Refresh( valuesOnly != 0 );
  927. }
  928. //-----------------------------------------------------------------------------
  929. // Called when the selected particle function changes
  930. //-----------------------------------------------------------------------------
  931. void CParticleSystemDmePanel::OnParticleFunctionSelChanged( KeyValues *pParams )
  932. {
  933. CDmeParticleFunction *pFunction = GetElementKeyValue<CDmeParticleFunction>( pParams, "function" );
  934. m_pPreview->SetParticleFunction( pFunction );
  935. }
  936. //-----------------------------------------------------------------------------
  937. // Communicate to the owning DmePanel
  938. //-----------------------------------------------------------------------------
  939. void CParticleSystemDmePanel::OnParticleSystemModified()
  940. {
  941. PostActionSignal( new KeyValues( "DmeElementChanged" ) );
  942. }