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.

2244 lines
49 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 "SceneRampTool.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. #include "curveeditorhelpers.h"
  35. #include "EdgeProperties.h"
  36. SceneRampTool *g_pSceneRampTool = 0;
  37. #define TRAY_HEIGHT 20
  38. #define TRAY_ITEM_INSET 10
  39. #define TAG_TOP ( TRAY_HEIGHT + 12 )
  40. #define TAG_BOTTOM ( TAG_TOP + 20 )
  41. #define MAX_TIME_ZOOM 1000
  42. // 10% per step
  43. #define TIME_ZOOM_STEP 2
  44. SceneRampTool::SceneRampTool( mxWindow *parent )
  45. : IFacePoserToolWindow( "SceneRampTool", "Scene Ramp" ), mxWindow( parent, 0, 0, 0, 0 )
  46. {
  47. m_pHelper = new CCurveEditorHelper< SceneRampTool >( this );
  48. m_bSuppressLayout = false;
  49. SetAutoProcess( true );
  50. m_flScrub = 0.0f;
  51. m_flScrubTarget = 0.0f;
  52. m_nDragType = DRAGTYPE_NONE;
  53. m_nClickedX = 0;
  54. m_nClickedY = 0;
  55. m_hPrevCursor = 0;
  56. m_nStartX = 0;
  57. m_nStartY = 0;
  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_SRT_RAMPHSCROLL, mxScrollbar::Horizontal );
  69. m_pHorzScrollBar->setVisible( false );
  70. m_flScrubberTimeOffset = 0.0f;
  71. m_nUndoSetup = 0;
  72. }
  73. SceneRampTool::~SceneRampTool( void )
  74. {
  75. delete m_pHelper;
  76. }
  77. //-----------------------------------------------------------------------------
  78. // Purpose:
  79. //-----------------------------------------------------------------------------
  80. CChoreoScene *SceneRampTool::GetSafeScene( void )
  81. {
  82. if ( !g_pChoreoView )
  83. return NULL;
  84. CChoreoScene *scene = g_pChoreoView->GetScene();
  85. if ( !scene )
  86. return NULL;
  87. return scene;
  88. }
  89. //-----------------------------------------------------------------------------
  90. // Purpose:
  91. // Input : rcHandle -
  92. //-----------------------------------------------------------------------------
  93. void SceneRampTool::GetScrubHandleRect( RECT& rcHandle, float scrub, bool clipped )
  94. {
  95. float pixel = 0.0f;
  96. if ( w2() > 0 )
  97. {
  98. pixel = GetPixelForTimeValue( scrub );
  99. if ( clipped )
  100. {
  101. pixel = clamp( pixel, SCRUBBER_HANDLE_WIDTH / 2, w2() - SCRUBBER_HANDLE_WIDTH / 2 );
  102. }
  103. }
  104. rcHandle.left = pixel- SCRUBBER_HANDLE_WIDTH / 2;
  105. rcHandle.right = pixel + SCRUBBER_HANDLE_WIDTH / 2;
  106. rcHandle.top = 2 + GetCaptionHeight();
  107. rcHandle.bottom = rcHandle.top + SCRUBBER_HANDLE_HEIGHT;
  108. }
  109. //-----------------------------------------------------------------------------
  110. // Purpose:
  111. // Input : drawHelper -
  112. // rcHandle -
  113. //-----------------------------------------------------------------------------
  114. void SceneRampTool::DrawScrubHandle( CChoreoWidgetDrawHelper& drawHelper, RECT& rcHandle, float scrub, bool reference )
  115. {
  116. HBRUSH br = CreateSolidBrush( reference ? RGB( 150, 0, 0 ) : RGB( 0, 150, 100 ) );
  117. COLORREF areaBorder = RGB( 230, 230, 220 );
  118. drawHelper.DrawColoredLine( areaBorder,
  119. PS_SOLID, 1, 0, rcHandle.top, w2(), rcHandle.top );
  120. drawHelper.DrawColoredLine( areaBorder,
  121. PS_SOLID, 1, 0, rcHandle.bottom, w2(), rcHandle.bottom );
  122. drawHelper.DrawFilledRect( br, rcHandle );
  123. //
  124. char sz[ 32 ];
  125. sprintf( sz, "%.3f", scrub );
  126. CChoreoScene *scene = GetSafeScene();
  127. if ( scene )
  128. {
  129. float st, ed;
  130. st = 0.0f;
  131. ed = scene->FindStopTime();
  132. float dt = ed - st;
  133. if ( dt > 0.0f )
  134. {
  135. sprintf( sz, "%.3f", st + scrub );
  136. }
  137. }
  138. int len = drawHelper.CalcTextWidth( "Arial", 9, 500, sz );
  139. RECT rcText = rcHandle;
  140. int textw = rcText.right - rcText.left;
  141. rcText.left += ( textw - len ) / 2;
  142. drawHelper.DrawColoredText( "Arial", 9, 500, RGB( 255, 255, 255 ), rcText, sz );
  143. DeleteObject( br );
  144. }
  145. //-----------------------------------------------------------------------------
  146. // Purpose:
  147. // Input : *event -
  148. // Output : Returns true on success, false on failure.
  149. //-----------------------------------------------------------------------------
  150. bool SceneRampTool::IsMouseOverScrubHandle( mxEvent *event )
  151. {
  152. RECT rcHandle;
  153. GetScrubHandleRect( rcHandle, m_flScrub, true );
  154. InflateRect( &rcHandle, 2, 2 );
  155. POINT pt;
  156. pt.x = (short)event->x;
  157. pt.y = (short)event->y;
  158. if ( PtInRect( &rcHandle, pt ) )
  159. {
  160. return true;
  161. }
  162. return false;
  163. }
  164. //-----------------------------------------------------------------------------
  165. // Purpose:
  166. // Output : Returns true on success, false on failure.
  167. //-----------------------------------------------------------------------------
  168. bool SceneRampTool::IsProcessing( void )
  169. {
  170. if ( !GetSafeScene() )
  171. return false;
  172. if ( m_flScrub != m_flScrubTarget )
  173. return true;
  174. return false;
  175. }
  176. bool SceneRampTool::IsScrubbing( void ) const
  177. {
  178. bool scrubbing = ( m_nDragType == DRAGTYPE_SCRUBBER ) ? true : false;
  179. return scrubbing;
  180. }
  181. void SceneRampTool::SetScrubTime( float t )
  182. {
  183. m_flScrub = t;
  184. CChoreoScene *scene = GetSafeScene();
  185. if ( scene && scene->FindStopTime() )
  186. {
  187. float realtime = m_flScrub;
  188. g_pChoreoView->SetScrubTime( realtime );
  189. g_pChoreoView->DrawScrubHandle();
  190. }
  191. }
  192. void SceneRampTool::SetScrubTargetTime( float t )
  193. {
  194. m_flScrubTarget = t;
  195. CChoreoScene *scene = GetSafeScene();
  196. if ( scene && scene->FindStopTime() )
  197. {
  198. float realtime = m_flScrubTarget;
  199. g_pChoreoView->SetScrubTargetTime( realtime );
  200. }
  201. }
  202. //-----------------------------------------------------------------------------
  203. // Purpose:
  204. // Input : dt -
  205. //-----------------------------------------------------------------------------
  206. void SceneRampTool::Think( float dt )
  207. {
  208. if ( !GetSafeScene() )
  209. return;
  210. bool scrubbing = IsScrubbing();
  211. ScrubThink( dt, scrubbing );
  212. }
  213. //-----------------------------------------------------------------------------
  214. // Purpose:
  215. // Input : dt -
  216. //-----------------------------------------------------------------------------
  217. void SceneRampTool::ScrubThink( float dt, bool scrubbing )
  218. {
  219. if ( !GetSafeScene() )
  220. return;
  221. if ( m_flScrubTarget == m_flScrub && !scrubbing )
  222. return;
  223. float d = m_flScrubTarget - m_flScrub;
  224. int sign = d > 0.0f ? 1 : -1;
  225. float maxmove = dt;
  226. if ( sign > 0 )
  227. {
  228. if ( d < maxmove )
  229. {
  230. SetScrubTime( m_flScrubTarget );
  231. }
  232. else
  233. {
  234. SetScrubTime( m_flScrub + maxmove );
  235. }
  236. }
  237. else
  238. {
  239. if ( -d < maxmove )
  240. {
  241. SetScrubTime( m_flScrubTarget );
  242. }
  243. else
  244. {
  245. SetScrubTime( m_flScrub - maxmove );
  246. }
  247. }
  248. if ( scrubbing )
  249. {
  250. g_pMatSysWindow->Frame();
  251. }
  252. }
  253. void SceneRampTool::DrawScrubHandles()
  254. {
  255. RECT rcTray;
  256. RECT rcHandle;
  257. GetScrubHandleRect( rcHandle, m_flScrub, true );
  258. rcTray = rcHandle;
  259. rcTray.left = 0;
  260. rcTray.right = w2();
  261. CChoreoWidgetDrawHelper drawHelper( this, rcTray );
  262. DrawScrubHandle( drawHelper, rcHandle, m_flScrub, false );
  263. }
  264. void SceneRampTool::redraw()
  265. {
  266. if ( !ToolCanDraw() )
  267. return;
  268. CChoreoWidgetDrawHelper drawHelper( this );
  269. HandleToolRedraw( drawHelper );
  270. RECT rc;
  271. drawHelper.GetClientRect( rc );
  272. CChoreoScene *scene = GetSafeScene();
  273. if ( scene )
  274. {
  275. RECT rcText;
  276. drawHelper.GetClientRect( rcText );
  277. rcText.top += GetCaptionHeight()+1;
  278. rcText.bottom = rcText.top + 13;
  279. rcText.left += 5;
  280. rcText.right -= 5;
  281. OffsetRect( &rcText, 0, 12 );
  282. int current, total;
  283. g_pChoreoView->GetUndoLevels( current, total );
  284. if ( total > 0 )
  285. {
  286. RECT rcUndo = rcText;
  287. OffsetRect( &rcUndo, 0, 2 );
  288. drawHelper.DrawColoredText( "Small Fonts", 8, FW_NORMAL, RGB( 0, 100, 0 ), rcUndo,
  289. "Undo: %i/%i", current, total );
  290. }
  291. rcText.left += 60;
  292. // Found it, write out description
  293. //
  294. RECT rcTextLine = rcText;
  295. drawHelper.DrawColoredText( "Arial", 11, 900, RGB( 200, 0, 0 ), rcTextLine,
  296. "Scene: %s",
  297. g_pChoreoView->GetChoreoFile() );
  298. RECT rcTimeLine;
  299. drawHelper.GetClientRect( rcTimeLine );
  300. rcTimeLine.left = 0;
  301. rcTimeLine.right = w2();
  302. rcTimeLine.top += ( GetCaptionHeight() + 50 );
  303. float lefttime = GetTimeValueForMouse( 0 );
  304. float righttime = GetTimeValueForMouse( w2() );
  305. DrawTimeLine( drawHelper, rcTimeLine, lefttime, righttime );
  306. OffsetRect( &rcText, 0, 28 );
  307. rcText.left = 5;
  308. RECT timeRect = rcText;
  309. timeRect.right = timeRect.left + 100;
  310. char sz[ 32 ];
  311. Q_snprintf( sz, sizeof( sz ), "%.2f", lefttime );
  312. drawHelper.DrawColoredText( "Arial", 9, FW_NORMAL, RGB( 0, 0, 0 ), timeRect, sz );
  313. timeRect = rcText;
  314. Q_snprintf( sz, sizeof( sz ), "%.2f", righttime );
  315. int textW = drawHelper.CalcTextWidth( "Arial", 9, FW_NORMAL, sz );
  316. timeRect.right = w2() - 10;
  317. timeRect.left = timeRect.right - textW;
  318. drawHelper.DrawColoredText( "Arial", 9, FW_NORMAL, RGB( 0, 0, 0 ), timeRect, sz );
  319. }
  320. RECT rcHandle;
  321. GetScrubHandleRect( rcHandle, m_flScrub, true );
  322. DrawScrubHandle( drawHelper, rcHandle, m_flScrub, false );
  323. RECT rcSamples;
  324. GetSampleTrayRect( rcSamples );
  325. DrawSamples( drawHelper, rcSamples );
  326. DrawSceneEnd( drawHelper );
  327. RECT rcTags = rc;
  328. rcTags.top = TAG_TOP + GetCaptionHeight();
  329. rcTags.bottom = TAG_BOTTOM + GetCaptionHeight();
  330. DrawTimingTags( drawHelper, rcTags );
  331. RECT rcPos;
  332. GetMouseOverPosRect( rcPos );
  333. DrawMouseOverPos( drawHelper, rcPos );
  334. }
  335. //-----------------------------------------------------------------------------
  336. // Purpose:
  337. //-----------------------------------------------------------------------------
  338. void SceneRampTool::ShowContextMenu( mxEvent *event, bool include_track_menus )
  339. {
  340. // Construct main menu
  341. mxPopupMenu *pop = new mxPopupMenu();
  342. int current, total;
  343. g_pChoreoView->GetUndoLevels( current, total );
  344. if ( total > 0 )
  345. {
  346. if ( current > 0 )
  347. {
  348. pop->add( va( "Undo %s", g_pChoreoView->GetUndoDescription() ), IDC_UNDO_SRT );
  349. }
  350. if ( current <= total - 1 )
  351. {
  352. pop->add( va( "Redo %s", g_pChoreoView->GetRedoDescription() ), IDC_REDO_SRT );
  353. }
  354. pop->addSeparator();
  355. }
  356. CChoreoScene *scene = GetSafeScene();
  357. if ( scene )
  358. {
  359. if ( CountSelected() > 0 )
  360. {
  361. pop->add( va( "Delete" ), IDC_SRT_DELETE );
  362. pop->add( "Deselect all", IDC_SRT_DESELECT );
  363. }
  364. pop->add( "Select all", IDC_SRT_SELECTALL );
  365. }
  366. pop->add( va( "Change scale..." ), IDC_SRT_CHANGESCALE );
  367. pop->addSeparator();
  368. pop->add( "Edge Properties...", IDC_SRT_EDGEPROPERTIES );
  369. pop->popup( this, (short)event->x, (short)event->y );
  370. }
  371. void SceneRampTool::GetWorkspaceLeftRight( int& left, int& right )
  372. {
  373. left = 0;
  374. right = w2();
  375. }
  376. //-----------------------------------------------------------------------------
  377. // Purpose:
  378. //-----------------------------------------------------------------------------
  379. void SceneRampTool::DrawFocusRect( void )
  380. {
  381. HDC dc = GetDC( NULL );
  382. for ( int i = 0; i < m_FocusRects.Size(); i++ )
  383. {
  384. RECT rc = m_FocusRects[ i ].m_rcFocus;
  385. ::DrawFocusRect( dc, &rc );
  386. }
  387. ReleaseDC( NULL, dc );
  388. }
  389. void SceneRampTool::SetClickedPos( int x, int y )
  390. {
  391. m_nClickedX = x;
  392. m_nClickedY = y;
  393. }
  394. float SceneRampTool::GetTimeForClickedPos( void )
  395. {
  396. CChoreoScene *scene = GetSafeScene();
  397. if ( !scene )
  398. return 0.0f;
  399. float t = GetTimeValueForMouse( m_nClickedX );
  400. return t;
  401. }
  402. //-----------------------------------------------------------------------------
  403. // Purpose:
  404. // Input : dragtype -
  405. // startx -
  406. // cursor -
  407. //-----------------------------------------------------------------------------
  408. void SceneRampTool::StartDragging( int dragtype, int startx, int starty, HCURSOR cursor )
  409. {
  410. m_nDragType = dragtype;
  411. m_nStartX = startx;
  412. m_nLastX = startx;
  413. m_nStartY = starty;
  414. m_nLastY = starty;
  415. if ( m_hPrevCursor )
  416. {
  417. SetCursor( m_hPrevCursor );
  418. m_hPrevCursor = NULL;
  419. }
  420. m_hPrevCursor = SetCursor( cursor );
  421. m_FocusRects.Purge();
  422. RECT rcStart;
  423. rcStart.left = startx;
  424. rcStart.right = startx;
  425. bool addrect = true;
  426. switch ( dragtype )
  427. {
  428. case DRAGTYPE_SCRUBBER:
  429. {
  430. RECT rcScrub;
  431. GetScrubHandleRect( rcScrub, m_flScrub, true );
  432. rcStart = rcScrub;
  433. rcStart.left = ( rcScrub.left + rcScrub.right ) / 2;
  434. rcStart.right = rcStart.left;
  435. rcStart.top = rcScrub.bottom;
  436. rcStart.bottom = h2();
  437. }
  438. break;
  439. default:
  440. {
  441. rcStart.top = starty;
  442. rcStart.bottom = starty;
  443. }
  444. break;
  445. }
  446. if ( addrect )
  447. {
  448. AddFocusRect( rcStart );
  449. }
  450. DrawFocusRect();
  451. }
  452. void SceneRampTool::OnMouseMove( mxEvent *event )
  453. {
  454. int mx = (short)event->x;
  455. int my = (short)event->y;
  456. event->x = (short)mx;
  457. if ( m_nDragType != DRAGTYPE_NONE )
  458. {
  459. DrawFocusRect();
  460. for ( int i = 0; i < m_FocusRects.Size(); i++ )
  461. {
  462. CFocusRect *f = &m_FocusRects[ i ];
  463. f->m_rcFocus = f->m_rcOrig;
  464. switch ( m_nDragType )
  465. {
  466. default:
  467. {
  468. OffsetRect( &f->m_rcFocus, ( mx - m_nStartX ), ( my - m_nStartY ) );
  469. }
  470. break;
  471. case DRAGTYPE_SCRUBBER:
  472. {
  473. ApplyBounds( mx, my );
  474. if ( w2() > 0 )
  475. {
  476. float t = GetTimeValueForMouse( mx );
  477. t += m_flScrubberTimeOffset;
  478. ForceScrubPosition( t );
  479. }
  480. OffsetRect( &f->m_rcFocus, ( mx - m_nStartX ), 0 );
  481. }
  482. break;
  483. case DRAGTYPE_MOVEPOINTS_TIME:
  484. case DRAGTYPE_MOVEPOINTS_VALUE:
  485. {
  486. int dx = mx - m_nLastX;
  487. int dy = my - m_nLastY;
  488. if ( !( event->modifiers & mxEvent::KeyCtrl ) )
  489. {
  490. // Zero out motion on other axis
  491. if ( m_nDragType == DRAGTYPE_MOVEPOINTS_VALUE )
  492. {
  493. dx = 0;
  494. mx = m_nLastX;
  495. }
  496. else
  497. {
  498. dy = 0;
  499. my = m_nLastY;
  500. }
  501. }
  502. else
  503. {
  504. SetCursor( LoadCursor( NULL, IDC_SIZEALL ) );
  505. }
  506. RECT rcSamples;
  507. GetSampleTrayRect( rcSamples );
  508. int height = rcSamples.bottom - rcSamples.top;
  509. Assert( height > 0 );
  510. float dfdx = (float)dx / GetPixelsPerSecond();
  511. float dfdy = (float)dy / (float)height;
  512. MoveSelectedSamples( dfdx, dfdy );
  513. // Update the scrubber
  514. if ( w2() > 0 )
  515. {
  516. float t = GetTimeValueForMouse( mx );
  517. ForceScrubPosition( t );
  518. g_pMatSysWindow->Frame();
  519. }
  520. OffsetRect( &f->m_rcFocus, dx, dy );
  521. }
  522. break;
  523. case DRAGTYPE_SELECTION:
  524. {
  525. RECT rcFocus;
  526. rcFocus.left = m_nStartX < m_nLastX ? m_nStartX : m_nLastX;
  527. rcFocus.right = m_nStartX < m_nLastX ? m_nLastX : m_nStartX;
  528. rcFocus.top = m_nStartY < m_nLastY ? m_nStartY : m_nLastY;
  529. rcFocus.bottom = m_nStartY < m_nLastY ? m_nLastY : m_nStartY;
  530. POINT offset;
  531. offset.x = 0;
  532. offset.y = 0;
  533. ClientToScreen( (HWND)getHandle(), &offset );
  534. OffsetRect( &rcFocus, offset.x, offset.y );
  535. f->m_rcFocus = rcFocus;
  536. }
  537. break;
  538. }
  539. }
  540. DrawFocusRect();
  541. }
  542. else
  543. {
  544. if ( m_hPrevCursor )
  545. {
  546. SetCursor( m_hPrevCursor );
  547. m_hPrevCursor = NULL;
  548. }
  549. if ( IsMouseOverScrubHandle( event ) )
  550. {
  551. m_hPrevCursor = SetCursor( LoadCursor( NULL, IDC_SIZEWE ) );
  552. }
  553. /*
  554. else if ( IsMouseOverTag( mx, my ) )
  555. {
  556. m_hPrevCursor = SetCursor( LoadCursor( NULL, IDC_SIZEWE ) );
  557. }
  558. */
  559. // See if anything is selected
  560. if ( CountSelected() <= 0 )
  561. {
  562. // Nothing selected
  563. // Draw auto highlight
  564. DrawAutoHighlight( event );
  565. }
  566. }
  567. m_nLastX = (short)event->x;
  568. m_nLastY = (short)event->y;
  569. }
  570. int SceneRampTool::handleEvent( mxEvent *event )
  571. {
  572. MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
  573. int iret = 0;
  574. if ( HandleToolEvent( event ) )
  575. {
  576. return iret;
  577. }
  578. // Give helper a shot at the event
  579. if ( m_pHelper->HelperHandleEvent( event ) )
  580. {
  581. return 1;
  582. }
  583. switch ( event->event )
  584. {
  585. case mxEvent::Size:
  586. {
  587. int w, h;
  588. w = event->width;
  589. h = event->height;
  590. m_nLastHPixelsNeeded = 0;
  591. InvalidateLayout();
  592. iret = 1;
  593. }
  594. break;
  595. case mxEvent::MouseWheeled:
  596. {
  597. CChoreoScene *scene = g_pChoreoView->GetScene();
  598. if ( scene )
  599. {
  600. int tz = g_pChoreoView->GetTimeZoom( GetToolName() );
  601. bool shiftdown = ( event->modifiers & mxEvent::KeyShift ) ? true : false;
  602. int stepMultipiler = shiftdown ? 5 : 1;
  603. // Zoom time in / out
  604. if ( event->height > 0 )
  605. {
  606. tz = min( tz + TIME_ZOOM_STEP * stepMultipiler, MAX_TIME_ZOOM );
  607. }
  608. else
  609. {
  610. tz = max( tz - TIME_ZOOM_STEP * stepMultipiler, TIME_ZOOM_STEP );
  611. }
  612. g_pChoreoView->SetPreservedTimeZoom( this, tz );
  613. }
  614. redraw();
  615. iret = 1;
  616. }
  617. break;
  618. case mxEvent::MouseDown:
  619. {
  620. bool ctrldown = ( event->modifiers & mxEvent::KeyCtrl ) ? true : false;
  621. bool shiftdown = ( event->modifiers & mxEvent::KeyShift ) ? true : false;
  622. bool rightbutton = ( event->buttons & mxEvent::MouseRightButton ) ? true : false;
  623. iret = 1;
  624. int mx = (short)event->x;
  625. int my = (short)event->y;
  626. SetClickedPos( mx, my );
  627. SetMouseOverPos( mx, my );
  628. DrawMouseOverPos();
  629. POINT pt;
  630. pt.x = mx;
  631. pt.y = my;
  632. RECT rcSamples;
  633. GetSampleTrayRect( rcSamples );
  634. bool insamplearea = PtInRect( &rcSamples, pt ) ? true : false;
  635. if ( m_nDragType == DRAGTYPE_NONE )
  636. {
  637. bool ctrlDown = ( event->modifiers & mxEvent::KeyCtrl ) ? true : false;
  638. CExpressionSample *sample = GetSampleUnderMouse( event->x, event->y, ctrlDown ? FP_SRT_ADDSAMPLE_TOLERANCE : FP_SRT_SELECTION_TOLERANCE );
  639. if ( IsMouseOverScrubHandle( event ) )
  640. {
  641. if ( w2() > 0 )
  642. {
  643. float t = GetTimeValueForMouse( (short)event->x );
  644. m_flScrubberTimeOffset = m_flScrub - t;
  645. float maxoffset = 0.5f * (float)SCRUBBER_HANDLE_WIDTH / GetPixelsPerSecond();
  646. m_flScrubberTimeOffset = clamp( m_flScrubberTimeOffset, -maxoffset, maxoffset );
  647. t += m_flScrubberTimeOffset;
  648. ForceScrubPosition( t );
  649. }
  650. StartDragging( DRAGTYPE_SCRUBBER, m_nClickedX, m_nClickedY, LoadCursor( NULL, IDC_SIZEWE ) );
  651. }
  652. else if ( insamplearea )
  653. {
  654. if ( sample )
  655. {
  656. if ( shiftdown )
  657. {
  658. sample->selected = !sample->selected;
  659. redraw();
  660. }
  661. else if ( sample->selected )
  662. {
  663. PreDataChanged( "move scene ramp points" );
  664. StartDragging(
  665. rightbutton ? DRAGTYPE_MOVEPOINTS_TIME : DRAGTYPE_MOVEPOINTS_VALUE,
  666. m_nClickedX, m_nClickedY,
  667. LoadCursor( NULL, rightbutton ? IDC_SIZEWE : IDC_SIZENS ) );
  668. }
  669. else
  670. {
  671. if ( !shiftdown )
  672. {
  673. DeselectAll();
  674. }
  675. StartDragging( DRAGTYPE_SELECTION, m_nClickedX, m_nClickedY, LoadCursor( NULL, IDC_ARROW ) );
  676. }
  677. }
  678. else if ( ctrldown )
  679. {
  680. CChoreoScene *s = GetSafeScene();
  681. if ( s )
  682. {
  683. // Add a sample point
  684. float t = GetTimeValueForMouse( mx );
  685. t = FacePoser_SnapTime( t );
  686. float value = 1.0f - (float)( (short)event->y - rcSamples.top ) / (float)( rcSamples.bottom - rcSamples.top );
  687. value = clamp( value, 0.0f, 1.0f );
  688. PreDataChanged( "Add scene ramp point" );
  689. s->AddSceneRamp( t, value, false );
  690. s->ResortSceneRamp();
  691. PostDataChanged( "Add scene ramp point" );
  692. }
  693. }
  694. else
  695. {
  696. if ( event->buttons & mxEvent::MouseRightButton )
  697. {
  698. ShowContextMenu( event, false );
  699. iret = 1;
  700. return iret;
  701. }
  702. else
  703. {
  704. if ( !shiftdown )
  705. {
  706. DeselectAll();
  707. }
  708. StartDragging( DRAGTYPE_SELECTION, m_nClickedX, m_nClickedY, LoadCursor( NULL, IDC_ARROW ) );
  709. }
  710. }
  711. }
  712. else
  713. {
  714. if ( event->buttons & mxEvent::MouseRightButton )
  715. {
  716. ShowContextMenu( event, false );
  717. iret = 1;
  718. return iret;
  719. }
  720. else
  721. {
  722. if ( w2() > 0 )
  723. {
  724. float t = GetTimeValueForMouse( (short)event->x );
  725. SetScrubTargetTime( t );
  726. }
  727. }
  728. }
  729. CalcBounds( m_nDragType );
  730. }
  731. }
  732. break;
  733. case mxEvent::MouseDrag:
  734. case mxEvent::MouseMove:
  735. {
  736. int mx = (short)event->x;
  737. int my = (short)event->y;
  738. SetMouseOverPos( mx, my );
  739. DrawMouseOverPos();
  740. OnMouseMove( event );
  741. iret = 1;
  742. }
  743. break;
  744. case mxEvent::MouseUp:
  745. {
  746. OnMouseMove( event );
  747. int mx = (short)event->x;
  748. int my = (short)event->y;
  749. if ( m_nDragType != DRAGTYPE_NONE )
  750. {
  751. DrawFocusRect();
  752. }
  753. if ( m_hPrevCursor )
  754. {
  755. SetCursor( m_hPrevCursor );
  756. m_hPrevCursor = 0;
  757. }
  758. switch ( m_nDragType )
  759. {
  760. case DRAGTYPE_NONE:
  761. break;
  762. case DRAGTYPE_SCRUBBER:
  763. {
  764. ApplyBounds( mx, my );
  765. if ( w2() > 0 )
  766. {
  767. float t = GetTimeValueForMouse( (short)event->x );
  768. t += m_flScrubberTimeOffset;
  769. ForceScrubPosition( t );
  770. m_flScrubberTimeOffset = 0.0f;
  771. }
  772. }
  773. break;
  774. case DRAGTYPE_MOVEPOINTS_VALUE:
  775. case DRAGTYPE_MOVEPOINTS_TIME:
  776. {
  777. PostDataChanged( "move ramp points" );
  778. }
  779. break;
  780. case DRAGTYPE_SELECTION:
  781. {
  782. SelectPoints();
  783. }
  784. break;
  785. }
  786. m_nDragType = DRAGTYPE_NONE;
  787. SetMouseOverPos( mx, my );
  788. DrawMouseOverPos();
  789. redraw();
  790. iret = 1;
  791. }
  792. break;
  793. case mxEvent::Action:
  794. {
  795. iret = 1;
  796. switch ( event->action )
  797. {
  798. default:
  799. iret = 0;
  800. break;
  801. case IDC_UNDO_SRT:
  802. {
  803. OnUndo();
  804. }
  805. break;
  806. case IDC_REDO_SRT:
  807. {
  808. OnRedo();
  809. }
  810. break;
  811. case IDC_SRT_DELETE:
  812. {
  813. Delete();
  814. }
  815. break;
  816. case IDC_SRT_DESELECT:
  817. {
  818. DeselectAll();
  819. }
  820. break;
  821. case IDC_SRT_SELECTALL:
  822. {
  823. SelectAll();
  824. }
  825. break;
  826. case IDC_SRT_RAMPHSCROLL:
  827. {
  828. int offset = 0;
  829. bool processed = true;
  830. switch ( event->modifiers )
  831. {
  832. case SB_THUMBTRACK:
  833. offset = event->height;
  834. break;
  835. case SB_PAGEUP:
  836. offset = m_pHorzScrollBar->getValue();
  837. offset -= 20;
  838. offset = max( offset, m_pHorzScrollBar->getMinValue() );
  839. break;
  840. case SB_PAGEDOWN:
  841. offset = m_pHorzScrollBar->getValue();
  842. offset += 20;
  843. offset = min( offset, m_pHorzScrollBar->getMaxValue() );
  844. break;
  845. case SB_LINEUP:
  846. offset = m_pHorzScrollBar->getValue();
  847. offset -= 10;
  848. offset = max( offset, m_pHorzScrollBar->getMinValue() );
  849. break;
  850. case SB_LINEDOWN:
  851. offset = m_pHorzScrollBar->getValue();
  852. offset += 10;
  853. offset = min( offset, m_pHorzScrollBar->getMaxValue() );
  854. break;
  855. default:
  856. processed = false;
  857. break;
  858. }
  859. if ( processed )
  860. {
  861. MoveTimeSliderToPos( offset );
  862. }
  863. }
  864. break;
  865. case IDC_SRT_CHANGESCALE:
  866. {
  867. OnChangeScale();
  868. }
  869. break;
  870. case IDC_SRT_EDGEPROPERTIES:
  871. {
  872. OnEdgeProperties();
  873. }
  874. break;
  875. }
  876. }
  877. break;
  878. case mxEvent::KeyDown:
  879. {
  880. iret = 1;
  881. switch ( event->key )
  882. {
  883. default:
  884. iret = g_pChoreoView->HandleZoomKey( this, event->key );
  885. break;
  886. case VK_ESCAPE:
  887. DeselectAll();
  888. break;
  889. case VK_DELETE:
  890. Delete();
  891. break;
  892. }
  893. }
  894. }
  895. return iret;
  896. }
  897. void SceneRampTool::ApplyBounds( int& mx, int& my )
  898. {
  899. if ( !m_bUseBounds )
  900. return;
  901. mx = clamp( mx, m_nMinX, m_nMaxX );
  902. }
  903. void SceneRampTool::CalcBounds( int movetype )
  904. {
  905. switch ( movetype )
  906. {
  907. default:
  908. case DRAGTYPE_NONE:
  909. {
  910. m_bUseBounds = false;
  911. m_nMinX = 0;
  912. m_nMaxX = 0;
  913. }
  914. break;
  915. case DRAGTYPE_SCRUBBER:
  916. {
  917. m_bUseBounds = true;
  918. m_nMinX = 0;
  919. m_nMaxX = w2();
  920. }
  921. break;
  922. }
  923. }
  924. bool SceneRampTool::PaintBackground()
  925. {
  926. redraw();
  927. return false;
  928. }
  929. void SceneRampTool::OnUndo( void )
  930. {
  931. g_pChoreoView->Undo();
  932. }
  933. void SceneRampTool::OnRedo( void )
  934. {
  935. g_pChoreoView->Redo();
  936. }
  937. void SceneRampTool::ForceScrubPositionFromSceneTime( float scenetime )
  938. {
  939. CChoreoScene *s = GetSafeScene();
  940. if ( !s || !s->FindStopTime() )
  941. return;
  942. float t = scenetime;
  943. m_flScrub = t;
  944. m_flScrubTarget = t;
  945. DrawScrubHandles();
  946. }
  947. void SceneRampTool::ForceScrubPosition( float t )
  948. {
  949. m_flScrub = t;
  950. m_flScrubTarget = t;
  951. CChoreoScene *s = GetSafeScene();
  952. if ( s && s->FindStopTime() )
  953. {
  954. float realtime = t;
  955. g_pChoreoView->SetScrubTime( realtime );
  956. g_pChoreoView->SetScrubTargetTime( realtime );
  957. g_pChoreoView->DrawScrubHandle();
  958. }
  959. DrawScrubHandles();
  960. }
  961. void SceneRampTool::SetMouseOverPos( int x, int y )
  962. {
  963. m_nMousePos[ 0 ] = x;
  964. m_nMousePos[ 1 ] = y;
  965. }
  966. void SceneRampTool::GetMouseOverPos( int &x, int& y )
  967. {
  968. x = m_nMousePos[ 0 ];
  969. y = m_nMousePos[ 1 ];
  970. }
  971. //-----------------------------------------------------------------------------
  972. // Purpose:
  973. // Input : rcPos -
  974. //-----------------------------------------------------------------------------
  975. void SceneRampTool::GetMouseOverPosRect( RECT& rcPos )
  976. {
  977. rcPos.top = GetCaptionHeight() + 12;
  978. rcPos.left = w2() - 200;
  979. rcPos.right = w2() - 5;
  980. rcPos.bottom = rcPos.top + 13;
  981. }
  982. //-----------------------------------------------------------------------------
  983. // Purpose:
  984. // Input : drawHelper -
  985. // rcPos -
  986. //-----------------------------------------------------------------------------
  987. void SceneRampTool::DrawMouseOverPos( CChoreoWidgetDrawHelper& drawHelper, RECT& rcPos )
  988. {
  989. // Compute time for pixel x
  990. float t = GetTimeValueForMouse( m_nMousePos[ 0 ] );
  991. CChoreoScene *s = GetSafeScene();
  992. if ( !s )
  993. return;
  994. float snapped = FacePoser_SnapTime( t );
  995. // Found it, write out description
  996. //
  997. char sz[ 128 ];
  998. if ( t != snapped )
  999. {
  1000. Q_snprintf( sz, sizeof( sz ), "%s", FacePoser_DescribeSnappedTime( t ) );
  1001. }
  1002. else
  1003. {
  1004. Q_snprintf( sz, sizeof( sz ), "%.3f", t );
  1005. }
  1006. int len = drawHelper.CalcTextWidth( "Arial", 11, 900, sz );
  1007. RECT rcText = rcPos;
  1008. rcText.left = max( rcPos.left, rcPos.right - len );
  1009. drawHelper.DrawColoredText( "Arial", 11, 900, RGB( 255, 50, 70 ), rcText, sz );
  1010. }
  1011. //-----------------------------------------------------------------------------
  1012. // Purpose:
  1013. //-----------------------------------------------------------------------------
  1014. void SceneRampTool::DrawMouseOverPos()
  1015. {
  1016. RECT rcPos;
  1017. GetMouseOverPosRect( rcPos );
  1018. CChoreoWidgetDrawHelper drawHelper( this, rcPos );
  1019. DrawMouseOverPos( drawHelper, rcPos );
  1020. }
  1021. void SceneRampTool::AddFocusRect( RECT& rc )
  1022. {
  1023. RECT rcFocus = rc;
  1024. POINT offset;
  1025. offset.x = 0;
  1026. offset.y = 0;
  1027. ClientToScreen( (HWND)getHandle(), &offset );
  1028. OffsetRect( &rcFocus, offset.x, offset.y );
  1029. // Convert to screen space?
  1030. CFocusRect fr;
  1031. fr.m_rcFocus = rcFocus;
  1032. fr.m_rcOrig = rcFocus;
  1033. m_FocusRects.AddToTail( fr );
  1034. }
  1035. //-----------------------------------------------------------------------------
  1036. // Purpose:
  1037. // Input : drawHelper -
  1038. // rc -
  1039. // left -
  1040. // right -
  1041. //-----------------------------------------------------------------------------
  1042. void SceneRampTool::DrawTimeLine( CChoreoWidgetDrawHelper& drawHelper, RECT& rc, float left, float right )
  1043. {
  1044. RECT rcLabel;
  1045. float granularity = 0.5f;
  1046. drawHelper.DrawColoredLine( RGB( 150, 150, 200 ), PS_SOLID, 1, rc.left, rc.top + 2, rc.right, rc.top + 2 );
  1047. float f = SnapTime( left, granularity );
  1048. while ( f < right )
  1049. {
  1050. float frac = ( f - left ) / ( right - left );
  1051. if ( frac >= 0.0f && frac <= 1.0f )
  1052. {
  1053. rcLabel.left = GetPixelForTimeValue( f );
  1054. rcLabel.top = rc.top + 5;
  1055. rcLabel.bottom = rcLabel.top + 10;
  1056. if ( f != left )
  1057. {
  1058. drawHelper.DrawColoredLine( RGB( 220, 220, 240 ), PS_DOT, 1,
  1059. rcLabel.left, rc.top, rcLabel.left, h2() );
  1060. }
  1061. char sz[ 32 ];
  1062. sprintf( sz, "%.2f", f );
  1063. int textWidth = drawHelper.CalcTextWidth( "Arial", 9, FW_NORMAL, sz );
  1064. rcLabel.right = rcLabel.left + textWidth;
  1065. OffsetRect( &rcLabel, -textWidth / 2, 0 );
  1066. RECT rcOut = rcLabel;
  1067. if ( rcOut.left <= 0 )
  1068. {
  1069. OffsetRect( &rcOut, -rcOut.left + 2, 0 );
  1070. }
  1071. drawHelper.DrawColoredText( "Arial", 9, FW_NORMAL, RGB( 0, 50, 150 ), rcOut, sz );
  1072. }
  1073. f += granularity;
  1074. }
  1075. }
  1076. void SceneRampTool::DrawTimingTags( CChoreoWidgetDrawHelper& drawHelper, RECT& rc )
  1077. {
  1078. CChoreoScene *scene = GetSafeScene();
  1079. if ( !scene )
  1080. return;
  1081. float starttime = GetTimeValueForMouse( 0 );
  1082. float endtime = GetTimeValueForMouse( w2() );
  1083. if ( endtime - starttime <= 0.0f )
  1084. return;
  1085. RECT rcText = rc;
  1086. rcText.bottom = rcText.top + 10;
  1087. drawHelper.DrawColoredText( "Arial", 9, FW_NORMAL, RGB( 0, 100, 200 ), rcText, "Timing Tags:" );
  1088. // Loop through all events in scene
  1089. int c = scene->GetNumEvents();
  1090. int i;
  1091. for ( i = 0; i < c; i++ )
  1092. {
  1093. CChoreoEvent *e = scene->GetEvent( i );
  1094. if ( !e )
  1095. continue;
  1096. // See if time overlaps
  1097. if ( !e->HasEndTime() )
  1098. continue;
  1099. if ( e->GetEndTime() < starttime )
  1100. continue;
  1101. if ( e->GetStartTime() > endtime )
  1102. continue;
  1103. if ( e->GetNumRelativeTags() > 0 )
  1104. {
  1105. DrawRelativeTagsForEvent( drawHelper, rc, e, starttime, endtime );
  1106. }
  1107. if ( e->GetNumAbsoluteTags( CChoreoEvent::PLAYBACK ) > 0 )
  1108. {
  1109. DrawAbsoluteTagsForEvent( drawHelper, rc, e, starttime, endtime );
  1110. }
  1111. }
  1112. }
  1113. //-----------------------------------------------------------------------------
  1114. // Purpose:
  1115. // Input : drawHelper -
  1116. // &rc -
  1117. //-----------------------------------------------------------------------------
  1118. void SceneRampTool::DrawAbsoluteTagsForEvent( CChoreoWidgetDrawHelper& drawHelper, RECT &rc, CChoreoEvent *event, float starttime, float endtime )
  1119. {
  1120. if ( !event )
  1121. return;
  1122. for ( int i = 0; i < event->GetNumAbsoluteTags( CChoreoEvent::PLAYBACK ); i++ )
  1123. {
  1124. CEventAbsoluteTag *tag = event->GetAbsoluteTag( CChoreoEvent::PLAYBACK, i );
  1125. if ( !tag )
  1126. continue;
  1127. float tagtime = ( event->GetStartTime() + tag->GetPercentage() * event->GetDuration() );
  1128. if ( tagtime < starttime || tagtime > endtime )
  1129. continue;
  1130. bool clipped = false;
  1131. int left = GetPixelForTimeValue( tagtime, &clipped );
  1132. if ( clipped )
  1133. continue;
  1134. if ( event->GetType() == CChoreoEvent::GESTURE )
  1135. {
  1136. continue;
  1137. }
  1138. COLORREF clr = RGB( 0, 100, 250 );
  1139. RECT rcMark;
  1140. rcMark = rc;
  1141. rcMark.top = rc.bottom - 8;
  1142. rcMark.bottom = rc.bottom;
  1143. rcMark.left = left - 4;
  1144. rcMark.right = left + 4;
  1145. drawHelper.DrawTriangleMarker( rcMark, clr );
  1146. RECT rcText;
  1147. rcText = rcMark;
  1148. rcText.top -= 12;
  1149. int len = drawHelper.CalcTextWidth( "Arial", 9, FW_NORMAL, tag->GetName() );
  1150. rcText.left = left - len / 2;
  1151. rcText.right = rcText.left + len + 2;
  1152. rcText.bottom = rcText.top + 10;
  1153. drawHelper.DrawColoredText( "Arial", 9, FW_NORMAL, clr, rcText, tag->GetName() );
  1154. }
  1155. }
  1156. //-----------------------------------------------------------------------------
  1157. // Purpose:
  1158. // Input : drawHelper -
  1159. // rc -
  1160. //-----------------------------------------------------------------------------
  1161. void SceneRampTool::DrawRelativeTagsForEvent( CChoreoWidgetDrawHelper& drawHelper, RECT& rc, CChoreoEvent *event, float starttime, float endtime )
  1162. {
  1163. if ( !event )
  1164. return;
  1165. //drawHelper.DrawColoredText( "Arial", 9, FW_NORMAL, PEColor( COLOR_PHONEME_TIMING_TAG ), rc, "Timing Tags:" );
  1166. for ( int i = 0; i < event->GetNumRelativeTags(); i++ )
  1167. {
  1168. CEventRelativeTag *tag = event->GetRelativeTag( i );
  1169. if ( !tag )
  1170. continue;
  1171. //
  1172. float tagtime = ( event->GetStartTime() + tag->GetPercentage() * event->GetDuration() );
  1173. if ( tagtime < starttime || tagtime > endtime )
  1174. continue;
  1175. bool clipped = false;
  1176. int left = GetPixelForTimeValue( tagtime, &clipped );
  1177. if ( clipped )
  1178. continue;
  1179. //float frac = ( tagtime - starttime ) / ( endtime - starttime );
  1180. //int left = rc.left + (int)( frac * ( float )( rc.right - rc.left ) + 0.5f );
  1181. COLORREF clr = RGB( 100, 100, 100 );
  1182. RECT rcMark;
  1183. rcMark = rc;
  1184. rcMark.top = rc.bottom - 8;
  1185. rcMark.bottom = rc.bottom;
  1186. rcMark.left = left - 4;
  1187. rcMark.right = left + 4;
  1188. drawHelper.DrawTriangleMarker( rcMark, clr );
  1189. RECT rcText;
  1190. rcText = rc;
  1191. rcText.bottom = rc.bottom - 10;
  1192. rcText.top = rcText.bottom - 10;
  1193. int len = drawHelper.CalcTextWidth( "Arial", 9, FW_NORMAL, tag->GetName() );
  1194. rcText.left = left - len / 2;
  1195. rcText.right = rcText.left + len + 2;
  1196. drawHelper.DrawColoredText( "Arial", 9, FW_NORMAL, clr, rcText, tag->GetName() );
  1197. }
  1198. }
  1199. //-----------------------------------------------------------------------------
  1200. // Purpose:
  1201. // Output : int
  1202. //-----------------------------------------------------------------------------
  1203. int SceneRampTool::ComputeHPixelsNeeded( void )
  1204. {
  1205. CChoreoScene *scene = GetSafeScene();
  1206. if ( !scene )
  1207. return 0;
  1208. int pixels = 0;
  1209. float maxtime = scene->FindStopTime();
  1210. pixels = (int)( ( maxtime ) * GetPixelsPerSecond() + 10 );
  1211. return pixels;
  1212. }
  1213. //-----------------------------------------------------------------------------
  1214. // Purpose:
  1215. //-----------------------------------------------------------------------------
  1216. void SceneRampTool::RepositionHSlider( void )
  1217. {
  1218. int pixelsneeded = ComputeHPixelsNeeded();
  1219. if ( pixelsneeded <= w2() )
  1220. {
  1221. m_pHorzScrollBar->setVisible( false );
  1222. }
  1223. else
  1224. {
  1225. m_pHorzScrollBar->setVisible( true );
  1226. }
  1227. m_pHorzScrollBar->setBounds( 0, h2() - m_nScrollbarHeight, w2() - m_nScrollbarHeight, m_nScrollbarHeight );
  1228. m_flLeftOffset = max( 0.f, m_flLeftOffset );
  1229. m_flLeftOffset = min( (float)pixelsneeded, m_flLeftOffset );
  1230. m_pHorzScrollBar->setRange( 0, pixelsneeded );
  1231. m_pHorzScrollBar->setValue( (int)m_flLeftOffset );
  1232. m_pHorzScrollBar->setPagesize( w2() );
  1233. m_nLastHPixelsNeeded = pixelsneeded;
  1234. }
  1235. //-----------------------------------------------------------------------------
  1236. // Purpose:
  1237. // Output : float
  1238. //-----------------------------------------------------------------------------
  1239. float SceneRampTool::GetPixelsPerSecond( void )
  1240. {
  1241. return m_flPixelsPerSecond * (float)g_pChoreoView->GetTimeZoom( GetToolName() )/100.0f;
  1242. }
  1243. //-----------------------------------------------------------------------------
  1244. // Purpose:
  1245. // Input : x -
  1246. //-----------------------------------------------------------------------------
  1247. void SceneRampTool::MoveTimeSliderToPos( int x )
  1248. {
  1249. m_flLeftOffset = (float)x;
  1250. m_pHorzScrollBar->setValue( (int)m_flLeftOffset );
  1251. InvalidateRect( (HWND)m_pHorzScrollBar->getHandle(), NULL, TRUE );
  1252. InvalidateLayout();
  1253. }
  1254. //-----------------------------------------------------------------------------
  1255. // Purpose:
  1256. //-----------------------------------------------------------------------------
  1257. void SceneRampTool::InvalidateLayout( void )
  1258. {
  1259. if ( m_bSuppressLayout )
  1260. return;
  1261. if ( ComputeHPixelsNeeded() != m_nLastHPixelsNeeded )
  1262. {
  1263. RepositionHSlider();
  1264. }
  1265. m_bLayoutIsValid = false;
  1266. redraw();
  1267. }
  1268. //-----------------------------------------------------------------------------
  1269. // Purpose:
  1270. // Input : st -
  1271. // ed -
  1272. //-----------------------------------------------------------------------------
  1273. void SceneRampTool::GetStartAndEndTime( float& st, float& ed )
  1274. {
  1275. st = m_flLeftOffset / GetPixelsPerSecond();
  1276. ed = st + (float)w2() / GetPixelsPerSecond();
  1277. }
  1278. //-----------------------------------------------------------------------------
  1279. // Purpose:
  1280. // Input : -
  1281. // Output : float
  1282. //-----------------------------------------------------------------------------
  1283. float SceneRampTool::GetEventEndTime()
  1284. {
  1285. CChoreoScene *scene = GetSafeScene();
  1286. if ( !scene )
  1287. return 1.0f;
  1288. return scene->FindStopTime();
  1289. }
  1290. //-----------------------------------------------------------------------------
  1291. // Purpose:
  1292. // Input : time -
  1293. // *clipped -
  1294. // Output : int
  1295. //-----------------------------------------------------------------------------
  1296. int SceneRampTool::GetPixelForTimeValue( float time, bool *clipped /*=NULL*/ )
  1297. {
  1298. if ( clipped )
  1299. {
  1300. *clipped = false;
  1301. }
  1302. float st, ed;
  1303. GetStartAndEndTime( st, ed );
  1304. float frac = ( time - st ) / ( ed - st );
  1305. if ( frac < 0.0 || frac > 1.0 )
  1306. {
  1307. if ( clipped )
  1308. {
  1309. *clipped = true;
  1310. }
  1311. }
  1312. int pixel = ( int )( frac * w2() );
  1313. return pixel;
  1314. }
  1315. //-----------------------------------------------------------------------------
  1316. // Purpose:
  1317. // Input : mx -
  1318. // clip -
  1319. // Output : float
  1320. //-----------------------------------------------------------------------------
  1321. float SceneRampTool::GetTimeValueForMouse( int mx, bool clip /*=false*/)
  1322. {
  1323. float st, ed;
  1324. GetStartAndEndTime( st, ed );
  1325. if ( clip )
  1326. {
  1327. if ( mx < 0 )
  1328. {
  1329. return st;
  1330. }
  1331. if ( mx > w2() )
  1332. {
  1333. return ed;
  1334. }
  1335. }
  1336. float frac = (float)( mx ) / (float)( w2() );
  1337. return st + frac * ( ed - st );
  1338. }
  1339. void SceneRampTool::OnChangeScale( void )
  1340. {
  1341. CChoreoScene *scene = g_pChoreoView->GetScene();
  1342. if ( !scene )
  1343. {
  1344. return;
  1345. }
  1346. // Zoom time in / out
  1347. CInputParams params;
  1348. memset( &params, 0, sizeof( params ) );
  1349. strcpy( params.m_szDialogTitle, "Change Zoom" );
  1350. strcpy( params.m_szPrompt, "New scale (e.g., 2.5x):" );
  1351. Q_snprintf( params.m_szInputText, sizeof( params.m_szInputText ), "%.2f", (float)g_pChoreoView->GetTimeZoom( GetToolName() ) / 100.0f );
  1352. if ( !InputProperties( &params ) )
  1353. return;
  1354. g_pChoreoView->SetTimeZoom( GetToolName(), clamp( (int)( 100.0f * atof( params.m_szInputText ) ), 1, MAX_TIME_ZOOM ), false );
  1355. m_nLastHPixelsNeeded = -1;
  1356. m_flLeftOffset= 0.0f;
  1357. InvalidateLayout();
  1358. Con_Printf( "Zoom factor %i %%\n", g_pChoreoView->GetTimeZoom( GetToolName() ) );
  1359. }
  1360. void SceneRampTool::DrawSceneEnd( CChoreoWidgetDrawHelper& drawHelper )
  1361. {
  1362. CChoreoScene *s = GetSafeScene();
  1363. if ( !s )
  1364. return;
  1365. float duration = s->FindStopTime();
  1366. if ( !duration )
  1367. return;
  1368. int leftx = GetPixelForTimeValue( duration );
  1369. if ( leftx >= w2() )
  1370. return;
  1371. RECT rcSample;
  1372. GetSampleTrayRect( rcSample );
  1373. drawHelper.DrawColoredLine(
  1374. COLOR_CHOREO_ENDTIME, PS_SOLID, 1,
  1375. leftx, rcSample.top, leftx, rcSample.bottom );
  1376. }
  1377. void SceneRampTool::GetSampleTrayRect( RECT& rc )
  1378. {
  1379. rc.left = 0;
  1380. rc.right = w2();
  1381. rc.top = GetCaptionHeight() + 65;
  1382. rc.bottom = h2() - m_nScrollbarHeight-2;
  1383. }
  1384. void SceneRampTool::DrawSamplesSimple( CChoreoWidgetDrawHelper& drawHelper, CChoreoScene *scene, bool clearbackground, COLORREF sampleColor, RECT &rcSamples )
  1385. {
  1386. if ( clearbackground )
  1387. {
  1388. drawHelper.DrawFilledRect( RGB( 230, 230, 215 ), rcSamples );
  1389. }
  1390. if ( !scene )
  1391. return;
  1392. float starttime = 0.0f;
  1393. float endtime = scene->FindStopTime();
  1394. COLORREF lineColor = sampleColor;
  1395. int width = rcSamples.right - rcSamples.left;
  1396. if ( width <= 0.0f )
  1397. return;
  1398. int height = rcSamples.bottom - rcSamples.top;
  1399. int bottom = rcSamples.bottom;
  1400. float timestepperpixel = endtime / (float)width;
  1401. float prev_value = scene->GetSceneRampIntensity( starttime );
  1402. int prev_x = rcSamples.left;
  1403. float prev_t = 0.0f;
  1404. for ( float x = rcSamples.left; x < rcSamples.right; x+=3 )
  1405. {
  1406. float t = (float)( x - rcSamples.left ) * timestepperpixel;
  1407. float value = scene->GetSceneRampIntensity( starttime + t );
  1408. // Draw segment
  1409. drawHelper.DrawColoredLine( lineColor, PS_SOLID, 1,
  1410. prev_x, bottom - prev_value * height,
  1411. x, bottom - value * height );
  1412. prev_x = x;
  1413. prev_t = t;
  1414. prev_value = value;
  1415. }
  1416. }
  1417. void SceneRampTool::DrawSamples( CChoreoWidgetDrawHelper& drawHelper, RECT &rcSamples )
  1418. {
  1419. drawHelper.DrawFilledRect( RGB( 230, 230, 215 ), rcSamples );
  1420. CChoreoScene *s = GetSafeScene();
  1421. if ( !s )
  1422. return;
  1423. int rampCount = s->GetSceneRampCount();
  1424. if ( !rampCount )
  1425. return;
  1426. float starttime;
  1427. float endtime;
  1428. GetStartAndEndTime( starttime, endtime );
  1429. COLORREF lineColor = RGB( 0, 0, 255 );
  1430. COLORREF dotColor = RGB( 0, 0, 255 );
  1431. COLORREF dotColorSelected = RGB( 240, 80, 20 );
  1432. COLORREF shadowColor = RGB( 150, 150, 250 );
  1433. int height = rcSamples.bottom - rcSamples.top;
  1434. int bottom = rcSamples.bottom;
  1435. int top = rcSamples.top;
  1436. float timestepperpixel = 1.0f / GetPixelsPerSecond();
  1437. float stoptime = min( endtime, s->FindStopTime() );
  1438. float prev_t = starttime;
  1439. float prev_value = s->GetSceneRampIntensity( prev_t );
  1440. for ( float t = starttime-timestepperpixel; t <= stoptime; t += timestepperpixel )
  1441. {
  1442. float value = s->GetSceneRampIntensity( t );
  1443. int prevx, x;
  1444. bool clipped1, clipped2;
  1445. x = GetPixelForTimeValue( t, &clipped1 );
  1446. prevx = GetPixelForTimeValue( prev_t, &clipped2 );
  1447. if ( !clipped1 && !clipped2 )
  1448. {
  1449. // Draw segment
  1450. drawHelper.DrawColoredLine( lineColor, PS_SOLID, 1,
  1451. prevx, clamp( bottom - prev_value * height, top, bottom ),
  1452. x, clamp( bottom - value * height, top, bottom ) );
  1453. }
  1454. prev_t = t;
  1455. prev_value = value;
  1456. }
  1457. for ( int sample = 0; sample < rampCount; sample++ )
  1458. {
  1459. CExpressionSample *start = s->GetSceneRamp( sample );
  1460. /*
  1461. int pixel = (int)( ( start->time / event_time ) * width + 0.5f);
  1462. int x = m_rcBounds.left + pixel;
  1463. float roundedfrac = (float)pixel / (float)width;
  1464. */
  1465. float value = start->value;
  1466. bool clipped = false;
  1467. int x = GetPixelForTimeValue( start->time, &clipped );
  1468. if ( clipped )
  1469. continue;
  1470. int y = bottom - value * height;
  1471. int dotsize = 6;
  1472. int dotSizeSelected = 6;
  1473. COLORREF clr = dotColor;
  1474. COLORREF clrSelected = dotColorSelected;
  1475. drawHelper.DrawCircle(
  1476. start->selected ? clrSelected : clr,
  1477. x, y,
  1478. start->selected ? dotSizeSelected : dotsize,
  1479. true );
  1480. if ( !start->selected )
  1481. continue;
  1482. if ( start->GetCurveType() == CURVE_DEFAULT )
  1483. continue;
  1484. // Draw curve type indicator...
  1485. char sz[ 128 ];
  1486. Q_snprintf( sz, sizeof( sz ), "%s", Interpolator_NameForCurveType( start->GetCurveType(), true ) );
  1487. RECT rc;
  1488. int fontSize = 9;
  1489. rc.top = clamp( y + 5, rcSamples.top + 2, rcSamples.bottom - 2 - fontSize );
  1490. rc.bottom = rc.top + fontSize + 1;
  1491. rc.left = x - 75;
  1492. rc.right = x + 175;
  1493. drawHelper.DrawColoredText( "Arial", fontSize, 500, shadowColor, rc, sz );
  1494. }
  1495. }
  1496. void SceneRampTool::DrawAutoHighlight( mxEvent *event )
  1497. {
  1498. CChoreoScene *s = GetSafeScene();
  1499. if ( !s )
  1500. return;
  1501. CExpressionSample *hover = GetSampleUnderMouse( event->x, event->y, 0.0f );
  1502. RECT rcSamples;
  1503. GetSampleTrayRect( rcSamples );
  1504. CChoreoWidgetDrawHelper drawHelper( this, rcSamples, true );
  1505. RECT rcClient = rcSamples;
  1506. COLORREF dotColor = RGB( 0, 0, 255 );
  1507. COLORREF dotColorSelected = RGB( 240, 80, 20 );
  1508. COLORREF clrHighlighted = RGB( 0, 200, 0 );
  1509. int height = rcClient.bottom - rcClient.top;
  1510. int bottom = rcClient.bottom;
  1511. int dotsize = 6;
  1512. int dotSizeSelected = 6;
  1513. int dotSizeHighlighted = 6;
  1514. COLORREF clr = dotColor;
  1515. COLORREF clrSelected = dotColorSelected;
  1516. COLORREF bgColor = RGB( 230, 230, 200 );
  1517. // Fixme, could look at 1st derivative and do more sampling at high rate of change?
  1518. // or near actual sample points!
  1519. int sampleCount = s->GetSceneRampCount();
  1520. for ( int sample = 0; sample < sampleCount; sample++ )
  1521. {
  1522. CExpressionSample *start = s->GetSceneRamp( sample );
  1523. float value = start->value;
  1524. bool clipped = false;
  1525. int x = GetPixelForTimeValue( start->time, &clipped );
  1526. if ( clipped )
  1527. continue;
  1528. int y = bottom - value * height;
  1529. if ( hover == start )
  1530. {
  1531. drawHelper.DrawCircle(
  1532. bgColor,
  1533. x, y,
  1534. dotSizeHighlighted,
  1535. true );
  1536. drawHelper.DrawCircle(
  1537. clrHighlighted,
  1538. x, y,
  1539. dotSizeHighlighted,
  1540. false );
  1541. }
  1542. else
  1543. {
  1544. drawHelper.DrawCircle(
  1545. start->selected ? clrSelected : clr,
  1546. x, y,
  1547. start->selected ? dotSizeSelected : dotsize,
  1548. true );
  1549. }
  1550. }
  1551. }
  1552. int SceneRampTool::NumSamples()
  1553. {
  1554. CChoreoScene *s = GetSafeScene();
  1555. if ( !s )
  1556. return 0;
  1557. return s->GetSceneRampCount();
  1558. }
  1559. CExpressionSample *SceneRampTool::GetSample( int idx )
  1560. {
  1561. CChoreoScene *s = GetSafeScene();
  1562. if ( !s )
  1563. return NULL;
  1564. return s->GetSceneRamp( idx );
  1565. }
  1566. CExpressionSample *SceneRampTool::GetSampleUnderMouse( int mx, int my, float tolerance /*= FP_SRT_SELECTION_TOLERANCE*/ )
  1567. {
  1568. CChoreoScene *s = GetSafeScene();
  1569. if ( !s )
  1570. return NULL;
  1571. RECT rcSamples;
  1572. GetSampleTrayRect( rcSamples );
  1573. POINT pt;
  1574. pt.x = mx;
  1575. pt.y = my;
  1576. if ( !PtInRect( &rcSamples, pt ) )
  1577. return NULL;
  1578. pt.y -= rcSamples.top;
  1579. float closest_dist = 9999999.f;
  1580. CExpressionSample *bestsample = NULL;
  1581. int height = rcSamples.bottom - rcSamples.top;
  1582. for ( int i = 0; i < s->GetSceneRampCount(); i++ )
  1583. {
  1584. CExpressionSample *sample = s->GetSceneRamp( i );
  1585. Assert( sample );
  1586. bool clipped = false;
  1587. int px = GetPixelForTimeValue( sample->time, &clipped );
  1588. int py = height * ( 1.0f - sample->value );
  1589. int dx = px - pt.x;
  1590. int dy = py - pt.y;
  1591. float dist = sqrt( (float)(dx * dx + dy * dy) );
  1592. if ( dist < closest_dist )
  1593. {
  1594. bestsample = sample;
  1595. closest_dist = dist;
  1596. }
  1597. }
  1598. // Not close to any of them!!!
  1599. if ( ( tolerance != 0.0f ) &&
  1600. ( closest_dist > tolerance ) )
  1601. return NULL;
  1602. return bestsample;
  1603. }
  1604. //-----------------------------------------------------------------------------
  1605. // Purpose:
  1606. //-----------------------------------------------------------------------------
  1607. void SceneRampTool::SelectPoints( void )
  1608. {
  1609. RECT rcSelection;
  1610. rcSelection.left = m_nStartX < m_nLastX ? m_nStartX : m_nLastX;
  1611. rcSelection.right = m_nStartX < m_nLastX ? m_nLastX : m_nStartX;
  1612. rcSelection.top = m_nStartY < m_nLastY ? m_nStartY : m_nLastY;
  1613. rcSelection.bottom = m_nStartY < m_nLastY ? m_nLastY : m_nStartY;
  1614. int selW = rcSelection.right - rcSelection.left;
  1615. int selH = rcSelection.bottom - rcSelection.top;
  1616. float tolerance = FP_SRT_SELECTION_RECTANGLE_TOLERANCE;
  1617. // If they are just clicking and releasing in one spot, capture any items w/in a larger tolerance
  1618. if ( selW <= 2 && selH <= 2 )
  1619. {
  1620. tolerance = FP_SRT_SELECTION_TOLERANCE;
  1621. CExpressionSample *sample = GetSampleUnderMouse( rcSelection.left + selW * 0.5f, rcSelection.top + selH * 0.5f );
  1622. if ( sample )
  1623. {
  1624. sample->selected = true;
  1625. return;
  1626. }
  1627. }
  1628. else
  1629. {
  1630. InflateRect( &rcSelection, 3, 3 );
  1631. }
  1632. RECT rcSamples;
  1633. GetSampleTrayRect( rcSamples );
  1634. int height = rcSamples.bottom - rcSamples.top;
  1635. CChoreoScene *s = GetSafeScene();
  1636. if ( !s )
  1637. return;
  1638. float duration = s->FindStopTime();
  1639. if ( !duration )
  1640. return;
  1641. float fleft = (float)GetTimeValueForMouse( rcSelection.left );
  1642. float fright = (float)GetTimeValueForMouse( rcSelection.right );
  1643. //fleft *= duration;
  1644. //fright *= duration;
  1645. float ftop = (float)( rcSelection.top - rcSamples.top ) / (float)height;
  1646. float fbottom = (float)( rcSelection.bottom - rcSamples.top ) / (float)height;
  1647. fleft = clamp( fleft, 0.0f, duration );
  1648. fright = clamp( fright, 0.0f, duration );
  1649. ftop = clamp( ftop, 0.0f, 1.0f );
  1650. fbottom = clamp( fbottom, 0.0f, 1.0f );
  1651. float timestepperpixel = 1.0f / GetPixelsPerSecond();
  1652. float yfracstepperpixel = 1.0f / (float)height;
  1653. float epsx = tolerance*timestepperpixel;
  1654. float epsy = tolerance*yfracstepperpixel;
  1655. for ( int i = 0; i < s->GetSceneRampCount(); i++ )
  1656. {
  1657. CExpressionSample *sample = s->GetSceneRamp( i );
  1658. if ( sample->time + epsx < fleft )
  1659. continue;
  1660. if ( sample->time - epsx > fright )
  1661. continue;
  1662. if ( (1.0f - sample->value ) + epsy < ftop )
  1663. continue;
  1664. if ( (1.0f - sample->value ) - epsy > fbottom )
  1665. continue;
  1666. sample->selected = true;
  1667. }
  1668. redraw();
  1669. }
  1670. //-----------------------------------------------------------------------------
  1671. // Purpose:
  1672. // Output : int
  1673. //-----------------------------------------------------------------------------
  1674. int SceneRampTool::CountSelected( void )
  1675. {
  1676. return m_pHelper->CountSelected( false );
  1677. }
  1678. void SceneRampTool::MoveSelectedSamples( float dfdx, float dfdy )
  1679. {
  1680. int selecteditems = CountSelected();
  1681. if ( !selecteditems )
  1682. return;
  1683. CChoreoScene *s = GetSafeScene();
  1684. if ( !s )
  1685. return;
  1686. int c = s->GetSceneRampCount();
  1687. float duration = s->FindStopTime();
  1688. //dfdx *= duration;
  1689. for ( int i = 0; i < c; i++ )
  1690. {
  1691. CExpressionSample *sample = s->GetSceneRamp( i );
  1692. if ( !sample || !sample->selected )
  1693. continue;
  1694. sample->time += dfdx;
  1695. sample->time = clamp( sample->time, 0.0f, duration );
  1696. sample->value -= dfdy;
  1697. sample->value = clamp( sample->value, 0.0f, 1.0f );
  1698. }
  1699. s->ResortSceneRamp();
  1700. redraw();
  1701. }
  1702. //-----------------------------------------------------------------------------
  1703. // Purpose:
  1704. //-----------------------------------------------------------------------------
  1705. void SceneRampTool::DeselectAll( void )
  1706. {
  1707. int i;
  1708. int selecteditems = CountSelected();
  1709. if ( !selecteditems )
  1710. return;
  1711. CChoreoScene *s = GetSafeScene();
  1712. Assert( s );
  1713. if ( !s )
  1714. return;
  1715. for ( i = s->GetSceneRampCount() - 1; i >= 0 ; i-- )
  1716. {
  1717. CExpressionSample *sample = s->GetSceneRamp( i );
  1718. sample->selected = false;
  1719. }
  1720. redraw();
  1721. }
  1722. void SceneRampTool::SelectAll( void )
  1723. {
  1724. int i;
  1725. CChoreoScene *s = GetSafeScene();
  1726. Assert( s );
  1727. if ( !s )
  1728. return;
  1729. for ( i = s->GetSceneRampCount() - 1; i >= 0 ; i-- )
  1730. {
  1731. CExpressionSample *sample = s->GetSceneRamp( i );
  1732. sample->selected = true;
  1733. }
  1734. redraw();
  1735. }
  1736. void SceneRampTool::Delete( void )
  1737. {
  1738. int i;
  1739. CChoreoScene *s = GetSafeScene();
  1740. if ( !s )
  1741. return;
  1742. int selecteditems = CountSelected();
  1743. if ( !selecteditems )
  1744. return;
  1745. PreDataChanged( "Delete scene ramp points" );
  1746. for ( i = s->GetSceneRampCount() - 1; i >= 0 ; i-- )
  1747. {
  1748. CExpressionSample *sample = s->GetSceneRamp( i );
  1749. if ( !sample->selected )
  1750. continue;
  1751. s->DeleteSceneRamp( i );
  1752. }
  1753. PostDataChanged( "Delete scene ramp points" );
  1754. }
  1755. void SceneRampTool::OnModelChanged()
  1756. {
  1757. redraw();
  1758. }
  1759. //-----------------------------------------------------------------------------
  1760. // Purpose:
  1761. // Input : *undodescription -
  1762. //-----------------------------------------------------------------------------
  1763. void SceneRampTool::PreDataChanged( char const *undodescription )
  1764. {
  1765. if ( m_nUndoSetup == 0 )
  1766. {
  1767. g_pChoreoView->SetDirty( true );
  1768. g_pChoreoView->PushUndo( undodescription );
  1769. }
  1770. ++m_nUndoSetup;
  1771. }
  1772. //-----------------------------------------------------------------------------
  1773. // Purpose:
  1774. // Input : *redodescription -
  1775. //-----------------------------------------------------------------------------
  1776. void SceneRampTool::PostDataChanged( char const *redodescription )
  1777. {
  1778. --m_nUndoSetup;
  1779. if ( m_nUndoSetup == 0 )
  1780. {
  1781. g_pChoreoView->PushRedo( redodescription );
  1782. redraw();
  1783. }
  1784. }
  1785. void SceneRampTool::SetMousePositionForEvent( mxEvent *event )
  1786. {
  1787. POINT pt;
  1788. GetCursorPos( &pt );
  1789. ScreenToClient( (HWND)getHandle(), &pt );
  1790. event->x = pt.x;
  1791. event->y = pt.y;
  1792. }
  1793. void SceneRampTool::OnEdgeProperties()
  1794. {
  1795. CChoreoScene *s = GetSafeScene();
  1796. if ( !s )
  1797. return;
  1798. CEdgePropertiesParams params;
  1799. Q_memset( &params, 0, sizeof( params ) );
  1800. Q_strcpy( params.m_szDialogTitle, "Edge Properties" );
  1801. params.SetFromCurve( s->GetSceneRamp() );
  1802. if ( !EdgeProperties( &params ) )
  1803. {
  1804. return;
  1805. }
  1806. char *undotext = "Change Scene Ramp Edge Properties";
  1807. PreDataChanged( undotext );
  1808. // Apply changes.
  1809. params.ApplyToCurve( s->GetSceneRamp() );
  1810. PostDataChanged( undotext );
  1811. }
  1812. void SceneRampTool::GetWorkList( bool reflect, CUtlVector< SceneRampTool * >& list )
  1813. {
  1814. NOTE_UNUSED( reflect );
  1815. list.AddToTail( this );
  1816. }