Counter Strike : Global Offensive Source Code
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.

1499 lines
34 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include <windows.h>
  8. #include "AnimationBrowser.h"
  9. #include "hlfaceposer.h"
  10. #include "ChoreoView.h"
  11. #include "StudioModel.h"
  12. #include "ViewerSettings.h"
  13. #include "choreowidgetdrawhelper.h"
  14. #include "faceposer_models.h"
  15. #include "tabwindow.h"
  16. #include "inputproperties.h"
  17. #include "keyvalues.h"
  18. #include "FileSystem.h"
  19. #include "tier1/KeyValues.h"
  20. #include "tier1/UtlBuffer.h"
  21. #define MAX_THUMBNAILSIZE 256
  22. #define MIN_THUMBNAILSIZE 64
  23. #define THUMBNAIL_SIZE_STEP 4
  24. #define DEFAULT_THUMBNAIL_SIZE 128
  25. #define TOP_GAP 70
  26. AnimationBrowser *g_pAnimationBrowserTool = 0;
  27. extern double realtime;
  28. void CreatePath( const char *pPath );
  29. void CCustomAnim::LoadFromFile()
  30. {
  31. char fn[ 512 ];
  32. if ( !filesystem->String( m_Handle, fn, sizeof( fn ) ) )
  33. return;
  34. KeyValues *kv = new KeyValues( "CustomAnimation" );
  35. if ( kv->LoadFromFile( filesystem, fn, "MOD" ) )
  36. {
  37. for ( KeyValues *sub = kv->GetFirstSubKey(); sub ; sub = sub->GetNextKey() )
  38. {
  39. CUtlSymbol anim;
  40. anim = sub->GetString();
  41. m_Animations.AddToTail( anim );
  42. }
  43. }
  44. kv->deleteThis();
  45. }
  46. void CCustomAnim::SaveToFile()
  47. {
  48. char fn[ 512 ];
  49. if ( !filesystem->String( m_Handle, fn, sizeof( fn ) ) )
  50. return;
  51. CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
  52. buf.Printf( "\"%s\"\n", m_ShortName.String() );
  53. buf.Printf( "{\n" );
  54. for ( int i = 0; i < m_Animations.Count(); ++i )
  55. {
  56. buf.Printf( "\t\"item%d\" \"%s\"\n", i + 1, m_Animations[ i ].String() );
  57. }
  58. buf.Printf( "}\n" );
  59. CreatePath( fn );
  60. filesystem->WriteFile( fn, "MOD", buf );
  61. }
  62. bool CCustomAnim::HasAnimation( char const *search )
  63. {
  64. CUtlSymbol searchSym;
  65. searchSym = search;
  66. if ( m_Animations.Find( searchSym ) != m_Animations.InvalidIndex() )
  67. return true;
  68. return false;
  69. }
  70. //-----------------------------------------------------------------------------
  71. // Purpose:
  72. //-----------------------------------------------------------------------------
  73. class CAnimBrowserTab : public CTabWindow
  74. {
  75. typedef CTabWindow BaseClass;
  76. public:
  77. CAnimBrowserTab( AnimationBrowser *parent, int x, int y, int w, int h, int id = 0, int style = 0 ) :
  78. CTabWindow( (mxWindow *)parent, x, y, w, h, id, style )
  79. {
  80. // SetInverted( true );
  81. }
  82. void Init( void )
  83. {
  84. add( "all" );
  85. add( "gestures" );
  86. add( "postures" );
  87. add( "search results" );
  88. }
  89. virtual void ShowRightClickMenu( int mx, int my )
  90. {
  91. POINT pt;
  92. GetCursorPos( &pt );
  93. ScreenToClient( (HWND)getHandle(), &pt );
  94. // New scene, edit comments
  95. mxPopupMenu *pop = new mxPopupMenu();
  96. pop->add ("&New Group...", IDC_AB_CREATE_CUSTOM );
  97. mxPopupMenu *sub = NULL;
  98. for ( int i = 0; i < m_CustomGroups.Count(); ++i )
  99. {
  100. if ( !sub )
  101. {
  102. sub = new mxPopupMenu();
  103. }
  104. sub->add( va( "%s", m_CustomGroups[ i ].String() ), IDC_AB_DELETEGROUPSTART + i );
  105. }
  106. if ( sub )
  107. {
  108. pop->addMenu( "Delete Group", sub );
  109. }
  110. pop->addSeparator();
  111. sub = new mxPopupMenu();
  112. for ( int i = 0; i < m_CustomGroups.Count(); ++i )
  113. {
  114. sub->add( va( "%s", m_CustomGroups[ i ].String() ), IDC_AB_RENAMEGROUPSTART + i );
  115. }
  116. pop->addMenu( "Rename Group", sub );
  117. pop->popup( getParent(), pt.x, pt.y );
  118. }
  119. void UpdateCustomTabs( CUtlVector< CCustomAnim * >& list )
  120. {
  121. m_CustomGroups.Purge();
  122. while ( getItemCount() > AnimationBrowser::FILTER_FIRST_CUSTOM )
  123. {
  124. remove( getItemCount() - 1 );
  125. }
  126. for ( int i = 0; i < list.Count(); ++i )
  127. {
  128. const CCustomAnim *anim = list[ i ];
  129. add( anim->m_ShortName.String() );
  130. m_CustomGroups.AddToTail( anim->m_ShortName );
  131. }
  132. }
  133. private:
  134. CUtlVector< CUtlSymbol > m_CustomGroups;
  135. };
  136. AnimationBrowser::AnimationBrowser( mxWindow *parent, int id /*=0*/ )
  137. : IFacePoserToolWindow( "AnimationBrowser", "Animations" ),
  138. mxWindow( parent, 0, 0, 0, 0, "AnimationBrowser", id )
  139. {
  140. setId( id );
  141. m_nTopOffset = 0;
  142. slScrollbar = new mxScrollbar( this, 0, 0, 18, 100, IDC_AB_TRAYSCROLL, mxScrollbar::Vertical );
  143. m_nLastNumAnimations = -1;
  144. m_nGranularity = 10;
  145. m_nCurCell = -1;
  146. m_nClickedCell = -1;
  147. m_nGap = 4;
  148. m_nDescriptionHeight = 34;
  149. m_nSnapshotWidth = g_viewerSettings.thumbnailsizeanim;
  150. m_nSnapshotWidth = max( MIN_THUMBNAILSIZE, m_nSnapshotWidth );
  151. m_nSnapshotWidth = min( MAX_THUMBNAILSIZE, m_nSnapshotWidth );
  152. g_viewerSettings.thumbnailsizeanim = m_nSnapshotWidth;
  153. m_nSnapshotHeight = m_nSnapshotWidth + m_nDescriptionHeight;
  154. m_bDragging = false;
  155. m_nDragCell = -1;
  156. m_szSearchString[0]=0;
  157. m_pFilterTab = new CAnimBrowserTab( this, 5, 5, 240, 20, IDC_AB_FILTERTAB );
  158. m_pFilterTab->Init();
  159. m_pSearchEntry = new mxLineEdit( this, 0, 0, 0, 0, "" );
  160. m_pThumbnailIncreaseButton = new mxButton( this, 0, 0, 18, 18, "+", IDC_AB_THUMBNAIL_INCREASE );
  161. m_pThumbnailDecreaseButton = new mxButton( this, 0, 0, 18, 18, "-", IDC_AB_THUMBNAIL_DECREASE );
  162. m_nCurFilter = FILTER_NONE;
  163. m_flDragTime = 0.0f;
  164. OnFilter();
  165. }
  166. //-----------------------------------------------------------------------------
  167. // Purpose:
  168. // Output : AnimationBrowser::~AnimationBrowser
  169. //-----------------------------------------------------------------------------
  170. AnimationBrowser::~AnimationBrowser ( void )
  171. {
  172. g_pAnimationBrowserTool = NULL;
  173. }
  174. void AnimationBrowser::Shutdown()
  175. {
  176. PurgeCustom();
  177. }
  178. //-----------------------------------------------------------------------------
  179. // Purpose:
  180. // Input : cellsize -
  181. //-----------------------------------------------------------------------------
  182. void AnimationBrowser::SetCellSize( int cellsize )
  183. {
  184. m_nSnapshotWidth = cellsize;
  185. m_nSnapshotHeight = cellsize + m_nDescriptionHeight;
  186. redraw();
  187. }
  188. //-----------------------------------------------------------------------------
  189. // Purpose:
  190. //-----------------------------------------------------------------------------
  191. void AnimationBrowser::Deselect( void )
  192. {
  193. m_nCurCell = -1;
  194. redraw();
  195. }
  196. //-----------------------------------------------------------------------------
  197. // Purpose:
  198. // Input : exp -
  199. //-----------------------------------------------------------------------------
  200. void AnimationBrowser::Select( int sequence )
  201. {
  202. m_nCurCell = sequence;
  203. redraw();
  204. }
  205. //-----------------------------------------------------------------------------
  206. // Purpose:
  207. // Output : int
  208. //-----------------------------------------------------------------------------
  209. int AnimationBrowser::ComputePixelsNeeded( void )
  210. {
  211. int seqcount = GetSequenceCount();
  212. if ( !seqcount )
  213. return 100;
  214. // Remove scroll bar
  215. int w = this->w2() - 16;
  216. int colsperrow;
  217. colsperrow = ( w - m_nGap ) / ( m_nSnapshotWidth + m_nGap );
  218. // At least one
  219. colsperrow = max( 1, colsperrow );
  220. int rowsneeded = ( ( seqcount + colsperrow - 1 ) / colsperrow );
  221. return rowsneeded * ( m_nSnapshotHeight + m_nGap ) + m_nGap + TOP_GAP + GetCaptionHeight();
  222. }
  223. bool AnimationBrowser::ComputeRect( int cell, int& rcx, int& rcy, int& rcw, int& rch )
  224. {
  225. // Remove scroll bar
  226. int w = this->w2() - 16;
  227. int colsperrow;
  228. colsperrow = ( w - m_nGap ) / ( m_nSnapshotWidth + m_nGap );
  229. // At least one
  230. colsperrow = max( 1, colsperrow );
  231. int row, col;
  232. row = cell / colsperrow;
  233. col = cell % colsperrow;
  234. // don't allow partial columns
  235. rcx = m_nGap + col * ( m_nSnapshotWidth + m_nGap );
  236. rcy = GetCaptionHeight() + TOP_GAP + ( -m_nTopOffset * m_nGranularity ) + m_nGap + row * ( m_nSnapshotHeight + m_nGap );
  237. // Starts off screen
  238. if ( rcx < 0 )
  239. return false;
  240. // Ends off screen
  241. if ( rcx + m_nSnapshotWidth + m_nGap > this->w2() )
  242. return false;
  243. // Allow partial in y direction
  244. if ( rcy > this->h2() )
  245. return false;
  246. if ( rcy + m_nSnapshotHeight + m_nGap < 0 )
  247. return false;
  248. // Some portion is onscreen
  249. rcw = m_nSnapshotWidth;
  250. rch = m_nSnapshotHeight;
  251. return true;
  252. }
  253. void AnimationBrowser::DrawSequenceFocusRect( CChoreoWidgetDrawHelper& helper, int x, int y, int w, int h, const Color& clr )
  254. {
  255. helper.DrawOutlinedRect( clr, PS_SOLID, 4, x, y, x + w, y + h );
  256. }
  257. void AnimationBrowser::DrawSequenceDescription( CChoreoWidgetDrawHelper& helper, int x, int y, int w, int h, int sequence, mstudioseqdesc_t &seqdesc )
  258. {
  259. int textheight = 15;
  260. RECT textRect;
  261. textRect.left = x + 5;
  262. textRect.top = y + h - 2 * textheight - 12;
  263. textRect.right = x + w - 10;
  264. textRect.bottom = y + h - 12;
  265. helper.DrawColoredText( "Arial", 9, FW_NORMAL, Color( 63, 63, 63 ), textRect, "%s", seqdesc.pszLabel() );
  266. StudioModel *mdl = models->GetActiveStudioModel();
  267. if ( !mdl )
  268. return;
  269. OffsetRect( &textRect, 0, textheight );
  270. helper.DrawColoredText( "Arial", 9, FW_NORMAL, Color( 63, 63, 63 ), textRect, "%.2f seconds",
  271. mdl->GetDuration( sequence ) );
  272. textRect.top = y + h - 4 * textheight - 1;
  273. textRect.bottom = textRect.top + textheight;
  274. helper.DrawColoredText( "Arial", 9, FW_NORMAL, Color( 50, 200, 255 ), textRect, "frames %i",
  275. mdl->GetNumFrames( sequence ) );
  276. OffsetRect( &textRect, 0, textheight - 4 );
  277. helper.DrawColoredText( "Arial", 9, FW_NORMAL, Color( 50, 200, 255 ), textRect, "fps %.2f",
  278. (float)mdl->GetFPS( sequence ) );
  279. }
  280. bool AnimationBrowser::PaintBackground( void )
  281. {
  282. redraw();
  283. return false;
  284. }
  285. void AnimationBrowser::DrawThumbNail( int sequence, CChoreoWidgetDrawHelper& helper, int rcx, int rcy, int rcw, int rch )
  286. {
  287. HDC dc = helper.GrabDC();
  288. helper.DrawFilledRect( RGBToColor( GetSysColor( COLOR_BTNFACE ) ), rcx, rcy, rcw + rcx, rch + rcy );
  289. mstudioseqdesc_t *pseqdesc = GetSeqDesc( sequence );
  290. if ( !pseqdesc )
  291. return;
  292. mxbitmapdata_t *bm = models->GetBitmapForSequence( models->GetActiveModelIndex(), TranslateSequenceNumber( sequence ) );
  293. if ( bm && bm->valid )
  294. {
  295. DrawBitmapToDC( dc, rcx, rcy, rcw, rch - m_nDescriptionHeight, *bm );
  296. helper.DrawOutlinedRect( Color( 127, 127, 127 ), PS_SOLID, 1, rcx, rcy, rcx + rcw, rcy + rch - m_nDescriptionHeight );
  297. }
  298. DrawSequenceDescription( helper, rcx, rcy, rcw, rch, TranslateSequenceNumber( sequence ), *pseqdesc );
  299. if ( sequence == m_nCurCell )
  300. {
  301. DrawSequenceFocusRect( helper, rcx, rcy, rcw, rch - m_nDescriptionHeight, Color( 255, 100, 63 ) );
  302. }
  303. }
  304. void AnimationBrowser::redraw()
  305. {
  306. if ( !ToolCanDraw() )
  307. return;
  308. bool updateSelection = false;
  309. int curcount = GetSequenceCount();
  310. if ( curcount != m_nLastNumAnimations )
  311. {
  312. m_nTopOffset = 0;
  313. RepositionSlider();
  314. m_nLastNumAnimations = curcount;
  315. updateSelection = true;
  316. }
  317. CChoreoWidgetDrawHelper helper( this, RGBToColor( GetSysColor( COLOR_BTNFACE ) ) );
  318. HandleToolRedraw( helper );
  319. int w, h;
  320. w = w2();
  321. h = h2();
  322. RECT clipRect;
  323. helper.GetClientRect( clipRect );
  324. clipRect.top += TOP_GAP + GetCaptionHeight();
  325. helper.StartClipping( clipRect );
  326. int rcx, rcy, rcw, rch;
  327. EnableStickySnapshotMode( );
  328. int c = curcount;
  329. for ( int i = 0; i < c; i++ )
  330. {
  331. if ( !ComputeRect( i, rcx, rcy, rcw, rch ) )
  332. {
  333. // Cache in .bmp no matter what
  334. // This was too slow, so turning it back off
  335. //models->GetBitmapForSequence( models->GetActiveModelIndex(), TranslateSequenceNumber( i ) );
  336. continue;
  337. }
  338. DrawThumbNail( i, helper, rcx, rcy, rcw, rch );
  339. }
  340. DisableStickySnapshotMode( );
  341. helper.StopClipping();
  342. RECT rcText;
  343. rcText.right = w2();
  344. rcText.left = rcText.right - 120;
  345. rcText.top = 8;
  346. rcText.bottom = rcText.top + 15;
  347. helper.DrawColoredText( "Arial", 9, FW_NORMAL, Color( 63, 63, 63 ), rcText, "%i sequences",
  348. curcount );
  349. }
  350. int AnimationBrowser::GetCellUnderPosition( int x, int y )
  351. {
  352. int count = GetSequenceCount();
  353. if ( !count )
  354. return -1;
  355. int rcx, rcy, rcw, rch;
  356. int c = 0;
  357. while ( c < count )
  358. {
  359. if ( !ComputeRect( c, rcx, rcy, rcw, rch ) )
  360. {
  361. c++;
  362. continue;
  363. }
  364. if ( x >= rcx && x <= rcx + rcw &&
  365. y >= rcy && y <= rcy + rch )
  366. {
  367. return c;
  368. }
  369. c++;
  370. }
  371. return -1;
  372. }
  373. void AnimationBrowser::RepositionSlider( void )
  374. {
  375. int trueh = h2() - GetCaptionHeight();
  376. int heightpixels = trueh / m_nGranularity;
  377. int rangepixels = ComputePixelsNeeded() / m_nGranularity;
  378. if ( rangepixels < heightpixels )
  379. {
  380. m_nTopOffset = 0;
  381. slScrollbar->setVisible( false );
  382. }
  383. else
  384. {
  385. slScrollbar->setVisible( true );
  386. }
  387. slScrollbar->setBounds( w2() - 16, GetCaptionHeight() + TOP_GAP, 16, trueh - TOP_GAP );
  388. m_nTopOffset = max( 0, m_nTopOffset );
  389. m_nTopOffset = min( rangepixels, m_nTopOffset );
  390. slScrollbar->setRange( 0, rangepixels );
  391. slScrollbar->setValue( m_nTopOffset );
  392. slScrollbar->setPagesize( heightpixels );
  393. }
  394. void AnimationBrowser::SetClickedCell( int cell )
  395. {
  396. m_nClickedCell = cell;
  397. Select( cell );
  398. }
  399. void AnimationBrowser::ShowRightClickMenu( int mx, int my )
  400. {
  401. mstudioseqdesc_t *pseqdesc = GetSeqDesc( m_nCurCell );
  402. if ( !pseqdesc )
  403. return;
  404. mxPopupMenu *pop = new mxPopupMenu();
  405. Assert( pop );
  406. pop->add( va( "New Group..." ), IDC_AB_CREATE_CUSTOM );
  407. if ( m_CustomAnimationTabs.Count() > 0 )
  408. {
  409. mxPopupMenu *ca = new mxPopupMenu();
  410. Assert( ca );
  411. for ( int i = 0; i < m_CustomAnimationTabs.Count() ; ++i )
  412. {
  413. CCustomAnim *anim = m_CustomAnimationTabs[ i ];
  414. ca->add( va( "%s", anim->m_ShortName.String() ), IDC_AB_ADDTOGROUPSTART + i );
  415. }
  416. pop->addMenu( "Add to Group", ca );
  417. ca = new mxPopupMenu();
  418. bool useMenu = false;
  419. for ( int i = 0; i < m_CustomAnimationTabs.Count() ; ++i )
  420. {
  421. CCustomAnim *anim = m_CustomAnimationTabs[ i ];
  422. if ( anim->HasAnimation( pseqdesc->pszLabel() ) )
  423. {
  424. ca->add( va( "%s", anim->m_ShortName.String() ), IDC_AB_REMOVEFROMGROUPSTART + i );
  425. useMenu = true;
  426. }
  427. }
  428. if ( useMenu )
  429. {
  430. pop->addMenu( "Remove from Group", ca );
  431. }
  432. else
  433. {
  434. delete ca;
  435. }
  436. }
  437. pop->addSeparator();
  438. pop->add( va( "Re-create thumbnail for '%s'", pseqdesc->pszLabel() ), IDC_AB_CONTEXT_CREATEBITMAP );
  439. pop->add( va( "Re-create all thumbnails" ), IDC_AB_CONTEXT_CREATEALLBITMAPS );
  440. pop->popup( this, mx, my );
  441. }
  442. //-----------------------------------------------------------------------------
  443. // Purpose:
  444. //-----------------------------------------------------------------------------
  445. void AnimationBrowser::DrawFocusRect( void )
  446. {
  447. HDC dc = GetDC( NULL );
  448. ::DrawFocusRect( dc, &m_rcFocus );
  449. ReleaseDC( NULL, dc );
  450. }
  451. static bool IsWindowOrChild( mxWindow *parent, HWND test )
  452. {
  453. HWND parentHwnd = (HWND)parent->getHandle();
  454. if ( test == parentHwnd ||
  455. IsChild( parentHwnd, test ) )
  456. {
  457. return true;
  458. }
  459. return false;
  460. }
  461. int AnimationBrowser::handleEvent (mxEvent *event)
  462. {
  463. MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
  464. int iret = 0;
  465. if ( HandleToolEvent( event ) )
  466. {
  467. return iret;
  468. }
  469. switch ( event->event )
  470. {
  471. case mxEvent::Action:
  472. {
  473. iret = 1;
  474. switch ( event->action )
  475. {
  476. default:
  477. if ( event->action >= IDC_AB_ADDTOGROUPSTART && event->action <= IDC_AB_ADDTOGROUPEND )
  478. {
  479. int index = event->action - IDC_AB_ADDTOGROUPSTART;
  480. mstudioseqdesc_t *pseqdesc = GetSeqDesc( m_nCurCell );
  481. if ( pseqdesc )
  482. {
  483. AddAnimationToCustomFile( index, pseqdesc->pszLabel() );
  484. }
  485. }
  486. else if ( event->action >= IDC_AB_REMOVEFROMGROUPSTART && event->action <= IDC_AB_REMOVEFROMGROUPEND )
  487. {
  488. int index = event->action - IDC_AB_REMOVEFROMGROUPSTART;
  489. mstudioseqdesc_t *pseqdesc = GetSeqDesc( m_nCurCell );
  490. if ( pseqdesc )
  491. {
  492. RemoveAnimationFromCustomFile( index, pseqdesc->pszLabel() );
  493. }
  494. }
  495. else if ( event->action >= IDC_AB_DELETEGROUPSTART && event->action <= IDC_AB_DELETEGROUPEND )
  496. {
  497. int index = event->action - IDC_AB_DELETEGROUPSTART;
  498. DeleteCustomFile( index );
  499. }
  500. else if ( event->action >= IDC_AB_RENAMEGROUPSTART && event->action <= IDC_AB_RENAMEGROUPEND )
  501. {
  502. int index = event->action - IDC_AB_RENAMEGROUPSTART;
  503. RenameCustomFile( index );
  504. }
  505. else
  506. {
  507. iret = 0;
  508. }
  509. break;
  510. case IDC_AB_CREATE_CUSTOM:
  511. {
  512. OnAddCustomAnimationFilter();
  513. }
  514. break;
  515. case IDC_AB_FILTERTAB:
  516. {
  517. int index = m_pFilterTab->getSelectedIndex();
  518. if ( index >= 0 )
  519. {
  520. m_nCurFilter = index;
  521. OnFilter();
  522. }
  523. }
  524. break;
  525. case IDC_AB_TRAYSCROLL:
  526. {
  527. if (event->modifiers == SB_THUMBTRACK)
  528. {
  529. int offset = event->height;
  530. slScrollbar->setValue( offset );
  531. m_nTopOffset = offset;
  532. redraw();
  533. }
  534. else if ( event->modifiers == SB_PAGEUP )
  535. {
  536. int offset = slScrollbar->getValue();
  537. offset -= m_nGranularity;
  538. offset = max( offset, slScrollbar->getMinValue() );
  539. slScrollbar->setValue( offset );
  540. InvalidateRect( (HWND)slScrollbar->getHandle(), NULL, TRUE );
  541. m_nTopOffset = offset;
  542. redraw();
  543. }
  544. else if ( event->modifiers == SB_PAGEDOWN )
  545. {
  546. int offset = slScrollbar->getValue();
  547. offset += m_nGranularity;
  548. offset = min( offset, slScrollbar->getMaxValue() );
  549. slScrollbar->setValue( offset );
  550. InvalidateRect( (HWND)slScrollbar->getHandle(), NULL, TRUE );
  551. m_nTopOffset = offset;
  552. redraw();
  553. }
  554. }
  555. break;
  556. case IDC_AB_THUMBNAIL_INCREASE:
  557. {
  558. ThumbnailIncrease();
  559. }
  560. break;
  561. case IDC_AB_THUMBNAIL_DECREASE:
  562. {
  563. ThumbnailDecrease();
  564. }
  565. break;
  566. case IDC_AB_CONTEXT_CREATEBITMAP:
  567. {
  568. int current_model = models->GetActiveModelIndex();
  569. if ( m_nClickedCell >= 0 )
  570. {
  571. models->RecreateAnimationBitmap( current_model, TranslateSequenceNumber( m_nClickedCell ) );
  572. }
  573. redraw();
  574. }
  575. break;
  576. case IDC_AB_CONTEXT_CREATEALLBITMAPS:
  577. {
  578. int current_model = models->GetActiveModelIndex();
  579. models->RecreateAllAnimationBitmaps( current_model );
  580. redraw();
  581. }
  582. break;
  583. }
  584. break;
  585. }
  586. case mxEvent::MouseDown:
  587. {
  588. if ( !( event->buttons & mxEvent::MouseRightButton ) )
  589. {
  590. // Figure out cell #
  591. int cell = GetCellUnderPosition( event->x, event->y );
  592. if ( cell >= 0 && cell < GetSequenceCount() )
  593. {
  594. int cx, cy, cw, ch;
  595. if ( ComputeRect( cell, cx, cy, cw, ch ) )
  596. {
  597. m_flDragTime = realtime;
  598. m_bDragging = true;
  599. m_nDragCell = cell;
  600. m_nXStart = (short)event->x;
  601. m_nYStart = (short)event->y;
  602. m_rcFocus.left = cx;
  603. m_rcFocus.top = cy;
  604. m_rcFocus.right = cx + cw;
  605. m_rcFocus.bottom = cy + ch - m_nDescriptionHeight;
  606. POINT pt;
  607. pt.x = pt.y = 0;
  608. ClientToScreen( (HWND)getHandle(), &pt );
  609. OffsetRect( &m_rcFocus, pt.x, pt.y );
  610. m_rcOrig = m_rcFocus;
  611. DrawFocusRect();
  612. Select( cell );
  613. m_nClickedCell = cell;
  614. }
  615. }
  616. else
  617. {
  618. Deselect();
  619. redraw();
  620. }
  621. }
  622. iret = 1;
  623. }
  624. break;
  625. case mxEvent::MouseDrag:
  626. {
  627. if ( m_bDragging )
  628. {
  629. // Draw drag line of some kind
  630. DrawFocusRect();
  631. // update pos
  632. m_rcFocus = m_rcOrig;
  633. OffsetRect( &m_rcFocus, ( (short)event->x - m_nXStart ),
  634. ( (short)event->y - m_nYStart ) );
  635. DrawFocusRect();
  636. }
  637. iret = 1;
  638. }
  639. break;
  640. case mxEvent::MouseUp:
  641. {
  642. iret = 1;
  643. if ( event->buttons & mxEvent::MouseRightButton )
  644. {
  645. SetClickedCell( GetCellUnderPosition( (short)event->x, (short)event->y ) );
  646. ShowRightClickMenu( (short)event->x, (short)event->y );
  647. return iret;
  648. }
  649. if ( m_bDragging && m_nClickedCell >= 0 )
  650. {
  651. mstudioseqdesc_t *pseqdesc = GetSeqDesc( m_nClickedCell );
  652. DrawFocusRect();
  653. m_bDragging = false;
  654. // See if we let go on top of the choreo view
  655. // Convert x, y to screen space
  656. POINT pt;
  657. pt.x = (short)event->x;
  658. pt.y = (short)event->y;
  659. ClientToScreen( (HWND)getHandle(), &pt );
  660. HWND maybeTool = WindowFromPoint( pt );
  661. // Now tell choreo view
  662. if ( maybeTool && pseqdesc )
  663. {
  664. if ( IsWindowOrChild( g_pChoreoView, maybeTool ) )
  665. {
  666. if ( g_pChoreoView->CreateAnimationEvent( pt.x, pt.y, pseqdesc->pszLabel() ) )
  667. {
  668. return iret;
  669. }
  670. }
  671. }
  672. }
  673. }
  674. break;
  675. case mxEvent::Size:
  676. {
  677. int width = w2();
  678. // int height = h2();
  679. int ch = GetCaptionHeight() + 10;
  680. m_pSearchEntry->setBounds( 5, ch, width - 10 - 170, 18 );
  681. m_pThumbnailIncreaseButton->setBounds( width - 40, 4 + ch, 16, 16 );
  682. m_pThumbnailDecreaseButton->setBounds( width - 20, 4 + ch, 16, 16 );
  683. m_pFilterTab->setBounds( 5, ch + 20, width - 10, 20 );
  684. m_nTopOffset = 0;
  685. RepositionSlider();
  686. redraw();
  687. iret = 1;
  688. }
  689. break;
  690. case mxEvent::MouseWheeled:
  691. {
  692. // Figure out cell #
  693. POINT pt;
  694. pt.x = event->x;
  695. pt.y = event->y;
  696. ScreenToClient( (HWND)getHandle(), &pt );
  697. if ( event->height < 0 )
  698. {
  699. m_nTopOffset = min( m_nTopOffset + 10, slScrollbar->getMaxValue() );
  700. }
  701. else
  702. {
  703. m_nTopOffset = max( m_nTopOffset - 10, 0 );
  704. }
  705. RepositionSlider();
  706. redraw();
  707. iret = 1;
  708. }
  709. break;
  710. case mxEvent::KeyDown:
  711. case mxEvent::KeyUp:
  712. {
  713. bool search = false;
  714. // int n = 3;
  715. if ( event->key == VK_ESCAPE && m_szSearchString[ 0 ] )
  716. {
  717. m_pSearchEntry->setLabel( "" );
  718. m_szSearchString[ 0 ] = 0;
  719. m_pFilterTab->select( FILTER_NONE );
  720. m_nCurFilter = FILTER_NONE;
  721. OnFilter();
  722. }
  723. else
  724. {
  725. // Text changed?
  726. char sz[ 512 ];
  727. m_pSearchEntry->getText( sz, sizeof( sz ) );
  728. if ( Q_stricmp( sz, m_szSearchString ) )
  729. {
  730. Q_strncpy( m_szSearchString, sz, sizeof( m_szSearchString ) );
  731. search = true;
  732. }
  733. }
  734. if ( search )
  735. {
  736. if ( Q_strlen( m_szSearchString ) > 0 )
  737. {
  738. m_pFilterTab->select( FILTER_STRING );
  739. m_nCurFilter = FILTER_STRING;
  740. }
  741. else
  742. {
  743. m_pFilterTab->select( FILTER_NONE );
  744. m_nCurFilter = FILTER_NONE;
  745. }
  746. OnFilter();
  747. }
  748. }
  749. break;
  750. };
  751. if ( iret )
  752. {
  753. SetActiveTool( this );
  754. }
  755. return iret;
  756. }
  757. // HACK HACK: VS2005 is generating bogus code for this little operation in the function below...
  758. #pragma optimize( "g", off )
  759. float roundcycle( float cycle )
  760. {
  761. int rounded = (int)(cycle);
  762. float cy2 = cycle - rounded;
  763. return cy2;
  764. }
  765. #pragma optimize( "", on )
  766. void AnimationBrowser::Think( float dt )
  767. {
  768. if ( !m_bDragging )
  769. return;
  770. if ( m_nClickedCell < 0 )
  771. return;
  772. StudioModel *model = models->GetActiveStudioModel();
  773. if ( model )
  774. {
  775. int iSequence = TranslateSequenceNumber( m_nClickedCell );
  776. float dur = model->GetDuration( iSequence );
  777. if ( dur > 0.0f )
  778. {
  779. float elapsed = (float)realtime - m_flDragTime;
  780. float flFrameRate = 0.0f;
  781. float flGroundSpeed = 0.0f;
  782. model->GetSequenceInfo( iSequence, &flFrameRate, &flGroundSpeed );
  783. float cycle = roundcycle( elapsed * flFrameRate );
  784. // This should be the only thing on the model!!!
  785. model->ClearAnimationLayers();
  786. // FIXME: shouldn't sequences always be lower priority than gestures?
  787. int iLayer = model->GetNewAnimationLayer( 0 );
  788. model->SetOverlaySequence( iLayer, iSequence, 1.0f );
  789. model->SetOverlayRate( iLayer, cycle, 0.0f );
  790. }
  791. }
  792. }
  793. //-----------------------------------------------------------------------------
  794. // Purpose:
  795. //-----------------------------------------------------------------------------
  796. void AnimationBrowser::ThumbnailIncrease( void )
  797. {
  798. if ( m_nSnapshotWidth + THUMBNAIL_SIZE_STEP <= MAX_THUMBNAILSIZE )
  799. {
  800. m_nSnapshotWidth += THUMBNAIL_SIZE_STEP;
  801. g_viewerSettings.thumbnailsizeanim = m_nSnapshotWidth;
  802. m_nSnapshotHeight = m_nSnapshotWidth + m_nDescriptionHeight;
  803. Con_Printf( "Thumbnail size %i x %i\n", m_nSnapshotWidth, m_nSnapshotWidth );
  804. redraw();
  805. }
  806. }
  807. //-----------------------------------------------------------------------------
  808. // Purpose:
  809. //-----------------------------------------------------------------------------
  810. void AnimationBrowser::ThumbnailDecrease( void )
  811. {
  812. if ( m_nSnapshotWidth - THUMBNAIL_SIZE_STEP >= MIN_THUMBNAILSIZE )
  813. {
  814. m_nSnapshotWidth -= THUMBNAIL_SIZE_STEP;
  815. g_viewerSettings.thumbnailsizeanim = m_nSnapshotWidth;
  816. m_nSnapshotHeight = m_nSnapshotWidth + m_nDescriptionHeight;
  817. Con_Printf( "Thumbnail size %i x %i\n", m_nSnapshotWidth, m_nSnapshotWidth );
  818. redraw();
  819. }
  820. }
  821. //-----------------------------------------------------------------------------
  822. // Purpose:
  823. //-----------------------------------------------------------------------------
  824. void AnimationBrowser::RestoreThumbnailSize( void )
  825. {
  826. m_nSnapshotWidth = g_viewerSettings.thumbnailsizeanim;
  827. m_nSnapshotWidth = max( MIN_THUMBNAILSIZE, m_nSnapshotWidth );
  828. m_nSnapshotWidth = min( MAX_THUMBNAILSIZE, m_nSnapshotWidth );
  829. g_viewerSettings.thumbnailsizeanim = m_nSnapshotWidth;
  830. m_nSnapshotHeight = m_nSnapshotWidth + m_nDescriptionHeight;
  831. redraw();
  832. }
  833. void AnimationBrowser::ReloadBitmaps( void )
  834. {
  835. Assert( 0 );
  836. redraw();
  837. }
  838. //-----------------------------------------------------------------------------
  839. // Purpose:
  840. // Input : *model -
  841. // sequence -
  842. // Output : static bool
  843. //-----------------------------------------------------------------------------
  844. static bool IsTypeOfSequence( StudioModel *model, int sequence, char const *typestring )
  845. {
  846. bool match = false;
  847. if ( !model->GetStudioHdr() )
  848. return match;
  849. KeyValues *seqKeyValues = new KeyValues("");
  850. if ( seqKeyValues->LoadFromBuffer( model->GetFileName( ), model->GetKeyValueText( sequence ) ) )
  851. {
  852. // Do we have a build point section?
  853. KeyValues *pkvAllFaceposer = seqKeyValues->FindKey("faceposer");
  854. if ( pkvAllFaceposer )
  855. {
  856. char const *t = pkvAllFaceposer->GetString( "type", "" );
  857. if ( t && !Q_stricmp( t, typestring ) )
  858. {
  859. match = true;
  860. }
  861. }
  862. }
  863. seqKeyValues->deleteThis();
  864. return match;
  865. }
  866. bool AnimationBrowser::SequencePassesFilter( StudioModel *model, int sequence, mstudioseqdesc_t &seqdesc )
  867. {
  868. if (model->IsHidden( sequence ))
  869. return false;
  870. switch ( m_nCurFilter )
  871. {
  872. default:
  873. {
  874. int offset = m_nCurFilter - FILTER_FIRST_CUSTOM;
  875. if ( offset >= 0 && offset < m_CustomAnimationTabs.Count() )
  876. {
  877. // Find the name
  878. CCustomAnim *anim = m_CustomAnimationTabs[ offset ];
  879. return anim->HasAnimation( seqdesc.pszLabel() );
  880. }
  881. return true;
  882. }
  883. break;
  884. case FILTER_NONE:
  885. {
  886. return true;
  887. }
  888. break;
  889. case FILTER_GESTURES:
  890. if ( IsTypeOfSequence( model, sequence, "gesture" ) )
  891. {
  892. return true;
  893. }
  894. break;
  895. case FILTER_POSTURES:
  896. if ( IsTypeOfSequence( model, sequence, "posture" ) )
  897. {
  898. return true;
  899. }
  900. break;
  901. case FILTER_STRING:
  902. if ( Q_stristr( seqdesc.pszLabel(), m_szSearchString ) )
  903. {
  904. return true;
  905. }
  906. }
  907. return false;
  908. }
  909. void AnimationBrowser::OnFilter()
  910. {
  911. m_Filtered.RemoveAll();
  912. StudioModel *model = models->GetActiveStudioModel();
  913. if ( !model )
  914. return;
  915. CStudioHdr *hdr = model->GetStudioHdr();
  916. if ( !hdr )
  917. return;
  918. int count = hdr->GetNumSeq();
  919. for ( int i = 0; i < count; i++ )
  920. {
  921. mstudioseqdesc_t &seqdesc = hdr->pSeqdesc( i );
  922. // if it passes the filter, add it
  923. if ( SequencePassesFilter( model, i, seqdesc ) )
  924. {
  925. m_Filtered.AddToTail( i );
  926. }
  927. }
  928. redraw();
  929. }
  930. //-----------------------------------------------------------------------------
  931. // Purpose:
  932. // Output : int
  933. //-----------------------------------------------------------------------------
  934. int AnimationBrowser::GetSequenceCount()
  935. {
  936. return m_Filtered.Count();
  937. }
  938. //-----------------------------------------------------------------------------
  939. // Purpose:
  940. // Input : index -
  941. // Output : mstudioseqdesc_t
  942. //-----------------------------------------------------------------------------
  943. mstudioseqdesc_t *AnimationBrowser::GetSeqDesc( int index )
  944. {
  945. CStudioHdr *hdr = models->GetActiveStudioModel()->GetStudioHdr();
  946. if ( !hdr )
  947. return NULL;
  948. index = TranslateSequenceNumber( index );
  949. if ( index < 0 || index >= hdr->GetNumSeq() )
  950. return NULL;
  951. return &hdr->pSeqdesc( index );
  952. }
  953. int AnimationBrowser::TranslateSequenceNumber( int index )
  954. {
  955. if ( index < 0 || index >= m_Filtered.Count() )
  956. return NULL;
  957. // Lookup the true index
  958. index = m_Filtered[ index ];
  959. return index;
  960. }
  961. void AnimationBrowser::FindCustomFiles( char const *subdir, CUtlVector< FileNameHandle_t >& files )
  962. {
  963. char search[ 512 ];
  964. Q_snprintf( search, sizeof( search ), "%s/*.txt", subdir );
  965. FileFindHandle_t findHandle;
  966. const char *pFileName = filesystem->FindFirst( search, &findHandle );
  967. while( pFileName )
  968. {
  969. if( !filesystem->FindIsDirectory( findHandle ) )
  970. {
  971. // Strip off the 'sound/' part of the name.
  972. char fn[ 512 ];
  973. Q_snprintf( fn, sizeof( fn ), "%s/%s", subdir, pFileName );
  974. FileNameHandle_t fh;
  975. fh = filesystem->FindOrAddFileName( fn );
  976. files.AddToTail( fh );
  977. }
  978. pFileName = filesystem->FindNext( findHandle );
  979. }
  980. filesystem->FindClose( findHandle );
  981. }
  982. void AnimationBrowser::PurgeCustom()
  983. {
  984. for ( int i = 0; i < m_CustomAnimationTabs.Count(); ++i )
  985. {
  986. if ( m_CustomAnimationTabs[ i ]->m_bDirty )
  987. {
  988. m_CustomAnimationTabs[ i ]->SaveToFile();
  989. }
  990. delete m_CustomAnimationTabs[ i ];
  991. }
  992. m_CustomAnimationTabs.Purge();
  993. }
  994. void AnimationBrowser::BuildCustomFromFiles( CUtlVector< FileNameHandle_t >& files )
  995. {
  996. PurgeCustom();
  997. for ( int i = 0; i < files.Count(); ++i )
  998. {
  999. char fn[ 512 ];
  1000. if ( !filesystem->String( files[ i ], fn, sizeof( fn ) ) )
  1001. continue;
  1002. Q_FixSlashes( fn );
  1003. Q_strlower( fn );
  1004. char basename[ 128 ];
  1005. Q_FileBase( fn, basename, sizeof( basename ) );
  1006. CCustomAnim *anim = new CCustomAnim( files[ i ] );
  1007. anim->m_ShortName = basename;
  1008. anim->LoadFromFile();
  1009. m_CustomAnimationTabs.AddToTail( anim );
  1010. }
  1011. UpdateCustomTabs();
  1012. }
  1013. void AnimationBrowser::RenameCustomFile( int index )
  1014. {
  1015. if ( index < 0 || index >= m_CustomAnimationTabs.Count() )
  1016. return;
  1017. CCustomAnim *anim = m_CustomAnimationTabs[ index ];
  1018. CInputParams params;
  1019. memset( &params, 0, sizeof( params ) );
  1020. Q_snprintf( params.m_szDialogTitle, sizeof( params.m_szDialogTitle ), "Custom Animation Group" );
  1021. Q_strcpy( params.m_szPrompt, "Group Name:" );
  1022. Q_strcpy( params.m_szInputText, anim->m_ShortName.String() );
  1023. if ( !InputProperties( &params ) )
  1024. return;
  1025. if ( !params.m_szInputText[ 0 ] )
  1026. return;
  1027. // No change
  1028. if ( !Q_stricmp( anim->m_ShortName.String(), params.m_szInputText ) )
  1029. return;
  1030. char fn[ 512 ];
  1031. if ( !filesystem->String( anim->m_Handle, fn, sizeof( fn ) ) )
  1032. {
  1033. Assert( 0 );
  1034. return;
  1035. }
  1036. StudioModel *model = models->GetActiveStudioModel();
  1037. if ( !model )
  1038. {
  1039. return;
  1040. }
  1041. CStudioHdr *hdr = model->GetStudioHdr();
  1042. if ( !hdr )
  1043. {
  1044. return;
  1045. }
  1046. // Delete the old file
  1047. filesystem->RemoveFile( fn, "MOD" );
  1048. anim->m_ShortName = params.m_szInputText;
  1049. char basename[ 128 ];
  1050. Q_StripExtension( hdr->name(), basename, sizeof( basename ) );
  1051. Q_snprintf( fn, sizeof( fn ), "expressions/%s/animation/%s.txt", basename, params.m_szInputText );
  1052. Q_FixSlashes( fn );
  1053. Q_strlower( fn );
  1054. CreatePath( fn );
  1055. anim->m_Handle = filesystem->FindOrAddFileName( fn );
  1056. anim->m_bDirty = true;
  1057. UpdateCustomTabs();
  1058. }
  1059. void AnimationBrowser::AddCustomFile( const FileNameHandle_t& handle )
  1060. {
  1061. char fn[ 512 ];
  1062. if ( !filesystem->String( handle, fn, sizeof( fn ) ) )
  1063. return;
  1064. Q_FixSlashes( fn );
  1065. Q_strlower( fn );
  1066. char basename[ 128 ];
  1067. Q_FileBase( fn, basename, sizeof( basename ) );
  1068. CCustomAnim *anim = new CCustomAnim( handle );
  1069. anim->m_ShortName = basename;
  1070. anim->LoadFromFile();
  1071. anim->m_bDirty = true;
  1072. if ( m_nCurCell != -1 )
  1073. {
  1074. StudioModel *model = models->GetActiveStudioModel();
  1075. if ( model )
  1076. {
  1077. CStudioHdr *hdr = model->GetStudioHdr();
  1078. if ( hdr )
  1079. {
  1080. mstudioseqdesc_t &seqdesc = hdr->pSeqdesc( m_nCurCell );
  1081. CUtlSymbol sym;
  1082. sym = seqdesc.pszLabel();
  1083. anim->m_Animations.AddToTail( sym );
  1084. }
  1085. }
  1086. }
  1087. m_CustomAnimationTabs.AddToTail( anim );
  1088. UpdateCustomTabs();
  1089. }
  1090. void AnimationBrowser::DeleteCustomFile( int index )
  1091. {
  1092. if ( index < 0 || index >= m_CustomAnimationTabs.Count() )
  1093. return;
  1094. CCustomAnim *anim = m_CustomAnimationTabs[ index ];
  1095. char fn[ 512 ];
  1096. if ( !filesystem->String( anim->m_Handle, fn, sizeof( fn ) ) )
  1097. return;
  1098. m_CustomAnimationTabs.Remove( index );
  1099. filesystem->RemoveFile( fn );
  1100. delete anim;
  1101. UpdateCustomTabs();
  1102. }
  1103. void AnimationBrowser::UpdateCustomTabs()
  1104. {
  1105. m_pFilterTab->UpdateCustomTabs( m_CustomAnimationTabs );
  1106. }
  1107. void AnimationBrowser::OnModelChanged()
  1108. {
  1109. CUtlVector< FileNameHandle_t > files;
  1110. StudioModel *model = models->GetActiveStudioModel();
  1111. if ( model )
  1112. {
  1113. CStudioHdr *hdr = model->GetStudioHdr();
  1114. if ( hdr )
  1115. {
  1116. char subdir[ 512 ];
  1117. char basename[ 512 ];
  1118. Q_StripExtension( hdr->name(), basename, sizeof( basename ) );
  1119. Q_snprintf( subdir, sizeof( subdir ), "expressions/%s/animation", basename );
  1120. Q_FixSlashes( subdir );
  1121. Q_strlower( subdir );
  1122. FindCustomFiles( subdir, files );
  1123. }
  1124. }
  1125. BuildCustomFromFiles( files );
  1126. RestoreThumbnailSize();
  1127. // Just reapply filter
  1128. OnFilter();
  1129. }
  1130. void AnimationBrowser::OnAddCustomAnimationFilter()
  1131. {
  1132. StudioModel *model = models->GetActiveStudioModel();
  1133. if ( !model )
  1134. {
  1135. return;
  1136. }
  1137. CStudioHdr *hdr = model->GetStudioHdr();
  1138. if ( !hdr )
  1139. {
  1140. return;
  1141. }
  1142. CInputParams params;
  1143. memset( &params, 0, sizeof( params ) );
  1144. Q_snprintf( params.m_szDialogTitle, sizeof( params.m_szDialogTitle ), "Custom Animation Group" );
  1145. Q_strcpy( params.m_szPrompt, "Group Name:" );
  1146. Q_strcpy( params.m_szInputText, "" );
  1147. if ( !InputProperties( &params ) )
  1148. return;
  1149. if ( !params.m_szInputText[ 0 ] )
  1150. return;
  1151. if ( FindCustomFile( params.m_szInputText ) != -1 )
  1152. {
  1153. Warning( "Can't add duplicate tab '%s'\n", params.m_szInputText );
  1154. return;
  1155. }
  1156. // Create it
  1157. char fn[ 512 ];
  1158. char basename[ 512 ];
  1159. Q_StripExtension( hdr->name(), basename, sizeof( basename ) );
  1160. Q_snprintf( fn, sizeof( fn ), "expressions/%s/animation/%s.txt", basename, params.m_szInputText );
  1161. Q_FixSlashes( fn );
  1162. Q_strlower( fn );
  1163. CreatePath( fn );
  1164. FileNameHandle_t fh = filesystem->FindOrAddFileName( fn );
  1165. AddCustomFile( fh );
  1166. }
  1167. int AnimationBrowser::FindCustomFile( char const *shortName )
  1168. {
  1169. CUtlSymbol search;
  1170. search = shortName;
  1171. for ( int i = 0; i < m_CustomAnimationTabs.Count(); ++i )
  1172. {
  1173. CCustomAnim *anim = m_CustomAnimationTabs[ i ];
  1174. if ( anim->m_ShortName == search )
  1175. return i;
  1176. }
  1177. return -1;
  1178. }
  1179. void AnimationBrowser::AddAnimationToCustomFile( int index, char const *animationName )
  1180. {
  1181. if ( index < 0 || index >= m_CustomAnimationTabs.Count() )
  1182. return;
  1183. CCustomAnim *anim = m_CustomAnimationTabs[ index ];
  1184. CUtlSymbol search;
  1185. search = animationName;
  1186. if ( anim->m_Animations.Find( search ) == anim->m_Animations.InvalidIndex() )
  1187. {
  1188. anim->m_Animations.AddToTail( search );
  1189. anim->m_bDirty = true;
  1190. }
  1191. OnFilter();
  1192. }
  1193. void AnimationBrowser::RemoveAnimationFromCustomFile( int index, char const *animationName )
  1194. {
  1195. if ( index < 0 || index >= m_CustomAnimationTabs.Count() )
  1196. return;
  1197. CCustomAnim *anim = m_CustomAnimationTabs[ index ];
  1198. CUtlSymbol search;
  1199. search = animationName;
  1200. int slot = anim->m_Animations.Find( search );
  1201. if ( slot != anim->m_Animations.InvalidIndex() )
  1202. {
  1203. anim->m_Animations.Remove( slot );
  1204. anim->m_bDirty = true;
  1205. OnFilter();
  1206. }
  1207. }
  1208. void AnimationBrowser::RemoveAllAnimationsFromCustomFile( int index )
  1209. {
  1210. if ( index < 0 || index >= m_CustomAnimationTabs.Count() )
  1211. return;
  1212. CCustomAnim *anim = m_CustomAnimationTabs[ index ];
  1213. anim->m_Animations.Purge();
  1214. anim->m_bDirty = true;
  1215. OnFilter();
  1216. }