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.

485 lines
15 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "matsys_controls/sequencepicker.h"
  7. #include "tier1/utldict.h"
  8. #include "tier1/KeyValues.h"
  9. #include "studio.h"
  10. #include "vgui/IInput.h"
  11. #include "vgui/ISurface.h"
  12. #include "vgui_controls/Splitter.h"
  13. #include "vgui_controls/PropertyPage.h"
  14. #include "vgui_controls/PropertySheet.h"
  15. #include "vgui_controls/ListPanel.h"
  16. #include "vgui_controls/Button.h"
  17. #include "matsys_controls/matsyscontrols.h"
  18. // memdbgon must be the last include file in a .cpp file!!!
  19. #include "tier0/memdbgon.h"
  20. using namespace vgui;
  21. //-----------------------------------------------------------------------------
  22. //
  23. // Sequence Picker
  24. //
  25. //-----------------------------------------------------------------------------
  26. //-----------------------------------------------------------------------------
  27. // Sort by sequence name
  28. //-----------------------------------------------------------------------------
  29. static int __cdecl SequenceSortFunc( vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
  30. {
  31. const char *string1 = item1.kv->GetString("sequence");
  32. const char *string2 = item2.kv->GetString("sequence");
  33. return stricmp( string1, string2 );
  34. }
  35. static int __cdecl ActivitySortFunc( vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
  36. {
  37. const char *string1 = item1.kv->GetString("activity");
  38. const char *string2 = item2.kv->GetString("activity");
  39. return stricmp( string1, string2 );
  40. }
  41. //-----------------------------------------------------------------------------
  42. // Purpose: Constructor
  43. //-----------------------------------------------------------------------------
  44. CSequencePicker::CSequencePicker( vgui::Panel *pParent, int nFlags ) : BaseClass( pParent, "SequencePicker" )
  45. {
  46. m_hSelectedMDL = MDLHANDLE_INVALID;
  47. // property sheet - revisions, changes, etc.
  48. m_pPreviewSplitter = new Splitter( this, "PreviewSplitter", SPLITTER_MODE_HORIZONTAL, 1 );
  49. vgui::Panel *pSplitterTopSide = m_pPreviewSplitter->GetChild( 0 );
  50. vgui::Panel *pSplitterBottomSide = m_pPreviewSplitter->GetChild( 1 );
  51. // MDL preview
  52. m_pMDLPreview = new CMDLPanel( pSplitterTopSide, "MDLPreview" );
  53. SetSkipChildDuringPainting( m_pMDLPreview );
  54. m_pViewsSheet = new vgui::PropertySheet( pSplitterBottomSide, "ViewsSheet" );
  55. m_pViewsSheet->AddActionSignalTarget( this );
  56. // sequences
  57. m_pSequencesPage = NULL;
  58. m_pSequencesList = NULL;
  59. if ( nFlags & PICK_SEQUENCES )
  60. {
  61. m_pSequencesPage = new PropertyPage( m_pViewsSheet, "SequencesPage" );
  62. m_pViewsSheet->AddPage( m_pSequencesPage, "Sequences" );
  63. m_pSequencesList = new ListPanel( m_pSequencesPage, "SequencesList" );
  64. m_pSequencesList->AddColumnHeader( 0, "sequence", "sequence", 52, 0 );
  65. m_pSequencesList->AddActionSignalTarget( this );
  66. m_pSequencesList->SetSelectIndividualCells( true );
  67. m_pSequencesList->SetEmptyListText(".MDL file contains no activities");
  68. m_pSequencesList->SetDragEnabled( true );
  69. m_pSequencesList->SetAutoResize( Panel::PIN_TOPLEFT, Panel::AUTORESIZE_DOWNANDRIGHT, 0, 0, 0, 0 );
  70. m_pSequencesList->SetSortFunc( 0, SequenceSortFunc );
  71. m_pSequencesList->SetSortColumn( 0 );
  72. }
  73. // Activities
  74. m_pActivitiesPage = NULL;
  75. m_pActivitiesList = NULL;
  76. if ( nFlags & PICK_ACTIVITIES )
  77. {
  78. m_pActivitiesPage = new PropertyPage( m_pViewsSheet, "ActivitiesPage" );
  79. m_pViewsSheet->AddPage( m_pActivitiesPage, "Activities" );
  80. m_pActivitiesList = new ListPanel( m_pActivitiesPage, "ActivitiesList" );
  81. m_pActivitiesList->AddColumnHeader( 0, "activity", "activity", 52, 0 );
  82. m_pActivitiesList->AddActionSignalTarget( this );
  83. m_pActivitiesList->SetSelectIndividualCells( true );
  84. m_pActivitiesList->SetEmptyListText( ".MDL file contains no activities" );
  85. m_pActivitiesList->SetDragEnabled( true );
  86. m_pActivitiesList->SetAutoResize( Panel::PIN_TOPLEFT, Panel::AUTORESIZE_DOWNANDRIGHT, 0, 0, 0, 0 );
  87. m_pActivitiesList->SetSortFunc( 0, ActivitySortFunc );
  88. m_pActivitiesList->SetSortColumn( 0 );
  89. }
  90. // Load layout settings; has to happen before pinning occurs in code
  91. LoadControlSettingsAndUserConfig( "resource/sequencepicker.res" );
  92. SETUP_PANEL( this );
  93. }
  94. //-----------------------------------------------------------------------------
  95. // Purpose: Destructor
  96. //-----------------------------------------------------------------------------
  97. CSequencePicker::~CSequencePicker()
  98. {
  99. }
  100. //-----------------------------------------------------------------------------
  101. // Performs layout
  102. //-----------------------------------------------------------------------------
  103. void CSequencePicker::PerformLayout()
  104. {
  105. // NOTE: This call should cause auto-resize to occur
  106. // which should fix up the width of the panels
  107. BaseClass::PerformLayout();
  108. int w, h;
  109. GetSize( w, h );
  110. // Layout the mdl splitter
  111. m_pPreviewSplitter->SetBounds( 0, 0, w, h );
  112. }
  113. //-----------------------------------------------------------------------------
  114. // Purpose: rebuilds the list of activities + sequences
  115. //-----------------------------------------------------------------------------
  116. void CSequencePicker::RefreshActivitiesAndSequencesList()
  117. {
  118. if ( m_pActivitiesList )
  119. {
  120. m_pActivitiesList->RemoveAll();
  121. }
  122. if ( m_pSequencesList )
  123. {
  124. m_pSequencesList->RemoveAll();
  125. }
  126. m_pMDLPreview->SetSequence( 0 );
  127. if ( m_hSelectedMDL == MDLHANDLE_INVALID )
  128. return;
  129. studiohdr_t *hdr = vgui::MDLCache()->GetStudioHdr( m_hSelectedMDL );
  130. CUtlDict<int, unsigned short> activityNames( true, 0, hdr->GetNumSeq() );
  131. for (int j = 0; j < hdr->GetNumSeq(); j++)
  132. {
  133. if ( /*g_viewerSettings.showHidden ||*/ !(hdr->pSeqdesc(j).flags & STUDIO_HIDDEN))
  134. {
  135. const char *pActivityName = hdr->pSeqdesc(j).pszActivityName();
  136. if ( m_pActivitiesList && pActivityName && pActivityName[0] )
  137. {
  138. // Multiple sequences can have the same activity name; only add unique activity names
  139. if ( activityNames.Find( pActivityName ) == activityNames.InvalidIndex() )
  140. {
  141. KeyValues *pkv = new KeyValues("node", "activity", pActivityName );
  142. int nItemID = m_pActivitiesList->AddItem( pkv, 0, false, false );
  143. KeyValues *pDrag = new KeyValues( "drag", "text", pActivityName );
  144. pDrag->SetString( "texttype", "activityName" );
  145. pDrag->SetString( "mdl", vgui::MDLCache()->GetModelName( m_hSelectedMDL ) );
  146. m_pActivitiesList->SetItemDragData( nItemID, pDrag );
  147. activityNames.Insert( pActivityName, j );
  148. }
  149. }
  150. const char *pSequenceName = hdr->pSeqdesc(j).pszLabel();
  151. if ( m_pSequencesList && pSequenceName && pSequenceName[0] )
  152. {
  153. KeyValues *pkv = new KeyValues("node", "sequence", pSequenceName);
  154. int nItemID = m_pSequencesList->AddItem( pkv, 0, false, false );
  155. KeyValues *pDrag = new KeyValues( "drag", "text", pSequenceName );
  156. pDrag->SetString( "texttype", "sequenceName" );
  157. pDrag->SetString( "mdl", vgui::MDLCache()->GetModelName( m_hSelectedMDL ) );
  158. m_pSequencesList->SetItemDragData( nItemID, pDrag );
  159. }
  160. }
  161. }
  162. if ( m_pSequencesList )
  163. {
  164. m_pSequencesList->SortList();
  165. }
  166. if ( m_pActivitiesList )
  167. {
  168. m_pActivitiesList->SortList();
  169. }
  170. }
  171. /*
  172. //-----------------------------------------------------------------------------
  173. // Purpose: Selects an sequence based on an activity
  174. //-----------------------------------------------------------------------------
  175. int SelectWeightedSequence( studiohdr_t *pstudiohdr, int activity, int curSequence )
  176. {
  177. if (! pstudiohdr)
  178. return 0;
  179. VerifySequenceIndex( pstudiohdr );
  180. int weighttotal = 0;
  181. int seq = ACTIVITY_NOT_AVAILABLE;
  182. int weight = 0;
  183. for (int i = 0; i < pstudiohdr->GetNumSeq(); i++)
  184. {
  185. int curActivity = GetSequenceActivity( pstudiohdr, i, &weight );
  186. if (curActivity == activity)
  187. {
  188. if ( curSequence == i && weight < 0 )
  189. {
  190. seq = i;
  191. break;
  192. }
  193. weighttotal += iabs(weight);
  194. int randomValue;
  195. if ( IsInPrediction() )
  196. randomValue = SharedRandomInt( "SelectWeightedSequence", 0, weighttotal - 1, i );
  197. else
  198. randomValue = RandomInt( 0, weighttotal - 1 );
  199. if (!weighttotal || randomValue < iabs(weight))
  200. seq = i;
  201. }
  202. }
  203. return seq;
  204. }
  205. */
  206. //-----------------------------------------------------------------------------
  207. // Gets the selected activity/sequence
  208. //-----------------------------------------------------------------------------
  209. CSequencePicker::PickType_t CSequencePicker::GetSelectedSequenceType( )
  210. {
  211. if ( m_pSequencesPage && ( m_pViewsSheet->GetActivePage() == m_pSequencesPage ) )
  212. return PICK_SEQUENCES;
  213. if ( m_pActivitiesPage && ( m_pViewsSheet->GetActivePage() == m_pActivitiesPage ) )
  214. return PICK_ACTIVITIES;
  215. return PICK_NONE;
  216. }
  217. const char *CSequencePicker::GetSelectedSequenceName( )
  218. {
  219. if ( m_pSequencesPage && ( m_pViewsSheet->GetActivePage() == m_pSequencesPage ) )
  220. {
  221. int nIndex = m_pSequencesList->GetSelectedItem( 0 );
  222. if ( nIndex >= 0 )
  223. {
  224. KeyValues *pkv = m_pSequencesList->GetItem( nIndex );
  225. return pkv->GetString( "sequence", NULL );
  226. }
  227. return NULL;
  228. }
  229. if ( m_pActivitiesPage && ( m_pViewsSheet->GetActivePage() == m_pActivitiesPage ) )
  230. {
  231. int nIndex = m_pActivitiesList->GetSelectedItem( 0 );
  232. if ( nIndex >= 0 )
  233. {
  234. KeyValues *pkv = m_pActivitiesList->GetItem( nIndex );
  235. return pkv->GetString( "activity", NULL );
  236. }
  237. return NULL;
  238. }
  239. return NULL;
  240. }
  241. //-----------------------------------------------------------------------------
  242. // Plays the selected activity
  243. //-----------------------------------------------------------------------------
  244. void CSequencePicker::PlayActivity( const char *pActivityName )
  245. {
  246. studiohdr_t *pstudiohdr = vgui::MDLCache()->GetStudioHdr( m_hSelectedMDL );
  247. for ( int i = 0; i < pstudiohdr->GetNumSeq(); i++ )
  248. {
  249. mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( i );
  250. if ( stricmp( seqdesc.pszActivityName(), pActivityName ) == 0 )
  251. {
  252. // FIXME: Add weighted sequence selection logic?
  253. m_pMDLPreview->SetSequence( i );
  254. break;
  255. }
  256. }
  257. }
  258. //-----------------------------------------------------------------------------
  259. // Plays the selected sequence
  260. //-----------------------------------------------------------------------------
  261. void CSequencePicker::PlaySequence( const char *pSequenceName )
  262. {
  263. studiohdr_t *pstudiohdr = vgui::MDLCache()->GetStudioHdr( m_hSelectedMDL );
  264. for (int i = 0; i < pstudiohdr->GetNumSeq(); i++)
  265. {
  266. mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( i );
  267. if ( !Q_stricmp( seqdesc.pszLabel(), pSequenceName ) )
  268. {
  269. m_pMDLPreview->SetSequence( i );
  270. break;
  271. }
  272. }
  273. }
  274. //-----------------------------------------------------------------------------
  275. // Purpose: Called when a page is shown
  276. //-----------------------------------------------------------------------------
  277. void CSequencePicker::OnPageChanged( )
  278. {
  279. if ( m_pSequencesPage && ( m_pViewsSheet->GetActivePage() == m_pSequencesPage ) )
  280. {
  281. const char *pSequenceName = GetSelectedSequenceName();
  282. if ( pSequenceName )
  283. {
  284. PlaySequence( pSequenceName );
  285. PostActionSignal( new KeyValues( "SequencePreviewChanged", "sequence", pSequenceName ) );
  286. }
  287. return;
  288. }
  289. if ( m_pActivitiesPage && ( m_pViewsSheet->GetActivePage() == m_pActivitiesPage ) )
  290. {
  291. const char *pActivityName = GetSelectedSequenceName();
  292. if ( pActivityName )
  293. {
  294. PlayActivity( pActivityName );
  295. PostActionSignal( new KeyValues( "SequencePreviewChanged", "activity", pActivityName ) );
  296. }
  297. return;
  298. }
  299. }
  300. //-----------------------------------------------------------------------------
  301. // Purpose: refreshes dialog on text changing
  302. //-----------------------------------------------------------------------------
  303. void CSequencePicker::OnItemSelected( KeyValues *kv )
  304. {
  305. Panel *pPanel = (Panel *)kv->GetPtr("panel", NULL);
  306. if ( m_pSequencesList && (pPanel == m_pSequencesList ) )
  307. {
  308. const char *pSequenceName = GetSelectedSequenceName();
  309. if ( pSequenceName )
  310. {
  311. PlaySequence( pSequenceName );
  312. PostActionSignal( new KeyValues( "SequencePreviewChanged", "sequence", pSequenceName ) );
  313. }
  314. return;
  315. }
  316. if ( m_pActivitiesList && ( pPanel == m_pActivitiesList ) )
  317. {
  318. const char *pActivityName = GetSelectedSequenceName();
  319. if ( pActivityName )
  320. {
  321. PlayActivity( pActivityName );
  322. PostActionSignal( new KeyValues( "SequencePreviewChanged", "activity", pActivityName ) );
  323. }
  324. return;
  325. }
  326. }
  327. //-----------------------------------------------------------------------------
  328. // Sets the MDL to select sequences in
  329. //-----------------------------------------------------------------------------
  330. void CSequencePicker::SetMDL( const char *pMDLName )
  331. {
  332. m_hSelectedMDL = pMDLName ? vgui::MDLCache()->FindMDL( pMDLName ) : MDLHANDLE_INVALID;
  333. if ( vgui::MDLCache()->IsErrorModel( m_hSelectedMDL ) )
  334. {
  335. m_hSelectedMDL = MDLHANDLE_INVALID;
  336. }
  337. m_pMDLPreview->SetMDL( m_hSelectedMDL );
  338. m_pMDLPreview->LookAtMDL();
  339. RefreshActivitiesAndSequencesList();
  340. }
  341. //-----------------------------------------------------------------------------
  342. //
  343. // Purpose: Modal picker frame
  344. //
  345. //-----------------------------------------------------------------------------
  346. CSequencePickerFrame::CSequencePickerFrame( vgui::Panel *pParent, int nFlags ) : BaseClass( pParent, "SequencePickerFrame" )
  347. {
  348. SetDeleteSelfOnClose( true );
  349. m_pPicker = new CSequencePicker( this, nFlags );
  350. m_pPicker->AddActionSignalTarget( this );
  351. m_pOpenButton = new Button( this, "OpenButton", "#FileOpenDialog_Open", this, "Open" );
  352. m_pCancelButton = new Button( this, "CancelButton", "#FileOpenDialog_Cancel", this, "Cancel" );
  353. SetBlockDragChaining( true );
  354. LoadControlSettingsAndUserConfig( "resource/sequencepickerframe.res" );
  355. m_pOpenButton->SetEnabled( false );
  356. }
  357. //-----------------------------------------------------------------------------
  358. // Purpose: Activate the dialog
  359. //-----------------------------------------------------------------------------
  360. void CSequencePickerFrame::DoModal( const char *pMDLName )
  361. {
  362. m_pPicker->SetMDL( pMDLName );
  363. BaseClass::DoModal();
  364. }
  365. //-----------------------------------------------------------------------------
  366. // On mdl preview changed
  367. //-----------------------------------------------------------------------------
  368. void CSequencePickerFrame::OnSequencePreviewChanged( KeyValues *pKeyValues )
  369. {
  370. const char *pSequence = pKeyValues->GetString( "sequence", NULL );
  371. const char *pActivity = pKeyValues->GetString( "activity", NULL );
  372. m_pOpenButton->SetEnabled( pSequence || pActivity );
  373. }
  374. //-----------------------------------------------------------------------------
  375. // On command
  376. //-----------------------------------------------------------------------------
  377. void CSequencePickerFrame::OnCommand( const char *pCommand )
  378. {
  379. if ( !Q_stricmp( pCommand, "Open" ) )
  380. {
  381. CSequencePicker::PickType_t type = m_pPicker->GetSelectedSequenceType( );
  382. if (( type == CSequencePicker::PICK_SEQUENCES ) || ( type == CSequencePicker::PICK_ACTIVITIES ))
  383. {
  384. const char *pSequenceName = m_pPicker->GetSelectedSequenceName();
  385. if ( pSequenceName )
  386. {
  387. if ( type == CSequencePicker::PICK_SEQUENCES )
  388. {
  389. PostActionSignal( new KeyValues("SequenceSelected", "sequence", pSequenceName ) );
  390. }
  391. else
  392. {
  393. PostActionSignal( new KeyValues("SequenceSelected", "activity", pSequenceName ) );
  394. }
  395. CloseModal();
  396. return;
  397. }
  398. }
  399. return;
  400. }
  401. if ( !Q_stricmp( pCommand, "Cancel" ) )
  402. {
  403. CloseModal();
  404. return;
  405. }
  406. BaseClass::OnCommand( pCommand );
  407. }