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.

539 lines
16 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "matsys_controls/mdlsequencepicker.h"
  7. #include "tier1/KeyValues.h"
  8. #include "tier1/utldict.h"
  9. #include "datacache/imdlcache.h"
  10. #include "filesystem.h"
  11. #include "studio.h"
  12. #include "vgui/IVGui.h"
  13. #include "vgui/Cursor.h"
  14. #include "vgui/ISurface.h"
  15. #include "vgui_controls/Splitter.h"
  16. #include "vgui_controls/ComboBox.h"
  17. #include "vgui_controls/PropertySheet.h"
  18. #include "vgui_controls/PropertyPage.h"
  19. #include "vgui_controls/ToolWindow.h"
  20. #include "vgui_controls/Button.h"
  21. #include "matsys_controls/gamefiletreeview.h"
  22. #include "matsys_controls/matsyscontrols.h"
  23. // memdbgon must be the last include file in a .cpp file!!!
  24. #include "tier0/memdbgon.h"
  25. using namespace vgui;
  26. //-----------------------------------------------------------------------------
  27. //
  28. // MDL Sequence Picker
  29. //
  30. //-----------------------------------------------------------------------------
  31. //-----------------------------------------------------------------------------
  32. // Purpose: Constructor
  33. //-----------------------------------------------------------------------------
  34. CMDLSequencePicker::CMDLSequencePicker( vgui::Panel *pParent ) : BaseClass(pParent, "MDLSequencePicker"), m_Images(false)
  35. {
  36. vgui::ivgui()->AddTickSignal( GetVPanel() );
  37. m_hSelectedMDL = MDLHANDLE_INVALID;
  38. // Horizontal splitter for mdls
  39. m_pMDLSplitter = new Splitter( this, "MDLSplitter", SPLITTER_MODE_VERTICAL, 1 );
  40. vgui::Panel *pSplitterLeftSide = m_pMDLSplitter->GetChild( 0 );
  41. vgui::Panel *pSplitterRightSide = m_pMDLSplitter->GetChild( 1 );
  42. // filter selection
  43. m_pFilterList = new ComboBox( pSplitterLeftSide, "FilterList", 16, true );
  44. m_pFilterList->AddActionSignalTarget( this );
  45. // file browser tree controls
  46. m_pFileTree = new CGameFileTreeView( pSplitterLeftSide, "FileTree", "All .MDLs", "models", "mdl" );
  47. // build our list of images
  48. m_Images.AddImage( scheme()->GetImage( "resource/icon_folder", false ) );
  49. m_Images.AddImage( scheme()->GetImage( "resource/icon_folder_selected", false ) );
  50. m_Images.AddImage( scheme()->GetImage( "resource/icon_file", false ) );
  51. m_pFileTree->SetImageList( &m_Images, false );
  52. m_pFileTree->AddActionSignalTarget( this );
  53. // property sheet - revisions, changes, etc.
  54. m_pSequenceSplitter = new Splitter( pSplitterRightSide, "SequenceSplitter", SPLITTER_MODE_HORIZONTAL, 1 );
  55. vgui::Panel *pSplitterTopSide = m_pSequenceSplitter->GetChild( 0 );
  56. vgui::Panel *pSplitterBottomSide = m_pSequenceSplitter->GetChild( 1 );
  57. // MDL preview
  58. m_pMDLPreview = new CMDLPanel( pSplitterTopSide, "MDLPreview" );
  59. SetSkipChildDuringPainting( m_pMDLPreview );
  60. m_pViewsSheet = new vgui::PropertySheet( pSplitterBottomSide, "ViewsSheet" );
  61. m_pViewsSheet->AddActionSignalTarget( this );
  62. // sequences
  63. m_pSequencesPage = new PropertyPage( m_pViewsSheet, "SequencesPage" );
  64. m_pViewsSheet->AddPage( m_pSequencesPage, "Sequences" );
  65. m_pSequencesList = new ListPanel( m_pSequencesPage, "SequencesList" );
  66. m_pSequencesList->AddColumnHeader( 0, "sequence", "sequence", 52, 0 );
  67. m_pSequencesList->AddActionSignalTarget( this );
  68. m_pSequencesList->SetSelectIndividualCells( true );
  69. m_pSequencesList->SetEmptyListText("No .MDL file currently selected.");
  70. m_pSequencesList->SetDragEnabled( true );
  71. m_pSequencesList->SetAutoResize( Panel::PIN_TOPLEFT, Panel::AUTORESIZE_DOWNANDRIGHT, 0, 0, 0, 0 );
  72. // Activities
  73. m_pActivitiesPage = new PropertyPage( m_pViewsSheet, "ActivitiesPage" );
  74. m_pViewsSheet->AddPage( m_pActivitiesPage, "Activities" );
  75. m_pActivitiesList = new ListPanel( m_pActivitiesPage, "ActivitiesList" );
  76. m_pActivitiesList->AddColumnHeader( 0, "activity", "activity", 52, 0 );
  77. m_pActivitiesList->AddActionSignalTarget( this );
  78. m_pActivitiesList->SetSelectIndividualCells( true );
  79. m_pActivitiesList->SetEmptyListText( "No .MDL file currently selected." );
  80. m_pActivitiesList->SetDragEnabled( true );
  81. m_pActivitiesList->SetAutoResize( Panel::PIN_TOPLEFT, Panel::AUTORESIZE_DOWNANDRIGHT, 0, 0, 0, 0 );
  82. // Load layout settings; has to happen before pinning occurs in code
  83. LoadControlSettingsAndUserConfig( "resource/mdlsequencepicker.res" );
  84. }
  85. //-----------------------------------------------------------------------------
  86. // Purpose: Destructor
  87. //-----------------------------------------------------------------------------
  88. CMDLSequencePicker::~CMDLSequencePicker()
  89. {
  90. }
  91. //-----------------------------------------------------------------------------
  92. // Purpose: This is a bit of a hack to make sure that the ToolWindow containing this picker punches
  93. // a hold for the rendering viewport, too
  94. // Input : -
  95. //-----------------------------------------------------------------------------
  96. void CMDLSequencePicker::OnTick()
  97. {
  98. BaseClass::OnTick();
  99. if ( GetParent() )
  100. {
  101. ToolWindow *tw = dynamic_cast< ToolWindow * >( GetParent()->GetParent() );
  102. if ( tw )
  103. {
  104. tw->SetSkipChildDuringPainting( IsVisible() ? m_pMDLPreview : NULL );
  105. }
  106. }
  107. }
  108. //-----------------------------------------------------------------------------
  109. // Purpose: stops app on close
  110. //-----------------------------------------------------------------------------
  111. void CMDLSequencePicker::OnClose()
  112. {
  113. BaseClass::OnClose();
  114. }
  115. //-----------------------------------------------------------------------------
  116. // Purpose: called to open
  117. //-----------------------------------------------------------------------------
  118. void CMDLSequencePicker::Activate()
  119. {
  120. RefreshFileList();
  121. RefreshActivitiesAndSequencesList();
  122. }
  123. //-----------------------------------------------------------------------------
  124. // Performs layout
  125. //-----------------------------------------------------------------------------
  126. void CMDLSequencePicker::PerformLayout()
  127. {
  128. // NOTE: This call should cause auto-resize to occur
  129. // which should fix up the width of the panels
  130. BaseClass::PerformLayout();
  131. int w, h;
  132. GetSize( w, h );
  133. // Layout the mdl splitter
  134. m_pMDLSplitter->SetBounds( 0, 0, w, h );
  135. }
  136. //-----------------------------------------------------------------------------
  137. // Purpose: Refreshes the active file list
  138. //-----------------------------------------------------------------------------
  139. void CMDLSequencePicker::RefreshFileList()
  140. {
  141. m_pFileTree->RefreshFileList();
  142. }
  143. //-----------------------------------------------------------------------------
  144. // Purpose: rebuilds the list of activities
  145. //-----------------------------------------------------------------------------
  146. void CMDLSequencePicker::RefreshActivitiesAndSequencesList()
  147. {
  148. m_pActivitiesList->RemoveAll();
  149. m_pSequencesList->RemoveAll();
  150. m_pMDLPreview->SetSequence( 0 );
  151. if ( m_hSelectedMDL == MDLHANDLE_INVALID )
  152. {
  153. m_pActivitiesList->SetEmptyListText("No .MDL file currently selected");
  154. m_pSequencesList->SetEmptyListText("No .MDL file currently selected");
  155. return;
  156. }
  157. m_pActivitiesList->SetEmptyListText(".MDL file contains no activities");
  158. m_pSequencesList->SetEmptyListText(".MDL file contains no sequences");
  159. studiohdr_t *hdr = vgui::MDLCache()->GetStudioHdr( m_hSelectedMDL );
  160. CUtlDict<int, unsigned short> activityNames( true, 0, hdr->GetNumSeq() );
  161. for (int j = 0; j < hdr->GetNumSeq(); j++)
  162. {
  163. if ( /*g_viewerSettings.showHidden ||*/ !(hdr->pSeqdesc(j).flags & STUDIO_HIDDEN))
  164. {
  165. const char *pActivityName = hdr->pSeqdesc(j).pszActivityName();
  166. if ( pActivityName && pActivityName[0] )
  167. {
  168. // Multiple sequences can have the same activity name; only add unique activity names
  169. if ( activityNames.Find( pActivityName ) == activityNames.InvalidIndex() )
  170. {
  171. KeyValues *pkv = new KeyValues("node", "activity", pActivityName );
  172. int nItemID = m_pActivitiesList->AddItem( pkv, 0, false, false );
  173. KeyValues *pDrag = new KeyValues( "drag", "text", pActivityName );
  174. pDrag->SetString( "texttype", "activityName" );
  175. pDrag->SetString( "mdl", vgui::MDLCache()->GetModelName( m_hSelectedMDL ) );
  176. m_pActivitiesList->SetItemDragData( nItemID, pDrag );
  177. activityNames.Insert( pActivityName, j );
  178. }
  179. }
  180. const char *pSequenceName = hdr->pSeqdesc(j).pszLabel();
  181. if ( pSequenceName && pSequenceName[0] )
  182. {
  183. KeyValues *pkv = new KeyValues("node", "sequence", pSequenceName);
  184. pkv->SetInt( "seqindex", j );
  185. int nItemID = m_pSequencesList->AddItem( pkv, 0, false, false );
  186. KeyValues *pDrag = new KeyValues( "drag", "text", pSequenceName );
  187. pDrag->SetString( "texttype", "sequenceName" );
  188. pDrag->SetString( "mdl", vgui::MDLCache()->GetModelName( m_hSelectedMDL ) );
  189. m_pSequencesList->SetItemDragData( nItemID, pDrag );
  190. }
  191. }
  192. }
  193. }
  194. //-----------------------------------------------------------------------------
  195. // Purpose: refreshes dialog on text changing
  196. //-----------------------------------------------------------------------------
  197. void CMDLSequencePicker::OnTextChanged( vgui::Panel *pPanel, const char *pText )
  198. {
  199. // m_pFileTree->SetFilter( pText );
  200. RefreshFileList();
  201. }
  202. /*
  203. //-----------------------------------------------------------------------------
  204. // Purpose: Selects an sequence based on an activity
  205. //-----------------------------------------------------------------------------
  206. int SelectWeightedSequence( studiohdr_t *pstudiohdr, int activity, int curSequence )
  207. {
  208. if (! pstudiohdr)
  209. return 0;
  210. VerifySequenceIndex( pstudiohdr );
  211. int weighttotal = 0;
  212. int seq = ACTIVITY_NOT_AVAILABLE;
  213. int weight = 0;
  214. for (int i = 0; i < pstudiohdr->GetNumSeq(); i++)
  215. {
  216. int curActivity = GetSequenceActivity( pstudiohdr, i, &weight );
  217. if (curActivity == activity)
  218. {
  219. if ( curSequence == i && weight < 0 )
  220. {
  221. seq = i;
  222. break;
  223. }
  224. weighttotal += iabs(weight);
  225. int randomValue;
  226. if ( IsInPrediction() )
  227. randomValue = SharedRandomInt( "SelectWeightedSequence", 0, weighttotal - 1, i );
  228. else
  229. randomValue = RandomInt( 0, weighttotal - 1 );
  230. if (!weighttotal || randomValue < iabs(weight))
  231. seq = i;
  232. }
  233. }
  234. return seq;
  235. }
  236. */
  237. //-----------------------------------------------------------------------------
  238. // Plays the selected activity
  239. //-----------------------------------------------------------------------------
  240. void CMDLSequencePicker::PlaySelectedActivity( )
  241. {
  242. int nIndex = m_pActivitiesList->GetSelectedItem( 0 );
  243. if ( nIndex < 0 )
  244. return;
  245. KeyValues *pkv = m_pActivitiesList->GetItem( nIndex );
  246. const char *pActivityName = pkv->GetString( "activity", NULL );
  247. if ( !pActivityName )
  248. return;
  249. studiohdr_t *pstudiohdr = vgui::MDLCache()->GetStudioHdr( m_hSelectedMDL );
  250. for ( int i = 0; i < pstudiohdr->GetNumSeq(); i++ )
  251. {
  252. mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( i );
  253. if ( stricmp( seqdesc.pszActivityName(), pActivityName ) == 0 )
  254. {
  255. // FIXME: Add weighted sequence selection logic?
  256. m_pMDLPreview->SetSequence( i );
  257. break;
  258. }
  259. }
  260. }
  261. //-----------------------------------------------------------------------------
  262. // Plays the selected sequence
  263. //-----------------------------------------------------------------------------
  264. void CMDLSequencePicker::PlaySelectedSequence( )
  265. {
  266. int nIndex = m_pSequencesList->GetSelectedItem( 0 );
  267. if ( nIndex < 0 )
  268. return;
  269. KeyValues *pkv = m_pSequencesList->GetItem( nIndex );
  270. const char *pSequenceName = pkv->GetString( "sequence", NULL );
  271. if ( !pSequenceName )
  272. return;
  273. studiohdr_t *pstudiohdr = vgui::MDLCache()->GetStudioHdr( m_hSelectedMDL );
  274. for (int i = 0; i < pstudiohdr->GetNumSeq(); i++)
  275. {
  276. mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( i );
  277. if ( !Q_stricmp( seqdesc.pszLabel(), pSequenceName ) )
  278. {
  279. m_pMDLPreview->SetSequence( i );
  280. break;
  281. }
  282. }
  283. }
  284. //-----------------------------------------------------------------------------
  285. // Purpose: Called when a page is shown
  286. //-----------------------------------------------------------------------------
  287. void CMDLSequencePicker::OnPageChanged( )
  288. {
  289. if ( m_pViewsSheet->GetActivePage() == m_pSequencesPage )
  290. {
  291. PlaySelectedSequence();
  292. return;
  293. }
  294. if ( m_pViewsSheet->GetActivePage() == m_pActivitiesPage )
  295. {
  296. PlaySelectedActivity();
  297. return;
  298. }
  299. }
  300. //-----------------------------------------------------------------------------
  301. // Purpose: refreshes dialog on text changing
  302. //-----------------------------------------------------------------------------
  303. void CMDLSequencePicker::OnItemSelected( KeyValues *kv )
  304. {
  305. Panel *pPanel = (Panel *)kv->GetPtr("panel", NULL);
  306. if ( pPanel == m_pSequencesList )
  307. {
  308. PlaySelectedSequence();
  309. return;
  310. }
  311. if ( pPanel == m_pActivitiesList )
  312. {
  313. PlaySelectedActivity();
  314. return;
  315. }
  316. }
  317. //-----------------------------------------------------------------------------
  318. // An MDL was selected
  319. //-----------------------------------------------------------------------------
  320. void CMDLSequencePicker::SelectMDL( const char *pMDLName )
  321. {
  322. m_hSelectedMDL = pMDLName ? vgui::MDLCache()->FindMDL( pMDLName ) : MDLHANDLE_INVALID;
  323. if ( vgui::MDLCache()->IsErrorModel( m_hSelectedMDL ) )
  324. {
  325. m_hSelectedMDL = MDLHANDLE_INVALID;
  326. }
  327. m_pMDLPreview->SetMDL( m_hSelectedMDL );
  328. m_pMDLPreview->LookAtMDL();
  329. RefreshActivitiesAndSequencesList();
  330. }
  331. //-----------------------------------------------------------------------------
  332. // Purpose: updates revision view on a file being selected
  333. //-----------------------------------------------------------------------------
  334. void CMDLSequencePicker::OnFileSelected()
  335. {
  336. // update list
  337. int iItem = m_pFileTree->GetFirstSelectedItem();
  338. if ( iItem < 0 )
  339. return;
  340. // Don't bother to change if a directory was selected
  341. KeyValues *pkv = m_pFileTree->GetItemData(iItem);
  342. if ( pkv->GetInt("dir") || pkv->GetInt("root") )
  343. return;
  344. surface()->SetCursor(dc_waitarrow);
  345. const char *pFullPathName = pkv->GetString( "path" );
  346. char pRelativePathName[MAX_PATH];
  347. g_pFullFileSystem->FullPathToRelativePath( pFullPathName, pRelativePathName, sizeof(pRelativePathName) );
  348. // FIXME: Check that we're not actually opening the wrong file!!
  349. SelectMDL( pRelativePathName );
  350. }
  351. char const *CMDLSequencePicker::GetModelName()
  352. {
  353. if ( MDLHANDLE_INVALID == m_hSelectedMDL )
  354. {
  355. return "";
  356. }
  357. return vgui::MDLCache()->GetModelName( m_hSelectedMDL );
  358. }
  359. char const *CMDLSequencePicker::GetSequenceName()
  360. {
  361. int nIndex = m_pSequencesList->GetSelectedItem( 0 );
  362. if ( nIndex < 0 )
  363. return "";
  364. KeyValues *pkv = m_pSequencesList->GetItem( nIndex );
  365. const char *pSequenceName = pkv->GetString( "sequence", NULL );
  366. if ( !pSequenceName )
  367. return "";
  368. return pSequenceName;
  369. }
  370. int CMDLSequencePicker::GetSequenceNumber()
  371. {
  372. int nIndex = m_pSequencesList->GetSelectedItem( 0 );
  373. if ( nIndex < 0 )
  374. return -1;
  375. KeyValues *pkv = m_pSequencesList->GetItem( nIndex );
  376. return pkv->GetInt( "seqindex", -1 );
  377. }
  378. //-----------------------------------------------------------------------------
  379. // Sequence picker frame
  380. //-----------------------------------------------------------------------------
  381. CMDLSequencePickerFrame::CMDLSequencePickerFrame( vgui::Panel *parent, char const *title ) :
  382. BaseClass( parent, "MDLSequencePickerFrame" )
  383. {
  384. m_pMDLSequencePicker = new CMDLSequencePicker( this );
  385. SetTitle( title, true );
  386. SetSizeable( false );
  387. SetCloseButtonVisible( false );
  388. SetMoveable( true );
  389. SetMinimumSize( 640, 480 );
  390. Activate();
  391. m_pMDLSequencePicker->Activate();
  392. m_pOK = new Button( this, "OK", "#vgui_ok", this );
  393. m_pOK->SetCommand( new KeyValues( "OnOK" ) );
  394. m_pCancel= new Button( this, "Cancel", "#vgui_cancel", this );
  395. m_pOK->SetCommand( new KeyValues( "OnCancel" ) );
  396. m_pOK->SetEnabled( false );
  397. vgui::ivgui()->AddTickSignal( GetVPanel(), 0 );
  398. }
  399. CMDLSequencePickerFrame::~CMDLSequencePickerFrame()
  400. {
  401. }
  402. void CMDLSequencePickerFrame::OnTick()
  403. {
  404. BaseClass::OnTick();
  405. bool bHasModel = m_pMDLSequencePicker->GetModelName()[ 0 ] != 0 ? true : false;
  406. bool bHasSequence = m_pMDLSequencePicker->GetSequenceNumber() != -1 ? true : false;
  407. m_pOK->SetEnabled( bHasModel && bHasSequence );
  408. }
  409. void CMDLSequencePickerFrame::PerformLayout()
  410. {
  411. BaseClass::PerformLayout();
  412. int x, y, w, h;
  413. GetClientArea( x, y, w, h );
  414. h -= 24;
  415. m_pMDLSequencePicker->SetBounds( x, y, w, h );
  416. h += 5;
  417. int bw = 120;
  418. int bwwithGap = 2 * bw + 10;
  419. x = ( w - bwwithGap ) / 2;
  420. m_pOK->SetBounds( x, y + h, bw, 16 );
  421. x += bw + 10;
  422. m_pCancel->SetBounds( x, y + h, bw, 16 );
  423. }
  424. void CMDLSequencePickerFrame::OnCancel()
  425. {
  426. KeyValues *pActionKeys = new KeyValues( "AssetSelected" );
  427. pActionKeys->SetString( "ModelName", m_pMDLSequencePicker->GetModelName() );
  428. pActionKeys->SetString( "SequenceName", m_pMDLSequencePicker->GetSequenceName() );
  429. pActionKeys->SetInt( "SequenceNumber", m_pMDLSequencePicker->GetSequenceNumber() );
  430. PostActionSignal( pActionKeys );
  431. CloseModal();
  432. }
  433. void CMDLSequencePickerFrame::OnOK()
  434. {
  435. CloseModal();
  436. }