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.

1985 lines
44 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include <stdio.h>
  9. #include "hlfaceposer.h"
  10. #include "GestureTool.h"
  11. #include "mdlviewer.h"
  12. #include "choreowidgetdrawhelper.h"
  13. #include "TimelineItem.h"
  14. #include "expressions.h"
  15. #include "expclass.h"
  16. #include "choreoevent.h"
  17. #include "StudioModel.h"
  18. #include "choreoscene.h"
  19. #include "choreoactor.h"
  20. #include "choreochannel.h"
  21. #include "ChoreoView.h"
  22. #include "InputProperties.h"
  23. #include "ControlPanel.h"
  24. #include "FlexPanel.h"
  25. #include "mxExpressionTray.h"
  26. #include "ExpressionProperties.h"
  27. #include "tier1/strtools.h"
  28. #include "faceposer_models.h"
  29. #include "UtlBuffer.h"
  30. #include "filesystem.h"
  31. #include "iscenetokenprocessor.h"
  32. #include "choreoviewcolors.h"
  33. #include "MatSysWin.h"
  34. GestureTool *g_pGestureTool = 0;
  35. #define TRAY_HEIGHT 20
  36. #define TRAY_ITEM_INSET 10
  37. #define TAG_TOP ( TRAY_HEIGHT + 32 )
  38. #define TAG_BOTTOM ( TAG_TOP + 20 )
  39. #define MAX_TIME_ZOOM 1000
  40. // 10% per step
  41. #define TIME_ZOOM_STEP 2
  42. float SnapTime( float input, float granularity );
  43. GestureTool::GestureTool( mxWindow *parent )
  44. : IFacePoserToolWindow( "GestureTool", "Gesture" ), mxWindow( parent, 0, 0, 0, 0 )
  45. {
  46. m_bSuppressLayout = false;
  47. SetAutoProcess( true );
  48. m_nFocusEventGlobalID = -1;
  49. m_flScrub = 0.0f;
  50. m_flScrubTarget = 0.0f;
  51. m_nDragType = DRAGTYPE_NONE;
  52. m_nClickedX = 0;
  53. m_nClickedY = 0;
  54. m_hPrevCursor = 0;
  55. m_nStartX = 0;
  56. m_nStartY = 0;
  57. m_pLastEvent = NULL;
  58. m_nMousePos[ 0 ] = m_nMousePos[ 1 ] = 0;
  59. m_nMinX = 0;
  60. m_nMaxX = 0;
  61. m_bUseBounds = false;
  62. m_bLayoutIsValid = false;
  63. m_flPixelsPerSecond = 500.0f;
  64. m_flLastDuration = 0.0f;
  65. m_nScrollbarHeight = 12;
  66. m_flLeftOffset = 0.0f;
  67. m_nLastHPixelsNeeded = -1;
  68. m_pHorzScrollBar = new mxScrollbar( this, 0, 0, 18, 100, IDC_GESTUREHSCROLL, mxScrollbar::Horizontal );
  69. m_pHorzScrollBar->setVisible( false );
  70. m_bInSetEvent = false;
  71. m_flScrubberTimeOffset = 0.0f;
  72. }
  73. GestureTool::~GestureTool( void )
  74. {
  75. }
  76. void GestureTool::SetEvent( CChoreoEvent *event )
  77. {
  78. if ( m_bInSetEvent )
  79. return;
  80. m_bInSetEvent = true;
  81. if ( event == m_pLastEvent )
  82. {
  83. if ( event )
  84. {
  85. if ( event->GetDuration() != m_flLastDuration )
  86. {
  87. m_flLastDuration = event->GetDuration();
  88. m_nLastHPixelsNeeded = -1;
  89. m_flLeftOffset = 0.0f;
  90. InvalidateLayout();
  91. }
  92. m_nFocusEventGlobalID = event->GetGlobalID();
  93. }
  94. m_bInSetEvent = false;
  95. return;
  96. }
  97. m_pLastEvent = event;
  98. m_nFocusEventGlobalID = -1;
  99. if ( event )
  100. {
  101. m_nFocusEventGlobalID = event->GetGlobalID();
  102. }
  103. if ( event )
  104. {
  105. m_flLastDuration = event->GetDuration();
  106. }
  107. else
  108. {
  109. m_flLastDuration = 0.0f;
  110. }
  111. m_flLeftOffset = 0.0f;
  112. m_nLastHPixelsNeeded = -1;
  113. InvalidateLayout();
  114. m_bInSetEvent = false;
  115. }
  116. //-----------------------------------------------------------------------------
  117. // Purpose:
  118. //-----------------------------------------------------------------------------
  119. CChoreoEvent *GestureTool::GetSafeEvent( void )
  120. {
  121. if ( m_nFocusEventGlobalID == -1 )
  122. return NULL;
  123. if ( !g_pChoreoView )
  124. return NULL;
  125. CChoreoScene *scene = g_pChoreoView->GetScene();
  126. if ( !scene )
  127. return NULL;
  128. // Find event by name
  129. for ( int i = 0; i < scene->GetNumEvents() ; i++ )
  130. {
  131. CChoreoEvent *e = scene->GetEvent( i );
  132. if ( !e || e->GetType() != CChoreoEvent::GESTURE )
  133. continue;
  134. if ( e->GetGlobalID() == m_nFocusEventGlobalID )
  135. {
  136. return e;
  137. }
  138. }
  139. return NULL;
  140. }
  141. //-----------------------------------------------------------------------------
  142. // Purpose:
  143. // Input : rcHandle -
  144. //-----------------------------------------------------------------------------
  145. void GestureTool::GetScrubHandleRect( RECT& rcHandle, float scrub, bool clipped )
  146. {
  147. float pixel = 0.0f;
  148. if ( w2() > 0 )
  149. {
  150. pixel = GetPixelForTimeValue( scrub );
  151. if ( clipped )
  152. {
  153. pixel = clamp( pixel, SCRUBBER_HANDLE_WIDTH / 2, w2() - SCRUBBER_HANDLE_WIDTH / 2 );
  154. }
  155. }
  156. rcHandle.left = pixel- SCRUBBER_HANDLE_WIDTH / 2;
  157. rcHandle.right = pixel + SCRUBBER_HANDLE_WIDTH / 2;
  158. rcHandle.top = 2 + GetCaptionHeight();
  159. rcHandle.bottom = rcHandle.top + SCRUBBER_HANDLE_HEIGHT;
  160. }
  161. void GestureTool::GetScrubHandleReferenceRect( RECT& rcHandle, float scrub, bool clipped /*= false*/ )
  162. {
  163. float pixel = 0.0f;
  164. if ( w2() > 0 )
  165. {
  166. pixel = GetPixelForTimeValue( scrub );
  167. if ( clipped )
  168. {
  169. pixel = clamp( pixel, SCRUBBER_HANDLE_WIDTH/2, w2() - SCRUBBER_HANDLE_WIDTH/2 );
  170. }
  171. }
  172. rcHandle.left = pixel-SCRUBBER_HANDLE_WIDTH/2;
  173. rcHandle.right = pixel + SCRUBBER_HANDLE_WIDTH/2;
  174. rcHandle.top = 2 + GetCaptionHeight() + 195;
  175. rcHandle.bottom = rcHandle.top + SCRUBBER_HANDLE_HEIGHT;
  176. }
  177. //-----------------------------------------------------------------------------
  178. // Purpose:
  179. // Input : drawHelper -
  180. // rcHandle -
  181. //-----------------------------------------------------------------------------
  182. void GestureTool::DrawScrubHandle( CChoreoWidgetDrawHelper& drawHelper, RECT& rcHandle, float scrub, bool reference )
  183. {
  184. HBRUSH br = CreateSolidBrush( reference ? RGB( 150, 0, 0 ) : RGB( 0, 150, 100 ) );
  185. COLORREF areaBorder = RGB( 230, 230, 220 );
  186. drawHelper.DrawColoredLine( areaBorder,
  187. PS_SOLID, 1, 0, rcHandle.top, w2(), rcHandle.top );
  188. drawHelper.DrawColoredLine( areaBorder,
  189. PS_SOLID, 1, 0, rcHandle.bottom, w2(), rcHandle.bottom );
  190. drawHelper.DrawFilledRect( br, rcHandle );
  191. //
  192. char sz[ 32 ];
  193. sprintf( sz, "%.3f", scrub );
  194. CChoreoEvent *ev = GetSafeEvent();
  195. if ( ev )
  196. {
  197. float st, ed;
  198. st = ev->GetStartTime();
  199. ed = ev->GetEndTime();
  200. float dt = ed - st;
  201. if ( dt > 0.0f )
  202. {
  203. sprintf( sz, "%.3f", st + scrub );
  204. }
  205. }
  206. int len = drawHelper.CalcTextWidth( "Arial", 9, 500, sz );
  207. RECT rcText = rcHandle;
  208. int textw = rcText.right - rcText.left;
  209. rcText.left += ( textw - len ) / 2;
  210. drawHelper.DrawColoredText( "Arial", 9, 500, RGB( 255, 255, 255 ), rcText, sz );
  211. DeleteObject( br );
  212. }
  213. //-----------------------------------------------------------------------------
  214. // Purpose:
  215. // Input : *event -
  216. // Output : Returns true on success, false on failure.
  217. //-----------------------------------------------------------------------------
  218. bool GestureTool::IsMouseOverScrubHandle( mxEvent *event )
  219. {
  220. RECT rcHandle;
  221. GetScrubHandleRect( rcHandle, m_flScrub, true );
  222. InflateRect( &rcHandle, 2, 2 );
  223. POINT pt;
  224. pt.x = (short)event->x;
  225. pt.y = (short)event->y;
  226. if ( PtInRect( &rcHandle, pt ) )
  227. {
  228. return true;
  229. }
  230. return false;
  231. }
  232. //-----------------------------------------------------------------------------
  233. // Purpose:
  234. // Output : Returns true on success, false on failure.
  235. //-----------------------------------------------------------------------------
  236. bool GestureTool::IsProcessing( void )
  237. {
  238. if ( !GetSafeEvent() )
  239. return false;
  240. if ( m_flScrub != m_flScrubTarget )
  241. return true;
  242. return false;
  243. }
  244. bool GestureTool::IsScrubbing( void ) const
  245. {
  246. bool scrubbing = ( m_nDragType == DRAGTYPE_SCRUBBER ) ? true : false;
  247. return scrubbing;
  248. }
  249. void GestureTool::SetScrubTime( float t )
  250. {
  251. m_flScrub = t;
  252. CChoreoEvent *e = GetSafeEvent();
  253. if ( e && e->GetDuration() )
  254. {
  255. float realtime = e->GetStartTime() + m_flScrub;
  256. g_pChoreoView->SetScrubTime( realtime );
  257. g_pChoreoView->DrawScrubHandle();
  258. }
  259. }
  260. void GestureTool::SetScrubTargetTime( float t )
  261. {
  262. m_flScrubTarget = t;
  263. CChoreoEvent *e = GetSafeEvent();
  264. if ( e && e->GetDuration() )
  265. {
  266. float realtime = e->GetStartTime() + m_flScrubTarget;
  267. g_pChoreoView->SetScrubTargetTime( realtime );
  268. }
  269. }
  270. //-----------------------------------------------------------------------------
  271. // Purpose:
  272. // Input : dt -
  273. //-----------------------------------------------------------------------------
  274. void GestureTool::Think( float dt )
  275. {
  276. CChoreoEvent *event = GetSafeEvent();
  277. if ( !event )
  278. return;
  279. bool scrubbing = IsScrubbing();
  280. ScrubThink( dt, scrubbing );
  281. }
  282. //-----------------------------------------------------------------------------
  283. // Purpose:
  284. // Input : dt -
  285. //-----------------------------------------------------------------------------
  286. void GestureTool::ScrubThink( float dt, bool scrubbing )
  287. {
  288. CChoreoEvent *event = GetSafeEvent();
  289. if ( !event )
  290. return;
  291. if ( m_flScrubTarget == m_flScrub && !scrubbing )
  292. return;
  293. float d = m_flScrubTarget - m_flScrub;
  294. int sign = d > 0.0f ? 1 : -1;
  295. float maxmove = dt;
  296. if ( sign > 0 )
  297. {
  298. if ( d < maxmove )
  299. {
  300. SetScrubTime( m_flScrubTarget );
  301. }
  302. else
  303. {
  304. SetScrubTime( m_flScrub + maxmove );
  305. }
  306. }
  307. else
  308. {
  309. if ( -d < maxmove )
  310. {
  311. SetScrubTime( m_flScrubTarget );
  312. }
  313. else
  314. {
  315. SetScrubTime( m_flScrub - maxmove );
  316. }
  317. }
  318. if ( scrubbing )
  319. {
  320. g_pMatSysWindow->Frame();
  321. }
  322. }
  323. void GestureTool::DrawScrubHandles()
  324. {
  325. RECT rcTray;
  326. RECT rcHandle;
  327. GetScrubHandleRect( rcHandle, m_flScrub, true );
  328. rcTray = rcHandle;
  329. rcTray.left = 0;
  330. rcTray.right = w2();
  331. CChoreoWidgetDrawHelper drawHelper( this, rcTray );
  332. DrawScrubHandle( drawHelper, rcHandle, m_flScrub, false );
  333. CChoreoEvent *ev = GetSafeEvent();
  334. if ( ev && ev->GetDuration() > 0.0f )
  335. {
  336. float scrub = ev->GetOriginalPercentageFromPlaybackPercentage( m_flScrub / ev->GetDuration() ) * ev->GetDuration();
  337. GetScrubHandleReferenceRect( rcHandle, scrub, true );
  338. rcTray = rcHandle;
  339. rcTray.left = 0;
  340. rcTray.right = w2();
  341. CChoreoWidgetDrawHelper drawHelper( this, rcTray );
  342. DrawScrubHandle( drawHelper, rcHandle, scrub, true );
  343. }
  344. }
  345. void GestureTool::redraw()
  346. {
  347. if ( !ToolCanDraw() )
  348. return;
  349. CChoreoWidgetDrawHelper drawHelper( this );
  350. HandleToolRedraw( drawHelper );
  351. RECT rc;
  352. drawHelper.GetClientRect( rc );
  353. CChoreoEvent *ev = GetSafeEvent();
  354. if ( ev )
  355. {
  356. RECT rcText;
  357. drawHelper.GetClientRect( rcText );
  358. rcText.top += GetCaptionHeight()+1;
  359. rcText.bottom = rcText.top + 13;
  360. rcText.left += 5;
  361. rcText.right -= 5;
  362. OffsetRect( &rcText, 0, 12 );
  363. int current, total;
  364. g_pChoreoView->GetUndoLevels( current, total );
  365. if ( total > 0 )
  366. {
  367. RECT rcUndo = rcText;
  368. OffsetRect( &rcUndo, 0, 2 );
  369. drawHelper.DrawColoredText( "Small Fonts", 8, FW_NORMAL, RGB( 0, 100, 0 ), rcUndo,
  370. "Undo: %i/%i", current, total );
  371. }
  372. rcText.left += 60;
  373. // Found it, write out description
  374. //
  375. float seqduration;
  376. ev->GetGestureSequenceDuration( seqduration );
  377. RECT rcTextLine = rcText;
  378. drawHelper.DrawColoredText( "Arial", 11, 900, RGB( 200, 0, 0 ), rcTextLine,
  379. "Event: %s",
  380. ev->GetName() );
  381. OffsetRect( &rcTextLine, 0, 12 );
  382. drawHelper.DrawColoredText( "Arial", 11, 900, RGB( 200, 0, 0 ), rcTextLine,
  383. "Sequence: '%s' %.3f s.",
  384. ev->GetParameters(),
  385. seqduration );
  386. RECT rcTimeLine;
  387. drawHelper.GetClientRect( rcTimeLine );
  388. rcTimeLine.left = 0;
  389. rcTimeLine.right = w2();
  390. rcTimeLine.top += ( GetCaptionHeight() + 70 );
  391. float lefttime = GetTimeValueForMouse( 0 );
  392. float righttime = GetTimeValueForMouse( w2() );
  393. DrawTimeLine( drawHelper, rcTimeLine, lefttime, righttime );
  394. OffsetRect( &rcText, 0, 30 );
  395. rcText.left = 5;
  396. RECT timeRect = rcText;
  397. timeRect.right = timeRect.left + 100;
  398. char sz[ 32 ];
  399. Q_snprintf( sz, sizeof( sz ), "%.2f", lefttime + ev->GetStartTime() );
  400. drawHelper.DrawColoredText( "Arial", 9, FW_NORMAL, RGB( 0, 0, 0 ), timeRect, sz );
  401. timeRect = rcText;
  402. Q_snprintf( sz, sizeof( sz ), "%.2f", righttime + ev->GetStartTime() );
  403. int textW = drawHelper.CalcTextWidth( "Arial", 9, FW_NORMAL, sz );
  404. timeRect.right = w2() - 10;
  405. timeRect.left = timeRect.right - textW;
  406. drawHelper.DrawColoredText( "Arial", 9, FW_NORMAL, RGB( 0, 0, 0 ), timeRect, sz );
  407. }
  408. RECT rcHandle;
  409. GetScrubHandleRect( rcHandle, m_flScrub, true );
  410. DrawScrubHandle( drawHelper, rcHandle, m_flScrub, false );
  411. DrawEventEnd( drawHelper );
  412. if ( ev && ev->GetDuration() > 0.0f )
  413. {
  414. float scrub = ev->GetOriginalPercentageFromPlaybackPercentage( m_flScrub / ev->GetDuration() ) * ev->GetDuration();
  415. GetScrubHandleReferenceRect( rcHandle, scrub, true );
  416. DrawScrubHandle( drawHelper, rcHandle, scrub, true );
  417. }
  418. RECT rcTags = rc;
  419. rcTags.top = TAG_TOP + GetCaptionHeight();
  420. rcTags.bottom = TAG_BOTTOM + GetCaptionHeight();
  421. DrawRelativeTags( drawHelper, rcTags );
  422. DrawAbsoluteTags( drawHelper );
  423. RECT rcPos;
  424. GetMouseOverPosRect( rcPos );
  425. DrawMouseOverPos( drawHelper, rcPos );
  426. }
  427. //-----------------------------------------------------------------------------
  428. // Purpose:
  429. //-----------------------------------------------------------------------------
  430. void GestureTool::ShowContextMenu( mxEvent *event, bool include_track_menus )
  431. {
  432. // Construct main menu
  433. mxPopupMenu *pop = new mxPopupMenu();
  434. int current, total;
  435. g_pChoreoView->GetUndoLevels( current, total );
  436. if ( total > 0 )
  437. {
  438. if ( current > 0 )
  439. {
  440. pop->add( va( "Undo %s", g_pChoreoView->GetUndoDescription() ), IDC_UNDO_GT );
  441. }
  442. if ( current <= total - 1 )
  443. {
  444. pop->add( va( "Redo %s", g_pChoreoView->GetRedoDescription() ), IDC_REDO_GT );
  445. }
  446. pop->addSeparator();
  447. }
  448. CEventAbsoluteTag *tag = IsMouseOverTag( (short)event->x, (short)event->y );
  449. if ( tag )
  450. {
  451. pop->add( va( "Delete '%s'...", tag->GetName() ), IDC_GT_DELETE_TAG );
  452. }
  453. else
  454. {
  455. pop->add( "Insert Tag...", IDC_GT_INSERT_TAG );
  456. }
  457. pop->add( "Revert Tag Timings", IDC_GT_REVERT );
  458. pop->add( va( "Change scale..." ), IDC_GT_CHANGESCALE );
  459. pop->popup( this, (short)event->x, (short)event->y );
  460. }
  461. void GestureTool::GetWorkspaceLeftRight( int& left, int& right )
  462. {
  463. left = 0;
  464. right = w2();
  465. }
  466. //-----------------------------------------------------------------------------
  467. // Purpose:
  468. //-----------------------------------------------------------------------------
  469. void GestureTool::DrawFocusRect( void )
  470. {
  471. HDC dc = GetDC( NULL );
  472. for ( int i = 0; i < m_FocusRects.Size(); i++ )
  473. {
  474. RECT rc = m_FocusRects[ i ].m_rcFocus;
  475. ::DrawFocusRect( dc, &rc );
  476. }
  477. ReleaseDC( NULL, dc );
  478. }
  479. void GestureTool::SetClickedPos( int x, int y )
  480. {
  481. m_nClickedX = x;
  482. m_nClickedY = y;
  483. }
  484. float GestureTool::GetTimeForClickedPos( void )
  485. {
  486. CChoreoEvent *e = GetSafeEvent();
  487. if ( !e )
  488. return 0.0f;
  489. float t = GetTimeValueForMouse( m_nClickedX );
  490. return t;
  491. }
  492. //-----------------------------------------------------------------------------
  493. // Purpose:
  494. // Input : dragtype -
  495. // startx -
  496. // cursor -
  497. //-----------------------------------------------------------------------------
  498. void GestureTool::StartDragging( int dragtype, int startx, int starty, HCURSOR cursor )
  499. {
  500. m_nDragType = dragtype;
  501. m_nStartX = startx;
  502. m_nLastX = startx;
  503. m_nStartY = starty;
  504. m_nLastY = starty;
  505. if ( m_hPrevCursor )
  506. {
  507. SetCursor( m_hPrevCursor );
  508. m_hPrevCursor = NULL;
  509. }
  510. m_hPrevCursor = SetCursor( cursor );
  511. m_FocusRects.Purge();
  512. RECT rcStart;
  513. rcStart.left = startx;
  514. rcStart.right = startx;
  515. bool addrect = true;
  516. switch ( dragtype )
  517. {
  518. default:
  519. case DRAGTYPE_SCRUBBER:
  520. {
  521. RECT rcScrub;
  522. GetScrubHandleRect( rcScrub, m_flScrub, true );
  523. rcStart = rcScrub;
  524. rcStart.left = ( rcScrub.left + rcScrub.right ) / 2;
  525. rcStart.right = rcStart.left;
  526. rcStart.top = rcScrub.bottom;
  527. rcStart.bottom = h2();
  528. }
  529. break;
  530. case DRAGTYPE_ABSOLUTE_TIMING_TAG:
  531. {
  532. rcStart.top = 0;
  533. rcStart.bottom = h2();
  534. }
  535. break;
  536. }
  537. if ( addrect )
  538. {
  539. AddFocusRect( rcStart );
  540. }
  541. DrawFocusRect();
  542. }
  543. void GestureTool::OnMouseMove( mxEvent *event )
  544. {
  545. int mx = (short)event->x;
  546. int my = (short)event->y;
  547. event->x = (short)mx;
  548. if ( m_nDragType != DRAGTYPE_NONE )
  549. {
  550. DrawFocusRect();
  551. for ( int i = 0; i < m_FocusRects.Size(); i++ )
  552. {
  553. CFocusRect *f = &m_FocusRects[ i ];
  554. f->m_rcFocus = f->m_rcOrig;
  555. switch ( m_nDragType )
  556. {
  557. default:
  558. case DRAGTYPE_SCRUBBER:
  559. {
  560. ApplyBounds( mx, my );
  561. if ( w2() > 0 )
  562. {
  563. float t = GetTimeValueForMouse( mx );
  564. t += m_flScrubberTimeOffset;
  565. ForceScrubPosition( t );
  566. }
  567. }
  568. break;
  569. case DRAGTYPE_ABSOLUTE_TIMING_TAG:
  570. {
  571. ApplyBounds( mx, my );
  572. }
  573. break;
  574. }
  575. OffsetRect( &f->m_rcFocus, ( mx - m_nStartX ), 0 );
  576. }
  577. DrawFocusRect();
  578. }
  579. else
  580. {
  581. if ( m_hPrevCursor )
  582. {
  583. SetCursor( m_hPrevCursor );
  584. m_hPrevCursor = NULL;
  585. }
  586. if ( IsMouseOverScrubHandle( event ) )
  587. {
  588. m_hPrevCursor = SetCursor( LoadCursor( NULL, IDC_SIZEWE ) );
  589. }
  590. else if ( IsMouseOverTag( mx, my ) )
  591. {
  592. m_hPrevCursor = SetCursor( LoadCursor( NULL, IDC_SIZEWE ) );
  593. }
  594. }
  595. m_nLastX = (short)event->x;
  596. m_nLastY = (short)event->y;
  597. }
  598. int GestureTool::handleEvent( mxEvent *event )
  599. {
  600. MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
  601. int iret = 0;
  602. if ( HandleToolEvent( event ) )
  603. {
  604. return iret;
  605. }
  606. switch ( event->event )
  607. {
  608. case mxEvent::Size:
  609. {
  610. int w, h;
  611. w = event->width;
  612. h = event->height;
  613. m_nLastHPixelsNeeded = 0;
  614. InvalidateLayout();
  615. iret = 1;
  616. }
  617. break;
  618. case mxEvent::MouseWheeled:
  619. {
  620. CChoreoScene *scene = g_pChoreoView->GetScene();
  621. if ( scene )
  622. {
  623. int tz = g_pChoreoView->GetTimeZoom( GetToolName() );
  624. bool shiftdown = ( event->modifiers & mxEvent::KeyShift ) ? true : false;
  625. int stepMultipiler = shiftdown ? 5 : 1;
  626. // Zoom time in / out
  627. if ( event->height > 0 )
  628. {
  629. tz = min( tz + TIME_ZOOM_STEP * stepMultipiler, MAX_TIME_ZOOM );
  630. }
  631. else
  632. {
  633. tz = max( tz - TIME_ZOOM_STEP * stepMultipiler, TIME_ZOOM_STEP );
  634. }
  635. g_pChoreoView->SetPreservedTimeZoom( this, tz );
  636. }
  637. RepositionHSlider();
  638. redraw();
  639. iret = 1;
  640. }
  641. break;
  642. case mxEvent::MouseDown:
  643. {
  644. iret = 1;
  645. int mx = (short)event->x;
  646. int my = (short)event->y;
  647. SetClickedPos( mx, my );
  648. SetMouseOverPos( mx, my );
  649. DrawMouseOverPos();
  650. if ( event->buttons & mxEvent::MouseRightButton )
  651. {
  652. ShowContextMenu( event, false );
  653. return iret;
  654. }
  655. if ( m_nDragType == DRAGTYPE_NONE )
  656. {
  657. if ( IsMouseOverScrubHandle( event ) )
  658. {
  659. if ( w2() > 0 )
  660. {
  661. float t = GetTimeValueForMouse( (short)event->x );
  662. m_flScrubberTimeOffset = m_flScrub - t;
  663. float maxoffset = 0.5f * (float)SCRUBBER_HANDLE_WIDTH / GetPixelsPerSecond();
  664. m_flScrubberTimeOffset = clamp( m_flScrubberTimeOffset, -maxoffset, maxoffset );
  665. t += m_flScrubberTimeOffset;
  666. ForceScrubPosition( t );
  667. }
  668. StartDragging( DRAGTYPE_SCRUBBER, m_nClickedX, m_nClickedY, LoadCursor( NULL, IDC_SIZEWE ) );
  669. }
  670. else if ( IsMouseOverTag( mx, my ) )
  671. {
  672. StartDragging( DRAGTYPE_ABSOLUTE_TIMING_TAG, m_nClickedX, m_nClickedY, LoadCursor( NULL, IDC_SIZEWE ) );
  673. }
  674. else
  675. {
  676. if ( w2() > 0 )
  677. {
  678. float t = GetTimeValueForMouse( (short)event->x );
  679. SetScrubTargetTime( t );
  680. }
  681. }
  682. CalcBounds( m_nDragType );
  683. }
  684. }
  685. break;
  686. case mxEvent::MouseDrag:
  687. case mxEvent::MouseMove:
  688. {
  689. int mx = (short)event->x;
  690. int my = (short)event->y;
  691. SetMouseOverPos( mx, my );
  692. DrawMouseOverPos();
  693. OnMouseMove( event );
  694. iret = 1;
  695. }
  696. break;
  697. case mxEvent::MouseUp:
  698. {
  699. if ( event->buttons & mxEvent::MouseRightButton )
  700. {
  701. return 1;
  702. }
  703. int mx = (short)event->x;
  704. int my = (short)event->y;
  705. if ( m_nDragType != DRAGTYPE_NONE )
  706. {
  707. DrawFocusRect();
  708. }
  709. if ( m_hPrevCursor )
  710. {
  711. SetCursor( m_hPrevCursor );
  712. m_hPrevCursor = 0;
  713. }
  714. switch ( m_nDragType )
  715. {
  716. case DRAGTYPE_NONE:
  717. break;
  718. case DRAGTYPE_SCRUBBER:
  719. {
  720. ApplyBounds( mx, my );
  721. if ( w2() > 0 )
  722. {
  723. float t = GetTimeValueForMouse( (short)event->x );
  724. t += m_flScrubberTimeOffset;
  725. ForceScrubPosition( t );
  726. m_flScrubberTimeOffset = 0.0f;
  727. }
  728. }
  729. break;
  730. case DRAGTYPE_ABSOLUTE_TIMING_TAG:
  731. {
  732. ApplyBounds( mx, my );
  733. CEventAbsoluteTag *tag = IsMouseOverTag( m_nClickedX, m_nClickedY );
  734. if ( tag && w2() && GetSafeEvent() )
  735. {
  736. float t = GetTimeValueForMouse( mx );
  737. float lastfrac = t / GetSafeEvent()->GetDuration();
  738. lastfrac = clamp( lastfrac, 0.0f, 1.0f );
  739. g_pChoreoView->SetDirty( true );
  740. g_pChoreoView->PushUndo( "move absolute tag" );
  741. tag->SetPercentage( lastfrac );
  742. g_pChoreoView->PushRedo( "move absolute tag" );
  743. g_pChoreoView->InvalidateLayout();
  744. redraw();
  745. }
  746. }
  747. break;
  748. }
  749. m_nDragType = DRAGTYPE_NONE;
  750. SetMouseOverPos( mx, my );
  751. DrawMouseOverPos();
  752. iret = 1;
  753. }
  754. break;
  755. case mxEvent::KeyDown:
  756. {
  757. iret = g_pChoreoView->HandleZoomKey( this, event->key );
  758. }
  759. break;
  760. case mxEvent::Action:
  761. {
  762. iret = 1;
  763. switch ( event->action )
  764. {
  765. default:
  766. iret = 0;
  767. break;
  768. case IDC_UNDO_GT:
  769. OnUndo();
  770. break;
  771. case IDC_REDO_GT:
  772. OnRedo();
  773. break;
  774. case IDC_GT_DELETE_TAG:
  775. OnDeleteTag();
  776. break;
  777. case IDC_GT_INSERT_TAG:
  778. OnInsertTag();
  779. break;
  780. case IDC_GT_REVERT:
  781. OnRevert();
  782. break;
  783. case IDC_GESTUREHSCROLL:
  784. {
  785. int offset = 0;
  786. bool processed = true;
  787. switch ( event->modifiers )
  788. {
  789. case SB_THUMBTRACK:
  790. offset = event->height;
  791. break;
  792. case SB_PAGEUP:
  793. offset = m_pHorzScrollBar->getValue();
  794. offset -= 20;
  795. offset = max( offset, m_pHorzScrollBar->getMinValue() );
  796. break;
  797. case SB_PAGEDOWN:
  798. offset = m_pHorzScrollBar->getValue();
  799. offset += 20;
  800. offset = min( offset, m_pHorzScrollBar->getMaxValue() );
  801. break;
  802. case SB_LINEUP:
  803. offset = m_pHorzScrollBar->getValue();
  804. offset -= 10;
  805. offset = max( offset, m_pHorzScrollBar->getMinValue() );
  806. break;
  807. case SB_LINEDOWN:
  808. offset = m_pHorzScrollBar->getValue();
  809. offset += 10;
  810. offset = min( offset, m_pHorzScrollBar->getMaxValue() );
  811. break;
  812. default:
  813. processed = false;
  814. break;
  815. }
  816. if ( processed )
  817. {
  818. MoveTimeSliderToPos( offset );
  819. }
  820. }
  821. break;
  822. case IDC_GT_CHANGESCALE:
  823. {
  824. OnChangeScale();
  825. }
  826. break;
  827. }
  828. }
  829. break;
  830. }
  831. return iret;
  832. }
  833. void GestureTool::ApplyBounds( int& mx, int& my )
  834. {
  835. if ( !m_bUseBounds )
  836. return;
  837. mx = clamp( mx, m_nMinX, m_nMaxX );
  838. }
  839. int GestureTool::GetTagTypeForTag( CEventAbsoluteTag const *tag )
  840. {
  841. CChoreoEvent *e = GetSafeEvent();
  842. if ( !e )
  843. return -1;
  844. for ( int t = 0; t < CChoreoEvent::NUM_ABS_TAG_TYPES; t++ )
  845. {
  846. CChoreoEvent::AbsTagType tagtype = (CChoreoEvent::AbsTagType)t;
  847. for ( int i = 0; i < e->GetNumAbsoluteTags( tagtype ); i++ )
  848. {
  849. CEventAbsoluteTag *ptag = e->GetAbsoluteTag( tagtype, i );
  850. Assert( ptag );
  851. if ( ptag == tag )
  852. return t;
  853. }
  854. }
  855. return -1;
  856. }
  857. void GestureTool::CalcBounds( int movetype )
  858. {
  859. switch ( movetype )
  860. {
  861. default:
  862. case DRAGTYPE_NONE:
  863. {
  864. m_bUseBounds = false;
  865. m_nMinX = 0;
  866. m_nMaxX = 0;
  867. }
  868. break;
  869. case DRAGTYPE_SCRUBBER:
  870. {
  871. m_bUseBounds = true;
  872. m_nMinX = 0;
  873. m_nMaxX = w2();
  874. }
  875. break;
  876. case DRAGTYPE_ABSOLUTE_TIMING_TAG:
  877. {
  878. m_bUseBounds = true;
  879. m_nMinX = 0;
  880. m_nMaxX = w2();
  881. CChoreoEvent *e = GetSafeEvent();
  882. CEventAbsoluteTag *tag = IsMouseOverTag( m_nClickedX, m_nClickedY );
  883. if ( tag && e && e->GetDuration() )
  884. {
  885. m_nMinX = GetPixelForTimeValue( 0 );
  886. m_nMaxX = max( w2(), GetPixelForTimeValue( e->GetDuration() ) );
  887. int t = GetTagTypeForTag( tag );
  888. if ( t != -1 )
  889. {
  890. CChoreoEvent::AbsTagType tagtype = (CChoreoEvent::AbsTagType)t;
  891. CEventAbsoluteTag *prevTag = NULL, *nextTag = NULL;
  892. int c = e->GetNumAbsoluteTags( tagtype );
  893. int i;
  894. for ( i = 0; i < c; i++ )
  895. {
  896. CEventAbsoluteTag *t = e->GetAbsoluteTag( tagtype, i );
  897. Assert( t );
  898. if ( t == tag )
  899. {
  900. prevTag = i > 0 ? e->GetAbsoluteTag( tagtype, i-1 ) : NULL;
  901. nextTag = i < c - 1 ? e->GetAbsoluteTag( tagtype, i+1 ) : NULL;
  902. break;
  903. }
  904. }
  905. if ( i < c )
  906. {
  907. if ( prevTag )
  908. {
  909. m_nMinX = GetPixelForTimeValue( prevTag->GetPercentage() * e->GetDuration() ) + 1;
  910. }
  911. if ( nextTag )
  912. {
  913. m_nMaxX = GetPixelForTimeValue( nextTag->GetPercentage() * e->GetDuration() ) - 1;
  914. }
  915. }
  916. else
  917. {
  918. Assert( 0 );
  919. }
  920. }
  921. }
  922. }
  923. break;
  924. }
  925. }
  926. bool GestureTool::PaintBackground()
  927. {
  928. redraw();
  929. return false;
  930. }
  931. void GestureTool::OnUndo( void )
  932. {
  933. g_pChoreoView->Undo();
  934. }
  935. void GestureTool::OnRedo( void )
  936. {
  937. g_pChoreoView->Redo();
  938. }
  939. void GestureTool::ForceScrubPositionFromSceneTime( float scenetime )
  940. {
  941. CChoreoEvent *e = GetSafeEvent();
  942. if ( !e || !e->GetDuration() )
  943. return;
  944. float t = scenetime - e->GetStartTime();
  945. m_flScrub = t;
  946. m_flScrubTarget = t;
  947. DrawScrubHandles();
  948. }
  949. void GestureTool::ForceScrubPosition( float t )
  950. {
  951. m_flScrub = t;
  952. m_flScrubTarget = t;
  953. CChoreoEvent *e = GetSafeEvent();
  954. if ( e && e->GetDuration() )
  955. {
  956. float realtime = e->GetStartTime() + t;
  957. g_pChoreoView->SetScrubTime( realtime );
  958. g_pChoreoView->SetScrubTargetTime( realtime );
  959. g_pChoreoView->DrawScrubHandle();
  960. }
  961. DrawScrubHandles();
  962. }
  963. void GestureTool::SetMouseOverPos( int x, int y )
  964. {
  965. m_nMousePos[ 0 ] = x;
  966. m_nMousePos[ 1 ] = y;
  967. }
  968. void GestureTool::GetMouseOverPos( int &x, int& y )
  969. {
  970. x = m_nMousePos[ 0 ];
  971. y = m_nMousePos[ 1 ];
  972. }
  973. //-----------------------------------------------------------------------------
  974. // Purpose:
  975. // Input : rcPos -
  976. //-----------------------------------------------------------------------------
  977. void GestureTool::GetMouseOverPosRect( RECT& rcPos )
  978. {
  979. rcPos.top = GetCaptionHeight() + 12;
  980. rcPos.left = w2() - 200;
  981. rcPos.right = w2() - 5;
  982. rcPos.bottom = rcPos.top + 13;
  983. }
  984. //-----------------------------------------------------------------------------
  985. // Purpose:
  986. // Input : drawHelper -
  987. // rcPos -
  988. //-----------------------------------------------------------------------------
  989. void GestureTool::DrawMouseOverPos( CChoreoWidgetDrawHelper& drawHelper, RECT& rcPos )
  990. {
  991. // Compute time for pixel x
  992. float t = GetTimeValueForMouse( m_nMousePos[ 0 ] );
  993. CChoreoEvent *e = GetSafeEvent();
  994. if ( !e )
  995. return;
  996. t += e->GetStartTime();
  997. float snapped = FacePoser_SnapTime( t );
  998. // Found it, write out description
  999. //
  1000. char sz[ 128 ];
  1001. if ( t != snapped )
  1002. {
  1003. Q_snprintf( sz, sizeof( sz ), "%s", FacePoser_DescribeSnappedTime( t ) );
  1004. }
  1005. else
  1006. {
  1007. Q_snprintf( sz, sizeof( sz ), "%.3f", t );
  1008. }
  1009. int len = drawHelper.CalcTextWidth( "Arial", 11, 900, sz );
  1010. RECT rcText = rcPos;
  1011. rcText.left = max( rcPos.left, rcPos.right - len );
  1012. drawHelper.DrawColoredText( "Arial", 11, 900, RGB( 255, 50, 70 ), rcText, sz );
  1013. }
  1014. //-----------------------------------------------------------------------------
  1015. // Purpose:
  1016. //-----------------------------------------------------------------------------
  1017. void GestureTool::DrawMouseOverPos()
  1018. {
  1019. RECT rcPos;
  1020. GetMouseOverPosRect( rcPos );
  1021. CChoreoWidgetDrawHelper drawHelper( this, rcPos );
  1022. DrawMouseOverPos( drawHelper, rcPos );
  1023. }
  1024. void GestureTool::AddFocusRect( RECT& rc )
  1025. {
  1026. RECT rcFocus = rc;
  1027. POINT offset;
  1028. offset.x = 0;
  1029. offset.y = 0;
  1030. ClientToScreen( (HWND)getHandle(), &offset );
  1031. OffsetRect( &rcFocus, offset.x, offset.y );
  1032. // Convert to screen space?
  1033. CFocusRect fr;
  1034. fr.m_rcFocus = rcFocus;
  1035. fr.m_rcOrig = rcFocus;
  1036. m_FocusRects.AddToTail( fr );
  1037. }
  1038. //-----------------------------------------------------------------------------
  1039. // Purpose:
  1040. // Input : &rcClient -
  1041. // tagtype -
  1042. // rcTray -
  1043. //-----------------------------------------------------------------------------
  1044. void GestureTool::GetTagTrayRect( RECT &rcClient, int tagtype, RECT& rcTray )
  1045. {
  1046. rcTray = rcClient;
  1047. rcTray.top += ( GetCaptionHeight() + 110 );
  1048. rcTray.bottom = rcTray.top + 6;
  1049. if ( tagtype == CChoreoEvent::ORIGINAL )
  1050. {
  1051. OffsetRect( &rcTray, 0, 45 );
  1052. }
  1053. }
  1054. //-----------------------------------------------------------------------------
  1055. // Purpose:
  1056. // Input : rcClient -
  1057. // *event -
  1058. // tagtype -
  1059. // *tag -
  1060. // rcTag -
  1061. // Output : Returns true on success, false on failure.
  1062. //-----------------------------------------------------------------------------
  1063. bool GestureTool::GetAbsTagRect( RECT& rcClient, CChoreoEvent *event,
  1064. int tagtype, CEventAbsoluteTag *tag, RECT& rcTag )
  1065. {
  1066. rcTag = rcClient;
  1067. GetTagTrayRect( rcClient, tagtype, rcTag );
  1068. bool clipped = false;
  1069. float t = tag->GetPercentage() * event->GetDuration();
  1070. int tagx = GetPixelForTimeValue( t, &clipped );
  1071. rcTag.left = tagx - 3;
  1072. rcTag.right = tagx + 3;
  1073. if ( clipped )
  1074. return false;
  1075. return true;
  1076. }
  1077. void GestureTool::DrawAbsoluteTags( CChoreoWidgetDrawHelper& drawHelper )
  1078. {
  1079. CChoreoEvent *event = GetSafeEvent();
  1080. if ( !event )
  1081. return;
  1082. RECT rcClient;
  1083. drawHelper.GetClientRect( rcClient );
  1084. bool showDots = true;
  1085. if ( event->GetNumAbsoluteTags( (CChoreoEvent::AbsTagType)0 ) !=
  1086. event->GetNumAbsoluteTags( (CChoreoEvent::AbsTagType)1 ) )
  1087. {
  1088. showDots = false;
  1089. }
  1090. int t;
  1091. for ( t = 0; t < CChoreoEvent::NUM_ABS_TAG_TYPES; t++ )
  1092. {
  1093. CChoreoEvent::AbsTagType tagtype = ( CChoreoEvent::AbsTagType )t;
  1094. RECT rcTray;
  1095. GetTagTrayRect( rcClient, tagtype, rcTray );
  1096. drawHelper.DrawColoredLine( RGB( 220, 220, 220 ), PS_SOLID, 1, rcTray.left, rcTray.top, rcTray.right, rcTray.top );
  1097. drawHelper.DrawColoredLine( RGB( 220, 220, 220 ), PS_SOLID, 1, rcTray.left, rcTray.bottom, rcTray.right, rcTray.bottom );
  1098. RECT rcText;
  1099. rcText = rcTray;
  1100. InflateRect( &rcText, 0, 4 );
  1101. OffsetRect( &rcText, 0, t == 0 ? -10 : 10 );
  1102. rcText.left = 2;
  1103. drawHelper.DrawColoredText( "Arial", 9, 500, RGB( 150, 150, 150 ), rcText, "%s",
  1104. t == 0 ? "Playback Time" : "Original Time" );
  1105. for ( int i = 0; i < event->GetNumAbsoluteTags( tagtype ); i++ )
  1106. {
  1107. CEventAbsoluteTag *tag = event->GetAbsoluteTag( tagtype, i );
  1108. if ( !tag )
  1109. continue;
  1110. RECT rcMark;
  1111. bool visible = GetAbsTagRect( rcClient, event, tagtype, tag, rcMark );
  1112. if ( showDots && t == 1 )
  1113. {
  1114. CChoreoEvent::AbsTagType tagtypeOther = (CChoreoEvent::AbsTagType)0;
  1115. RECT rcMark2;
  1116. CEventAbsoluteTag *otherTag = event->GetAbsoluteTag( tagtypeOther, i );
  1117. if ( otherTag )
  1118. {
  1119. GetAbsTagRect( rcClient, event, tagtypeOther, otherTag, rcMark2 );
  1120. {
  1121. int midx1 = ( rcMark.left + rcMark.right ) / 2;
  1122. int midx2 = ( rcMark2.left + rcMark2.right ) / 2;
  1123. int y1 = rcMark.top;
  1124. int y2 = rcMark2.bottom;
  1125. drawHelper.DrawColoredLine(
  1126. RGB( 200, 200, 200 ), PS_SOLID, 1,
  1127. midx1, y1, midx2, y2 );
  1128. }
  1129. }
  1130. }
  1131. if ( !visible )
  1132. continue;
  1133. drawHelper.DrawTriangleMarker( rcMark, RGB( 200, 0, 30 ), tagtype != CChoreoEvent::PLAYBACK );
  1134. RECT rcText;
  1135. rcText = rcMark;
  1136. if ( tagtype == CChoreoEvent::PLAYBACK )
  1137. {
  1138. rcText.top -= 15;
  1139. }
  1140. else
  1141. {
  1142. rcText.top += 10;
  1143. }
  1144. char text[ 256 ];
  1145. sprintf( text, "%s", tag->GetName() );
  1146. int len = drawHelper.CalcTextWidth( "Arial", 9, FW_NORMAL, text );
  1147. rcText.left = ( rcMark.left + rcMark.right ) / 2 - len / 2;
  1148. rcText.right = rcText.left + len + 2;
  1149. rcText.bottom = rcText.top + 10;
  1150. drawHelper.DrawColoredText( "Arial", 9, FW_NORMAL, RGB( 200, 100, 100 ), rcText, text );
  1151. if ( tagtype == CChoreoEvent::PLAYBACK )
  1152. {
  1153. rcText.top -= 10;
  1154. }
  1155. else
  1156. {
  1157. rcText.top += 10;
  1158. }
  1159. // sprintf( text, "%.3f", tag->GetPercentage() * event->GetDuration() + event->GetStartTime() );
  1160. sprintf( text, "%.3f", tag->GetPercentage() );
  1161. len = drawHelper.CalcTextWidth( "Arial", 9, FW_NORMAL, text );
  1162. rcText.left = ( rcMark.left + rcMark.right ) / 2 - len / 2;
  1163. rcText.right = rcText.left + len + 2;
  1164. rcText.bottom = rcText.top + 10;
  1165. drawHelper.DrawColoredText( "Arial", 9, FW_NORMAL, RGB( 200, 100, 100 ), rcText, text );
  1166. }
  1167. }
  1168. }
  1169. //-----------------------------------------------------------------------------
  1170. // Purpose:
  1171. // Input : drawHelper -
  1172. // rc -
  1173. // left -
  1174. // right -
  1175. //-----------------------------------------------------------------------------
  1176. void GestureTool::DrawTimeLine( CChoreoWidgetDrawHelper& drawHelper, RECT& rc, float left, float right )
  1177. {
  1178. RECT rcLabel;
  1179. float granularity = 0.5f;
  1180. drawHelper.DrawColoredLine( RGB( 150, 150, 200 ), PS_SOLID, 1, rc.left, rc.top + 2, rc.right, rc.top + 2 );
  1181. float f = SnapTime( left, granularity );
  1182. while ( f < right )
  1183. {
  1184. float frac = ( f - left ) / ( right - left );
  1185. if ( frac >= 0.0f && frac <= 1.0f )
  1186. {
  1187. rcLabel.left = GetPixelForTimeValue( f );
  1188. rcLabel.top = rc.top + 5;
  1189. rcLabel.bottom = rcLabel.top + 10;
  1190. if ( f != left )
  1191. {
  1192. drawHelper.DrawColoredLine( RGB( 220, 220, 240 ), PS_DOT, 1,
  1193. rcLabel.left, rc.top, rcLabel.left, h2() );
  1194. }
  1195. char sz[ 32 ];
  1196. sprintf( sz, "%.2f", f );
  1197. int textWidth = drawHelper.CalcTextWidth( "Arial", 9, FW_NORMAL, sz );
  1198. rcLabel.right = rcLabel.left + textWidth;
  1199. OffsetRect( &rcLabel, -textWidth / 2, 0 );
  1200. RECT rcOut = rcLabel;
  1201. if ( rcOut.left <= 0 )
  1202. {
  1203. OffsetRect( &rcOut, -rcOut.left + 2, 0 );
  1204. }
  1205. drawHelper.DrawColoredText( "Arial", 9, FW_NORMAL, RGB( 0, 50, 150 ), rcOut, sz );
  1206. }
  1207. f += granularity;
  1208. }
  1209. }
  1210. //-----------------------------------------------------------------------------
  1211. // Purpose:
  1212. // Input : mx -
  1213. // my -
  1214. // Output : CFlexTimingTag
  1215. //-----------------------------------------------------------------------------
  1216. CEventAbsoluteTag *GestureTool::IsMouseOverTag( int mx, int my )
  1217. {
  1218. CChoreoEvent *event = GetSafeEvent();
  1219. if ( !event )
  1220. return NULL;
  1221. RECT rcClient;
  1222. GetClientRect( (HWND)getHandle(), &rcClient );
  1223. POINT pt;
  1224. pt.x = mx;
  1225. pt.y = my;
  1226. for ( int t = 0; t < CChoreoEvent::NUM_ABS_TAG_TYPES; t++ )
  1227. {
  1228. CChoreoEvent::AbsTagType tagtype = ( CChoreoEvent::AbsTagType )t;
  1229. for ( int i = 0; i < event->GetNumAbsoluteTags( tagtype ); i++ )
  1230. {
  1231. CEventAbsoluteTag *tag = event->GetAbsoluteTag( tagtype, i );
  1232. if ( !tag )
  1233. continue;
  1234. if ( tag->GetLocked() )
  1235. continue;
  1236. RECT rcTag;
  1237. if ( !GetAbsTagRect( rcClient, event, tagtype, tag, rcTag ) )
  1238. continue;
  1239. if ( !PtInRect( &rcTag, pt ) )
  1240. continue;
  1241. return tag;
  1242. }
  1243. }
  1244. return NULL;
  1245. }
  1246. //-----------------------------------------------------------------------------
  1247. // Purpose:
  1248. // Input : mx -
  1249. // my -
  1250. // Output : int
  1251. //-----------------------------------------------------------------------------
  1252. int GestureTool::GetTagTypeForMouse( int mx, int my )
  1253. {
  1254. RECT rcClient;
  1255. rcClient.left = 0;
  1256. rcClient.right = w2();
  1257. rcClient.top = 0;
  1258. rcClient.bottom = h2();
  1259. POINT pt;
  1260. pt.x = mx;
  1261. pt.y = my;
  1262. for ( int t = 0; t < CChoreoEvent::NUM_ABS_TAG_TYPES; t++ )
  1263. {
  1264. RECT rcTray;
  1265. GetTagTrayRect( rcClient, t, rcTray );
  1266. if ( PtInRect( &rcTray, pt ) )
  1267. {
  1268. return t;
  1269. }
  1270. }
  1271. return -1;
  1272. }
  1273. void GestureTool::OnInsertTag( void )
  1274. {
  1275. CChoreoEvent *event = GetSafeEvent();
  1276. if ( !event )
  1277. return;
  1278. if ( event->GetType() != CChoreoEvent::GESTURE )
  1279. {
  1280. Con_ErrorPrintf( "Absolute Tag: Can only tag GESTURE events\n" );
  1281. return;
  1282. }
  1283. CInputParams params;
  1284. memset( &params, 0, sizeof( params ) );
  1285. strcpy( params.m_szDialogTitle, "Absolute Tag Name" );
  1286. strcpy( params.m_szPrompt, "Name:" );
  1287. strcpy( params.m_szInputText, "" );
  1288. if ( !InputProperties( &params ) )
  1289. return;
  1290. if ( strlen( params.m_szInputText ) <= 0 )
  1291. {
  1292. Con_ErrorPrintf( "Timing Tag Name: No name entered!\n" );
  1293. return;
  1294. }
  1295. // Convert click to frac
  1296. float t = GetTimeValueForMouse( m_nClickedX ) / event->GetDuration();
  1297. float tshifted = event->GetOriginalPercentageFromPlaybackPercentage( t );
  1298. g_pChoreoView->SetDirty( true );
  1299. g_pChoreoView->PushUndo( "Add Gesture Tag" );
  1300. event->AddAbsoluteTag( CChoreoEvent::ORIGINAL, params.m_szInputText, tshifted );
  1301. event->AddAbsoluteTag( CChoreoEvent::PLAYBACK, params.m_szInputText, t );
  1302. g_pChoreoView->PushRedo( "Add Gesture Tag" );
  1303. // Redraw this window
  1304. redraw();
  1305. }
  1306. void GestureTool::OnRevert()
  1307. {
  1308. CChoreoEvent *event = GetSafeEvent();
  1309. if ( !event )
  1310. return;
  1311. if ( !event->GetNumAbsoluteTags( CChoreoEvent::PLAYBACK ) )
  1312. return;
  1313. if ( event->GetNumAbsoluteTags( CChoreoEvent::PLAYBACK ) !=
  1314. event->GetNumAbsoluteTags( CChoreoEvent::ORIGINAL ) )
  1315. {
  1316. Assert( 0 );
  1317. return;
  1318. }
  1319. g_pChoreoView->SetDirty( true );
  1320. g_pChoreoView->PushUndo( "Revert Gesture Tags" );
  1321. int c = event->GetNumAbsoluteTags( CChoreoEvent::PLAYBACK );
  1322. for ( int i = 0; i < c; i++ )
  1323. {
  1324. CEventAbsoluteTag *original = event->GetAbsoluteTag( CChoreoEvent::ORIGINAL, i );
  1325. CEventAbsoluteTag *playback = event->GetAbsoluteTag( CChoreoEvent::PLAYBACK, i );
  1326. playback->SetPercentage( original->GetPercentage() );
  1327. }
  1328. g_pChoreoView->PushRedo( "Revert Gesture Tags" );
  1329. // Redraw this window
  1330. redraw();
  1331. }
  1332. void GestureTool::OnDeleteTag( void )
  1333. {
  1334. CChoreoEvent *event = GetSafeEvent();
  1335. if ( !event )
  1336. return;
  1337. CEventAbsoluteTag *tag = IsMouseOverTag( m_nClickedX, m_nClickedY );
  1338. if ( !tag )
  1339. return;
  1340. g_pChoreoView->SetDirty( true );
  1341. g_pChoreoView->PushUndo( "Remove Gesture Tag" );
  1342. char sz[ 512 ];
  1343. Q_strncpy( sz, tag->GetName(), sizeof( sz ) );
  1344. for ( int t = 0; t < CChoreoEvent::NUM_ABS_TAG_TYPES; t++ )
  1345. {
  1346. event->RemoveAbsoluteTag( (CChoreoEvent::AbsTagType)t, sz );
  1347. }
  1348. g_pChoreoView->PushRedo( "Remove Gesture Tags" );
  1349. // Redraw this window
  1350. redraw();
  1351. }
  1352. void GestureTool::DrawRelativeTags( CChoreoWidgetDrawHelper& drawHelper, RECT& rc )
  1353. {
  1354. CChoreoEvent *gesture = GetSafeEvent();
  1355. if ( !gesture )
  1356. return;
  1357. CChoreoScene *scene = gesture->GetScene();
  1358. if ( !scene )
  1359. return;
  1360. float starttime = GetTimeValueForMouse( 0 );
  1361. float endtime = GetTimeValueForMouse( w2() );
  1362. if ( endtime - starttime <= 0.0f )
  1363. return;
  1364. drawHelper.DrawColoredText( "Arial", 9, FW_NORMAL, RGB( 0, 100, 200 ), rc, "Timing Tags:" );
  1365. // Loop through all events in scene
  1366. int c = scene->GetNumEvents();
  1367. int i;
  1368. for ( i = 0; i < c; i++ )
  1369. {
  1370. CChoreoEvent *e = scene->GetEvent( i );
  1371. if ( !e )
  1372. continue;
  1373. if ( e->GetNumRelativeTags() <= 0 )
  1374. continue;
  1375. // See if time overlaps
  1376. if ( !e->HasEndTime() )
  1377. continue;
  1378. if ( ( e->GetEndTime() - e->GetStartTime() ) < starttime )
  1379. continue;
  1380. if ( ( e->GetStartTime() - e->GetStartTime() ) > endtime )
  1381. continue;
  1382. DrawRelativeTagsForEvent( drawHelper, rc, gesture, e, starttime, endtime );
  1383. }
  1384. }
  1385. //-----------------------------------------------------------------------------
  1386. // Purpose:
  1387. // Input : drawHelper -
  1388. // rc -
  1389. //-----------------------------------------------------------------------------
  1390. void GestureTool::DrawRelativeTagsForEvent( CChoreoWidgetDrawHelper& drawHelper, RECT& rc, CChoreoEvent *gesture, CChoreoEvent *event, float starttime, float endtime )
  1391. {
  1392. if ( !event )
  1393. return;
  1394. //drawHelper.DrawColoredText( "Arial", 9, FW_NORMAL, PEColor( COLOR_PHONEME_TIMING_TAG ), rc, "Timing Tags:" );
  1395. for ( int i = 0; i < event->GetNumRelativeTags(); i++ )
  1396. {
  1397. CEventRelativeTag *tag = event->GetRelativeTag( i );
  1398. if ( !tag )
  1399. continue;
  1400. //
  1401. float tagtime = ( event->GetStartTime() + tag->GetPercentage() * event->GetDuration() ) - gesture->GetStartTime();
  1402. if ( tagtime < starttime || tagtime > endtime )
  1403. continue;
  1404. bool clipped = false;
  1405. int left = GetPixelForTimeValue( tagtime, &clipped );
  1406. if ( clipped )
  1407. continue;
  1408. //float frac = ( tagtime - starttime ) / ( endtime - starttime );
  1409. //int left = rc.left + (int)( frac * ( float )( rc.right - rc.left ) + 0.5f );
  1410. RECT rcMark;
  1411. rcMark = rc;
  1412. rcMark.top = rc.bottom - 8;
  1413. rcMark.bottom = rc.bottom;
  1414. rcMark.left = left - 4;
  1415. rcMark.right = left + 4;
  1416. drawHelper.DrawTriangleMarker( rcMark, RGB( 0, 100, 200 ) );
  1417. RECT rcText;
  1418. rcText = rc;
  1419. rcText.bottom = rc.bottom - 10;
  1420. rcText.top = rcText.bottom - 10;
  1421. int len = drawHelper.CalcTextWidth( "Arial", 9, FW_NORMAL, tag->GetName() );
  1422. rcText.left = left - len / 2;
  1423. rcText.right = rcText.left + len + 2;
  1424. drawHelper.DrawColoredText( "Arial", 9, FW_NORMAL, RGB( 0, 100, 200 ), rcText, tag->GetName() );
  1425. }
  1426. }
  1427. //-----------------------------------------------------------------------------
  1428. // Purpose:
  1429. // Output : int
  1430. //-----------------------------------------------------------------------------
  1431. int GestureTool::ComputeHPixelsNeeded( void )
  1432. {
  1433. CChoreoEvent *event = GetSafeEvent();
  1434. if ( !event )
  1435. return 0;
  1436. int pixels = 0;
  1437. float maxtime = event->GetDuration();
  1438. pixels = (int)( ( maxtime ) * GetPixelsPerSecond() ) + 10;
  1439. return pixels;
  1440. }
  1441. //-----------------------------------------------------------------------------
  1442. // Purpose:
  1443. //-----------------------------------------------------------------------------
  1444. void GestureTool::RepositionHSlider( void )
  1445. {
  1446. int pixelsneeded = ComputeHPixelsNeeded();
  1447. if ( pixelsneeded <= w2() )
  1448. {
  1449. m_pHorzScrollBar->setVisible( false );
  1450. }
  1451. else
  1452. {
  1453. m_pHorzScrollBar->setVisible( true );
  1454. }
  1455. m_pHorzScrollBar->setBounds( 0, h2() - m_nScrollbarHeight, w2() - m_nScrollbarHeight, m_nScrollbarHeight );
  1456. m_flLeftOffset = max( 0.f, m_flLeftOffset );
  1457. m_flLeftOffset = min( (float)pixelsneeded, m_flLeftOffset );
  1458. m_pHorzScrollBar->setRange( 0, pixelsneeded );
  1459. m_pHorzScrollBar->setValue( (int)m_flLeftOffset );
  1460. m_pHorzScrollBar->setPagesize( w2() );
  1461. m_nLastHPixelsNeeded = pixelsneeded;
  1462. }
  1463. //-----------------------------------------------------------------------------
  1464. // Purpose:
  1465. // Output : float
  1466. //-----------------------------------------------------------------------------
  1467. float GestureTool::GetPixelsPerSecond( void )
  1468. {
  1469. return m_flPixelsPerSecond * (float)g_pChoreoView->GetTimeZoom( GetToolName() )/100.0f;
  1470. }
  1471. //-----------------------------------------------------------------------------
  1472. // Purpose:
  1473. // Input : x -
  1474. //-----------------------------------------------------------------------------
  1475. void GestureTool::MoveTimeSliderToPos( int x )
  1476. {
  1477. m_flLeftOffset = (float)x;
  1478. m_pHorzScrollBar->setValue( (int)m_flLeftOffset );
  1479. InvalidateRect( (HWND)m_pHorzScrollBar->getHandle(), NULL, TRUE );
  1480. InvalidateLayout();
  1481. }
  1482. //-----------------------------------------------------------------------------
  1483. // Purpose:
  1484. //-----------------------------------------------------------------------------
  1485. void GestureTool::InvalidateLayout( void )
  1486. {
  1487. if ( m_bSuppressLayout )
  1488. return;
  1489. if ( ComputeHPixelsNeeded() != m_nLastHPixelsNeeded )
  1490. {
  1491. RepositionHSlider();
  1492. }
  1493. m_bLayoutIsValid = false;
  1494. redraw();
  1495. }
  1496. //-----------------------------------------------------------------------------
  1497. // Purpose:
  1498. // Input : st -
  1499. // ed -
  1500. //-----------------------------------------------------------------------------
  1501. void GestureTool::GetStartAndEndTime( float& st, float& ed )
  1502. {
  1503. st = m_flLeftOffset / GetPixelsPerSecond();
  1504. ed = st + (float)w2() / GetPixelsPerSecond();
  1505. }
  1506. //-----------------------------------------------------------------------------
  1507. // Purpose:
  1508. // Input : -
  1509. // Output : float
  1510. //-----------------------------------------------------------------------------
  1511. float GestureTool::GetEventEndTime()
  1512. {
  1513. CChoreoEvent *ev = GetSafeEvent();
  1514. if ( !ev )
  1515. return 1.0f;
  1516. return ev->GetDuration();
  1517. }
  1518. //-----------------------------------------------------------------------------
  1519. // Purpose:
  1520. // Input : time -
  1521. // *clipped -
  1522. // Output : int
  1523. //-----------------------------------------------------------------------------
  1524. int GestureTool::GetPixelForTimeValue( float time, bool *clipped /*=NULL*/ )
  1525. {
  1526. if ( clipped )
  1527. {
  1528. *clipped = false;
  1529. }
  1530. float st, ed;
  1531. GetStartAndEndTime( st, ed );
  1532. float frac = ( time - st ) / ( ed - st );
  1533. if ( frac < 0.0 || frac > 1.0 )
  1534. {
  1535. if ( clipped )
  1536. {
  1537. *clipped = true;
  1538. }
  1539. }
  1540. int pixel = ( int )( frac * w2() );
  1541. return pixel;
  1542. }
  1543. //-----------------------------------------------------------------------------
  1544. // Purpose:
  1545. // Input : mx -
  1546. // clip -
  1547. // Output : float
  1548. //-----------------------------------------------------------------------------
  1549. float GestureTool::GetTimeValueForMouse( int mx, bool clip /*=false*/)
  1550. {
  1551. float st, ed;
  1552. GetStartAndEndTime( st, ed );
  1553. if ( clip )
  1554. {
  1555. if ( mx < 0 )
  1556. {
  1557. return st;
  1558. }
  1559. if ( mx > w2() )
  1560. {
  1561. return ed;
  1562. }
  1563. }
  1564. float frac = (float)( mx ) / (float)( w2() );
  1565. return st + frac * ( ed - st );
  1566. }
  1567. void GestureTool::OnChangeScale( void )
  1568. {
  1569. CChoreoScene *scene = g_pChoreoView->GetScene();
  1570. if ( !scene )
  1571. {
  1572. return;
  1573. }
  1574. // Zoom time in / out
  1575. CInputParams params;
  1576. memset( &params, 0, sizeof( params ) );
  1577. strcpy( params.m_szDialogTitle, "Change Zoom" );
  1578. strcpy( params.m_szPrompt, "New scale (e.g., 2.5x):" );
  1579. Q_snprintf( params.m_szInputText, sizeof( params.m_szInputText ), "%.2f", (float)g_pChoreoView->GetTimeZoom( GetToolName() ) / 100.0f );
  1580. if ( !InputProperties( &params ) )
  1581. return;
  1582. g_pChoreoView->SetTimeZoom( GetToolName(), clamp( (int)( 100.0f * atof( params.m_szInputText ) ), 1, MAX_TIME_ZOOM ), false );
  1583. m_nLastHPixelsNeeded = -1;
  1584. m_flLeftOffset= 0.0f;
  1585. InvalidateLayout();
  1586. Con_Printf( "Zoom factor %i %%\n", g_pChoreoView->GetTimeZoom( GetToolName() ) );
  1587. }
  1588. void GestureTool::DrawEventEnd( CChoreoWidgetDrawHelper& drawHelper )
  1589. {
  1590. CChoreoEvent *e = GetSafeEvent();
  1591. if ( !e )
  1592. return;
  1593. float duration = e->GetDuration();
  1594. if ( !duration )
  1595. return;
  1596. int leftx = GetPixelForTimeValue( duration );
  1597. if ( leftx >= w2() )
  1598. return;
  1599. RECT rcClient;
  1600. drawHelper.GetClientRect( rcClient );
  1601. drawHelper.DrawColoredLine(
  1602. COLOR_CHOREO_ENDTIME, PS_SOLID, 1,
  1603. leftx, GetCaptionHeight() + 73, leftx, rcClient.bottom );
  1604. }
  1605. void GestureTool::OnModelChanged()
  1606. {
  1607. redraw();
  1608. }