summaryrefslogtreecommitdiff
path: root/utils/hlfaceposer/RampTool.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'utils/hlfaceposer/RampTool.cpp')
-rw-r--r--utils/hlfaceposer/RampTool.cpp2379
1 files changed, 2379 insertions, 0 deletions
diff --git a/utils/hlfaceposer/RampTool.cpp b/utils/hlfaceposer/RampTool.cpp
new file mode 100644
index 0000000..519fc61
--- /dev/null
+++ b/utils/hlfaceposer/RampTool.cpp
@@ -0,0 +1,2379 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+#include <stdio.h>
+#include "hlfaceposer.h"
+#include "RampTool.h"
+#include "mdlviewer.h"
+#include "choreowidgetdrawhelper.h"
+#include "TimelineItem.h"
+#include "expressions.h"
+#include "expclass.h"
+#include "choreoevent.h"
+#include "StudioModel.h"
+#include "choreoscene.h"
+#include "choreoactor.h"
+#include "choreochannel.h"
+#include "ChoreoView.h"
+#include "InputProperties.h"
+#include "ControlPanel.h"
+#include "FlexPanel.h"
+#include "mxExpressionTray.h"
+#include "ExpressionProperties.h"
+#include "tier1/strtools.h"
+#include "faceposer_models.h"
+#include "UtlBuffer.h"
+#include "filesystem.h"
+#include "iscenetokenprocessor.h"
+#include "choreoviewcolors.h"
+#include "MatSysWin.h"
+#include "curveeditorhelpers.h"
+#include "EdgeProperties.h"
+
+RampTool *g_pRampTool = 0;
+
+#define TRAY_HEIGHT 20
+#define TRAY_ITEM_INSET 10
+
+#define TAG_TOP ( TRAY_HEIGHT + 12 )
+#define TAG_BOTTOM ( TAG_TOP + 20 )
+
+#define MAX_TIME_ZOOM 1000
+// 10% per step
+#define TIME_ZOOM_STEP 2
+
+RampTool::RampTool( mxWindow *parent )
+: IFacePoserToolWindow( "RampTool", "Ramp" ), mxWindow( parent, 0, 0, 0, 0 )
+{
+ m_pHelper = new CCurveEditorHelper< RampTool >( this );
+
+ m_bSuppressLayout = false;
+
+ SetAutoProcess( true );
+
+ m_nFocusEventGlobalID = -1;
+
+ m_flScrub = 0.0f;
+ m_flScrubTarget = 0.0f;
+ m_nDragType = DRAGTYPE_NONE;
+
+ m_nClickedX = 0;
+ m_nClickedY = 0;
+
+ m_hPrevCursor = 0;
+
+ m_nStartX = 0;
+ m_nStartY = 0;
+
+ m_pLastEvent = NULL;
+
+ m_nMousePos[ 0 ] = m_nMousePos[ 1 ] = 0;
+
+ m_nMinX = 0;
+ m_nMaxX = 0;
+ m_bUseBounds = false;
+
+ m_bLayoutIsValid = false;
+ m_flPixelsPerSecond = 500.0f;
+
+ m_flLastDuration = 0.0f;
+ m_nScrollbarHeight = 12;
+ m_flLeftOffset = 0.0f;
+ m_nLastHPixelsNeeded = -1;
+ m_pHorzScrollBar = new mxScrollbar( this, 0, 0, 18, 100, IDC_RAMPHSCROLL, mxScrollbar::Horizontal );
+ m_pHorzScrollBar->setVisible( false );
+
+ m_bInSetEvent = false;
+ m_flScrubberTimeOffset = 0.0f;
+
+ m_nUndoSetup = 0;
+}
+
+RampTool::~RampTool( void )
+{
+ delete m_pHelper;
+}
+
+void RampTool::SetEvent( CChoreoEvent *event )
+{
+ if ( m_bInSetEvent )
+ return;
+
+ m_bInSetEvent = true;
+
+ if ( event == m_pLastEvent )
+ {
+ if ( event )
+ {
+ if ( event->GetDuration() != m_flLastDuration )
+ {
+ m_flLastDuration = event->GetDuration();
+ m_nLastHPixelsNeeded = -1;
+ m_flLeftOffset = 0.0f;
+ InvalidateLayout();
+ }
+
+ m_nFocusEventGlobalID = event->GetGlobalID();
+ }
+
+ m_bInSetEvent = false;
+ return;
+ }
+
+ m_pLastEvent = event;
+
+ m_nFocusEventGlobalID = -1;
+ if ( event )
+ {
+ m_nFocusEventGlobalID = event->GetGlobalID();
+ }
+
+ if ( event )
+ {
+ m_flLastDuration = event->GetDuration();
+ }
+ else
+ {
+ m_flLastDuration = 0.0f;
+ }
+ m_flLeftOffset = 0.0f;
+ m_nLastHPixelsNeeded = -1;
+ InvalidateLayout();
+
+ m_bInSetEvent = false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CChoreoEvent *RampTool::GetSafeEvent( void )
+{
+ if ( m_nFocusEventGlobalID == -1 )
+ return NULL;
+
+ if ( !g_pChoreoView )
+ return NULL;
+
+ CChoreoScene *scene = g_pChoreoView->GetScene();
+ if ( !scene )
+ return NULL;
+
+ // Find event by name
+ for ( int i = 0; i < scene->GetNumEvents() ; i++ )
+ {
+ CChoreoEvent *e = scene->GetEvent( i );
+ if ( !e || !e->HasEndTime() )
+ continue;
+
+ if ( e->GetGlobalID() == m_nFocusEventGlobalID )
+ {
+ return e;
+ }
+ }
+
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : rcHandle -
+//-----------------------------------------------------------------------------
+void RampTool::GetScrubHandleRect( RECT& rcHandle, float scrub, bool clipped )
+{
+ float pixel = 0.0f;
+ if ( w2() > 0 )
+ {
+ pixel = GetPixelForTimeValue( scrub );
+
+ if ( clipped )
+ {
+ pixel = clamp( pixel, SCRUBBER_HANDLE_WIDTH / 2, w2() - SCRUBBER_HANDLE_WIDTH / 2 );
+ }
+ }
+
+ rcHandle.left = pixel- SCRUBBER_HANDLE_WIDTH / 2;
+ rcHandle.right = pixel + SCRUBBER_HANDLE_WIDTH / 2;
+ rcHandle.top = 2 + GetCaptionHeight();
+ rcHandle.bottom = rcHandle.top + SCRUBBER_HANDLE_HEIGHT;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : drawHelper -
+// rcHandle -
+//-----------------------------------------------------------------------------
+void RampTool::DrawScrubHandle( CChoreoWidgetDrawHelper& drawHelper, RECT& rcHandle, float scrub, bool reference )
+{
+ HBRUSH br = CreateSolidBrush( reference ? RGB( 150, 0, 0 ) : RGB( 0, 150, 100 ) );
+
+ COLORREF areaBorder = RGB( 230, 230, 220 );
+
+ drawHelper.DrawColoredLine( areaBorder,
+ PS_SOLID, 1, 0, rcHandle.top, w2(), rcHandle.top );
+ drawHelper.DrawColoredLine( areaBorder,
+ PS_SOLID, 1, 0, rcHandle.bottom, w2(), rcHandle.bottom );
+
+ drawHelper.DrawFilledRect( br, rcHandle );
+
+ //
+ char sz[ 32 ];
+ sprintf( sz, "%.3f", scrub );
+
+ CChoreoEvent *ev = GetSafeEvent();
+ if ( ev )
+ {
+ float st, ed;
+ st = ev->GetStartTime();
+ ed = ev->GetEndTime();
+
+ float dt = ed - st;
+ if ( dt > 0.0f )
+ {
+ sprintf( sz, "%.3f", st + scrub );
+ }
+ }
+
+ int len = drawHelper.CalcTextWidth( "Arial", 9, 500, sz );
+
+ RECT rcText = rcHandle;
+
+ int textw = rcText.right - rcText.left;
+
+ rcText.left += ( textw - len ) / 2;
+
+ drawHelper.DrawColoredText( "Arial", 9, 500, RGB( 255, 255, 255 ), rcText, sz );
+
+ DeleteObject( br );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *event -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool RampTool::IsMouseOverScrubHandle( mxEvent *event )
+{
+ RECT rcHandle;
+ GetScrubHandleRect( rcHandle, m_flScrub, true );
+ InflateRect( &rcHandle, 2, 2 );
+
+ POINT pt;
+ pt.x = (short)event->x;
+ pt.y = (short)event->y;
+ if ( PtInRect( &rcHandle, pt ) )
+ {
+ return true;
+ }
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool RampTool::IsProcessing( void )
+{
+ if ( !GetSafeEvent() )
+ return false;
+
+ if ( m_flScrub != m_flScrubTarget )
+ return true;
+
+ return false;
+}
+
+bool RampTool::IsScrubbing( void ) const
+{
+ bool scrubbing = ( m_nDragType == DRAGTYPE_SCRUBBER ) ? true : false;
+ return scrubbing;
+}
+
+void RampTool::SetScrubTime( float t )
+{
+ m_flScrub = t;
+ CChoreoEvent *e = GetSafeEvent();
+ if ( e && e->GetDuration() )
+ {
+ float realtime = e->GetStartTime() + m_flScrub;
+
+ g_pChoreoView->SetScrubTime( realtime );
+ g_pChoreoView->DrawScrubHandle();
+ }
+}
+
+void RampTool::SetScrubTargetTime( float t )
+{
+ m_flScrubTarget = t;
+ CChoreoEvent *e = GetSafeEvent();
+ if ( e && e->GetDuration() )
+ {
+ float realtime = e->GetStartTime() + m_flScrubTarget;
+
+ g_pChoreoView->SetScrubTargetTime( realtime );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : dt -
+//-----------------------------------------------------------------------------
+void RampTool::Think( float dt )
+{
+ CChoreoEvent *event = GetSafeEvent();
+ if ( !event )
+ return;
+
+ bool scrubbing = IsScrubbing();
+ ScrubThink( dt, scrubbing );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : dt -
+//-----------------------------------------------------------------------------
+void RampTool::ScrubThink( float dt, bool scrubbing )
+{
+ CChoreoEvent *event = GetSafeEvent();
+ if ( !event )
+ return;
+
+ if ( m_flScrubTarget == m_flScrub && !scrubbing )
+ return;
+
+ float d = m_flScrubTarget - m_flScrub;
+ int sign = d > 0.0f ? 1 : -1;
+
+ float maxmove = dt;
+
+ if ( sign > 0 )
+ {
+ if ( d < maxmove )
+ {
+ SetScrubTime( m_flScrubTarget );
+ }
+ else
+ {
+ SetScrubTime( m_flScrub + maxmove );
+ }
+ }
+ else
+ {
+ if ( -d < maxmove )
+ {
+ SetScrubTime( m_flScrubTarget );
+ }
+ else
+ {
+ SetScrubTime( m_flScrub - maxmove );
+ }
+ }
+
+ if ( scrubbing )
+ {
+ g_pMatSysWindow->Frame();
+ }
+}
+
+void RampTool::DrawScrubHandles()
+{
+ RECT rcTray;
+
+ RECT rcHandle;
+ GetScrubHandleRect( rcHandle, m_flScrub, true );
+
+ rcTray = rcHandle;
+ rcTray.left = 0;
+ rcTray.right = w2();
+
+ CChoreoWidgetDrawHelper drawHelper( this, rcTray );
+ DrawScrubHandle( drawHelper, rcHandle, m_flScrub, false );
+}
+
+void RampTool::redraw()
+{
+ if ( !ToolCanDraw() )
+ return;
+
+ CChoreoWidgetDrawHelper drawHelper( this );
+ HandleToolRedraw( drawHelper );
+
+ RECT rc;
+ drawHelper.GetClientRect( rc );
+
+ CChoreoEvent *ev = GetSafeEvent();
+ if ( ev )
+ {
+ RECT rcText;
+ drawHelper.GetClientRect( rcText );
+ rcText.top += GetCaptionHeight()+1;
+ rcText.bottom = rcText.top + 13;
+ rcText.left += 5;
+ rcText.right -= 5;
+
+ OffsetRect( &rcText, 0, 12 );
+
+ int current, total;
+
+ g_pChoreoView->GetUndoLevels( current, total );
+ if ( total > 0 )
+ {
+ RECT rcUndo = rcText;
+ OffsetRect( &rcUndo, 0, 2 );
+
+ drawHelper.DrawColoredText( "Small Fonts", 8, FW_NORMAL, RGB( 0, 100, 0 ), rcUndo,
+ "Undo: %i/%i", current, total );
+ }
+
+ rcText.left += 60;
+
+ // Found it, write out description
+ //
+ RECT rcTextLine = rcText;
+
+ drawHelper.DrawColoredText( "Arial", 11, 900, RGB( 200, 0, 0 ), rcTextLine,
+ "Event: %s",
+ ev->GetName() );
+
+ RECT rcTimeLine;
+ drawHelper.GetClientRect( rcTimeLine );
+ rcTimeLine.left = 0;
+ rcTimeLine.right = w2();
+ rcTimeLine.top += ( GetCaptionHeight() + 50 );
+
+ float lefttime = GetTimeValueForMouse( 0 );
+ float righttime = GetTimeValueForMouse( w2() );
+
+ DrawTimeLine( drawHelper, rcTimeLine, lefttime, righttime );
+
+ OffsetRect( &rcText, 0, 28 );
+
+ rcText.left = 5;
+
+ RECT timeRect = rcText;
+
+ timeRect.right = timeRect.left + 100;
+
+ char sz[ 32 ];
+
+ Q_snprintf( sz, sizeof( sz ), "%.2f", lefttime + ev->GetStartTime() );
+
+ drawHelper.DrawColoredText( "Arial", 9, FW_NORMAL, RGB( 0, 0, 0 ), timeRect, sz );
+
+ timeRect = rcText;
+
+ Q_snprintf( sz, sizeof( sz ), "%.2f", righttime + ev->GetStartTime() );
+
+ int textW = drawHelper.CalcTextWidth( "Arial", 9, FW_NORMAL, sz );
+
+ timeRect.right = w2() - 10;
+ timeRect.left = timeRect.right - textW;
+
+ drawHelper.DrawColoredText( "Arial", 9, FW_NORMAL, RGB( 0, 0, 0 ), timeRect, sz );
+ }
+
+ RECT rcHandle;
+ GetScrubHandleRect( rcHandle, m_flScrub, true );
+ DrawScrubHandle( drawHelper, rcHandle, m_flScrub, false );
+
+ RECT rcSamples;
+ GetSampleTrayRect( rcSamples );
+ DrawSamples( drawHelper, rcSamples );
+
+ DrawEventEnd( drawHelper );
+
+ RECT rcTags = rc;
+ rcTags.top = TAG_TOP + GetCaptionHeight();
+ rcTags.bottom = TAG_BOTTOM + GetCaptionHeight();
+
+ DrawTimingTags( drawHelper, rcTags );
+
+ RECT rcPos;
+ GetMouseOverPosRect( rcPos );
+ DrawMouseOverPos( drawHelper, rcPos );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void RampTool::ShowContextMenu( mxEvent *event, bool include_track_menus )
+{
+ // Construct main menu
+ mxPopupMenu *pop = new mxPopupMenu();
+
+ int current, total;
+ g_pChoreoView->GetUndoLevels( current, total );
+ if ( total > 0 )
+ {
+ if ( current > 0 )
+ {
+ pop->add( va( "Undo %s", g_pChoreoView->GetUndoDescription() ), IDC_UNDO_RT );
+ }
+
+ if ( current <= total - 1 )
+ {
+ pop->add( va( "Redo %s", g_pChoreoView->GetRedoDescription() ), IDC_REDO_RT );
+ }
+ pop->addSeparator();
+ }
+
+ CChoreoEvent *e = GetSafeEvent();
+ if ( e )
+ {
+ if ( CountSelected() > 0 )
+ {
+ pop->add( va( "Delete" ), IDC_RT_DELETE );
+ pop->add( "Deselect all", IDC_RT_DESELECT );
+ }
+ pop->add( "Select all", IDC_RT_SELECTALL );
+ }
+
+ pop->add( va( "Change scale..." ), IDC_RT_CHANGESCALE );
+ pop->addSeparator();
+ pop->add( "Edge Properties...", IDC_RT_EDGEPROPERTIES );
+
+ pop->popup( this, (short)event->x, (short)event->y );
+}
+
+void RampTool::GetWorkspaceLeftRight( int& left, int& right )
+{
+ left = 0;
+ right = w2();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void RampTool::DrawFocusRect( void )
+{
+ HDC dc = GetDC( NULL );
+
+ for ( int i = 0; i < m_FocusRects.Size(); i++ )
+ {
+ RECT rc = m_FocusRects[ i ].m_rcFocus;
+
+ ::DrawFocusRect( dc, &rc );
+ }
+
+ ReleaseDC( NULL, dc );
+}
+
+void RampTool::SetClickedPos( int x, int y )
+{
+ m_nClickedX = x;
+ m_nClickedY = y;
+}
+
+float RampTool::GetTimeForClickedPos( void )
+{
+ CChoreoEvent *e = GetSafeEvent();
+ if ( !e )
+ return 0.0f;
+
+ float t = GetTimeValueForMouse( m_nClickedX );
+ return t;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : dragtype -
+// startx -
+// cursor -
+//-----------------------------------------------------------------------------
+void RampTool::StartDragging( int dragtype, int startx, int starty, HCURSOR cursor )
+{
+ m_nDragType = dragtype;
+ m_nStartX = startx;
+ m_nLastX = startx;
+ m_nStartY = starty;
+ m_nLastY = starty;
+
+ if ( m_hPrevCursor )
+ {
+ SetCursor( m_hPrevCursor );
+ m_hPrevCursor = NULL;
+ }
+ m_hPrevCursor = SetCursor( cursor );
+
+ m_FocusRects.Purge();
+
+ RECT rcStart;
+ rcStart.left = startx;
+ rcStart.right = startx;
+
+ bool addrect = true;
+ switch ( dragtype )
+ {
+ case DRAGTYPE_SCRUBBER:
+ {
+ RECT rcScrub;
+ GetScrubHandleRect( rcScrub, m_flScrub, true );
+
+ rcStart = rcScrub;
+ rcStart.left = ( rcScrub.left + rcScrub.right ) / 2;
+ rcStart.right = rcStart.left;
+ rcStart.top = rcScrub.bottom;
+
+ rcStart.bottom = h2();
+ }
+ break;
+ default:
+ {
+ rcStart.top = starty;
+ rcStart.bottom = starty;
+ }
+ break;
+ }
+
+
+ if ( addrect )
+ {
+ AddFocusRect( rcStart );
+ }
+
+ DrawFocusRect();
+}
+
+void RampTool::OnMouseMove( mxEvent *event )
+{
+ int mx = (short)event->x;
+ int my = (short)event->y;
+
+ event->x = (short)mx;
+
+ if ( m_nDragType != DRAGTYPE_NONE )
+ {
+ DrawFocusRect();
+
+ for ( int i = 0; i < m_FocusRects.Size(); i++ )
+ {
+ CFocusRect *f = &m_FocusRects[ i ];
+ f->m_rcFocus = f->m_rcOrig;
+
+ switch ( m_nDragType )
+ {
+ default:
+ {
+ OffsetRect( &f->m_rcFocus, ( mx - m_nStartX ), ( my - m_nStartY ) );
+ }
+ break;
+ case DRAGTYPE_SCRUBBER:
+ {
+ ApplyBounds( mx, my );
+ if ( w2() > 0 )
+ {
+ float t = GetTimeValueForMouse( mx );
+ t += m_flScrubberTimeOffset;
+ ForceScrubPosition( t );
+ }
+
+ OffsetRect( &f->m_rcFocus, ( mx - m_nStartX ), 0 );
+ }
+ break;
+ case DRAGTYPE_MOVEPOINTS_TIME:
+ case DRAGTYPE_MOVEPOINTS_VALUE:
+ {
+ int dx = mx - m_nLastX;
+ int dy = my - m_nLastY;
+
+ if ( !( event->modifiers & mxEvent::KeyCtrl ) )
+ {
+ // Zero out motion on other axis
+ if ( m_nDragType == DRAGTYPE_MOVEPOINTS_VALUE )
+ {
+ dx = 0;
+ mx = m_nLastX;
+ }
+ else
+ {
+ dy = 0;
+ my = m_nLastY;
+ }
+ }
+ else
+ {
+ SetCursor( LoadCursor( NULL, IDC_SIZEALL ) );
+ }
+
+ RECT rcSamples;
+ GetSampleTrayRect( rcSamples );
+
+ int height = rcSamples.bottom - rcSamples.top;
+ Assert( height > 0 );
+
+ float dfdx = (float)dx / GetPixelsPerSecond();
+ float dfdy = (float)dy / (float)height;
+
+ MoveSelectedSamples( dfdx, dfdy );
+
+ // Update the scrubber
+ if ( w2() > 0 )
+ {
+ float t = GetTimeValueForMouse( mx );
+ ForceScrubPosition( t );
+ g_pMatSysWindow->Frame();
+ }
+
+ OffsetRect( &f->m_rcFocus, dx, dy );
+ }
+ break;
+ case DRAGTYPE_SELECTION:
+ {
+ RECT rcFocus;
+
+ rcFocus.left = m_nStartX < m_nLastX ? m_nStartX : m_nLastX;
+ rcFocus.right = m_nStartX < m_nLastX ? m_nLastX : m_nStartX;
+
+ rcFocus.top = m_nStartY < m_nLastY ? m_nStartY : m_nLastY;
+ rcFocus.bottom = m_nStartY < m_nLastY ? m_nLastY : m_nStartY;
+
+ POINT offset;
+ offset.x = 0;
+ offset.y = 0;
+ ClientToScreen( (HWND)getHandle(), &offset );
+ OffsetRect( &rcFocus, offset.x, offset.y );
+
+ f->m_rcFocus = rcFocus;
+ }
+ break;
+ }
+ }
+
+ DrawFocusRect();
+ }
+ else
+ {
+ if ( m_hPrevCursor )
+ {
+ SetCursor( m_hPrevCursor );
+ m_hPrevCursor = NULL;
+ }
+
+ if ( IsMouseOverScrubHandle( event ) )
+ {
+ m_hPrevCursor = SetCursor( LoadCursor( NULL, IDC_SIZEWE ) );
+ }
+ /*
+ else if ( IsMouseOverTag( mx, my ) )
+ {
+ m_hPrevCursor = SetCursor( LoadCursor( NULL, IDC_SIZEWE ) );
+ }
+ */
+
+ // See if anything is selected
+ if ( CountSelected() <= 0 )
+ {
+ // Nothing selected
+ // Draw auto highlight
+ DrawAutoHighlight( event );
+ }
+ }
+
+ m_nLastX = (short)event->x;
+ m_nLastY = (short)event->y;
+}
+
+int RampTool::handleEvent( mxEvent *event )
+{
+ MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
+
+ int iret = 0;
+
+ if ( HandleToolEvent( event ) )
+ {
+ return iret;
+ }
+
+ // Give helper a shot at the event
+ if ( m_pHelper->HelperHandleEvent( event ) )
+ {
+ return 1;
+ }
+
+ switch ( event->event )
+ {
+ case mxEvent::Size:
+ {
+ int w, h;
+ w = event->width;
+ h = event->height;
+
+ m_nLastHPixelsNeeded = 0;
+ InvalidateLayout();
+ iret = 1;
+ }
+ break;
+ case mxEvent::MouseWheeled:
+ {
+ CChoreoScene *scene = g_pChoreoView->GetScene();
+ if ( scene )
+ {
+ int tz = g_pChoreoView->GetTimeZoom( GetToolName() );
+ bool shiftdown = ( event->modifiers & mxEvent::KeyShift ) ? true : false;
+ int stepMultipiler = shiftdown ? 5 : 1;
+
+ // Zoom time in / out
+ if ( event->height > 0 )
+ {
+ tz = min( tz + TIME_ZOOM_STEP * stepMultipiler, MAX_TIME_ZOOM );
+ }
+ else
+ {
+ tz = max( tz - TIME_ZOOM_STEP * stepMultipiler, TIME_ZOOM_STEP );
+ }
+
+ g_pChoreoView->SetPreservedTimeZoom( this, tz );
+ }
+
+ redraw();
+ iret = 1;
+ }
+ break;
+ case mxEvent::MouseDown:
+ {
+ bool ctrldown = ( event->modifiers & mxEvent::KeyCtrl ) ? true : false;
+ bool shiftdown = ( event->modifiers & mxEvent::KeyShift ) ? true : false;
+
+ bool rightbutton = ( event->buttons & mxEvent::MouseRightButton ) ? true : false;
+
+ iret = 1;
+
+ int mx = (short)event->x;
+ int my = (short)event->y;
+
+ SetClickedPos( mx, my );
+
+ SetMouseOverPos( mx, my );
+ DrawMouseOverPos();
+
+ POINT pt;
+ pt.x = mx;
+ pt.y = my;
+
+ RECT rcSamples;
+ GetSampleTrayRect( rcSamples );
+
+ bool insamplearea = PtInRect( &rcSamples, pt ) ? true : false;
+
+ if ( m_nDragType == DRAGTYPE_NONE )
+ {
+ bool ctrlDown = ( event->modifiers & mxEvent::KeyCtrl ) ? true : false;
+
+ CExpressionSample *sample = GetSampleUnderMouse( event->x, event->y, ctrlDown ? FP_RT_ADDSAMPLE_TOLERANCE : FP_RT_SELECTION_TOLERANCE );
+
+ if ( IsMouseOverScrubHandle( event ) )
+ {
+ if ( w2() > 0 )
+ {
+ float t = GetTimeValueForMouse( (short)event->x );
+ m_flScrubberTimeOffset = m_flScrub - t;
+ float maxoffset = 0.5f * (float)SCRUBBER_HANDLE_WIDTH / GetPixelsPerSecond();
+ m_flScrubberTimeOffset = clamp( m_flScrubberTimeOffset, -maxoffset, maxoffset );
+ t += m_flScrubberTimeOffset;
+ ForceScrubPosition( t );
+ }
+
+ StartDragging( DRAGTYPE_SCRUBBER, m_nClickedX, m_nClickedY, LoadCursor( NULL, IDC_SIZEWE ) );
+ }
+ else if ( insamplearea )
+ {
+ if ( sample )
+ {
+ if ( shiftdown )
+ {
+ sample->selected = !sample->selected;
+ redraw();
+ }
+ else if ( sample->selected )
+ {
+ PreDataChanged( "move ramp points" );
+
+ StartDragging(
+ rightbutton ? DRAGTYPE_MOVEPOINTS_TIME : DRAGTYPE_MOVEPOINTS_VALUE,
+ m_nClickedX, m_nClickedY,
+ LoadCursor( NULL, rightbutton ? IDC_SIZEWE : IDC_SIZENS ) );
+ }
+ else
+ {
+ if ( !shiftdown )
+ {
+ DeselectAll();
+ }
+
+ StartDragging( DRAGTYPE_SELECTION, m_nClickedX, m_nClickedY, LoadCursor( NULL, IDC_ARROW ) );
+ }
+ }
+ else if ( ctrldown )
+ {
+ CChoreoEvent *e = GetSafeEvent();
+ if ( e )
+ {
+ // Add a sample point
+ float t = GetTimeValueForMouse( mx );
+
+ t = FacePoser_SnapTime( t );
+ float value = 1.0f - (float)( (short)event->y - rcSamples.top ) / (float)( rcSamples.bottom - rcSamples.top );
+ value = clamp( value, 0.0f, 1.0f );
+
+ PreDataChanged( "Add ramp point" );
+
+ e->AddRamp( t, value, false );
+
+ e->ResortRamp();
+
+ PostDataChanged( "Add ramp point" );
+ }
+ }
+ else
+ {
+ if ( event->buttons & mxEvent::MouseRightButton )
+ {
+ ShowContextMenu( event, false );
+ iret = 1;
+ return iret;
+ }
+ else
+ {
+ if ( !shiftdown )
+ {
+ DeselectAll();
+ }
+
+ StartDragging( DRAGTYPE_SELECTION, m_nClickedX, m_nClickedY, LoadCursor( NULL, IDC_ARROW ) );
+ }
+ }
+ }
+ else
+ {
+ if ( event->buttons & mxEvent::MouseRightButton )
+ {
+ ShowContextMenu( event, false );
+ iret = 1;
+ return iret;
+ }
+ else
+ {
+ if ( w2() > 0 )
+ {
+ float t = GetTimeValueForMouse( (short)event->x );
+
+ SetScrubTargetTime( t );
+ }
+ }
+ }
+
+ CalcBounds( m_nDragType );
+ }
+ }
+ break;
+ case mxEvent::MouseDrag:
+ case mxEvent::MouseMove:
+ {
+ int mx = (short)event->x;
+ int my = (short)event->y;
+
+ SetMouseOverPos( mx, my );
+ DrawMouseOverPos();
+
+ OnMouseMove( event );
+
+ iret = 1;
+ }
+ break;
+ case mxEvent::MouseUp:
+ {
+ OnMouseMove( event );
+
+ int mx = (short)event->x;
+ int my = (short)event->y;
+
+ if ( m_nDragType != DRAGTYPE_NONE )
+ {
+ DrawFocusRect();
+ }
+
+ if ( m_hPrevCursor )
+ {
+ SetCursor( m_hPrevCursor );
+ m_hPrevCursor = 0;
+ }
+
+ switch ( m_nDragType )
+ {
+ case DRAGTYPE_NONE:
+ break;
+ case DRAGTYPE_SCRUBBER:
+ {
+ ApplyBounds( mx, my );
+
+ if ( w2() > 0 )
+ {
+ float t = GetTimeValueForMouse( (short)event->x );
+ t += m_flScrubberTimeOffset;
+ ForceScrubPosition( t );
+ m_flScrubberTimeOffset = 0.0f;
+ }
+ }
+ break;
+ case DRAGTYPE_MOVEPOINTS_VALUE:
+ case DRAGTYPE_MOVEPOINTS_TIME:
+ {
+ PostDataChanged( "move ramp points" );
+ }
+ break;
+ case DRAGTYPE_SELECTION:
+ {
+ SelectPoints();
+ }
+ break;
+ }
+
+ m_nDragType = DRAGTYPE_NONE;
+
+ SetMouseOverPos( mx, my );
+ DrawMouseOverPos();
+
+ redraw();
+
+ iret = 1;
+ }
+ break;
+ case mxEvent::Action:
+ {
+ iret = 1;
+ switch ( event->action )
+ {
+ default:
+ iret = 0;
+ break;
+ case IDC_UNDO_RT:
+ {
+ OnUndo();
+ }
+ break;
+ case IDC_REDO_RT:
+ {
+ OnRedo();
+ }
+ break;
+ case IDC_RT_DELETE:
+ {
+ Delete();
+ }
+ break;
+ case IDC_RT_DESELECT:
+ {
+ DeselectAll();
+ }
+ break;
+ case IDC_RT_SELECTALL:
+ {
+ SelectAll();
+ }
+ break;
+ case IDC_RAMPHSCROLL:
+ {
+ int offset = 0;
+ bool processed = true;
+
+ switch ( event->modifiers )
+ {
+ case SB_THUMBTRACK:
+ offset = event->height;
+ break;
+ case SB_PAGEUP:
+ offset = m_pHorzScrollBar->getValue();
+ offset -= 20;
+ offset = max( offset, m_pHorzScrollBar->getMinValue() );
+ break;
+ case SB_PAGEDOWN:
+ offset = m_pHorzScrollBar->getValue();
+ offset += 20;
+ offset = min( offset, m_pHorzScrollBar->getMaxValue() );
+ break;
+ case SB_LINEUP:
+ offset = m_pHorzScrollBar->getValue();
+ offset -= 10;
+ offset = max( offset, m_pHorzScrollBar->getMinValue() );
+ break;
+ case SB_LINEDOWN:
+ offset = m_pHorzScrollBar->getValue();
+ offset += 10;
+ offset = min( offset, m_pHorzScrollBar->getMaxValue() );
+ break;
+ default:
+ processed = false;
+ break;
+ }
+
+ if ( processed )
+ {
+ MoveTimeSliderToPos( offset );
+ }
+ }
+ break;
+ case IDC_RT_CHANGESCALE:
+ {
+ OnChangeScale();
+ }
+ break;
+ case IDC_RT_EDGEPROPERTIES:
+ {
+ OnEdgeProperties();
+ }
+ break;
+ }
+ }
+ break;
+ case mxEvent::KeyDown:
+ {
+ iret = 1;
+ switch ( event->key )
+ {
+ default:
+ iret = g_pChoreoView->HandleZoomKey( this, event->key );
+ break;
+ case VK_ESCAPE:
+ DeselectAll();
+ break;
+ case VK_DELETE:
+ Delete();
+ break;
+ }
+ }
+ }
+ return iret;
+}
+
+void RampTool::ApplyBounds( int& mx, int& my )
+{
+ if ( !m_bUseBounds )
+ return;
+
+ mx = clamp( mx, m_nMinX, m_nMaxX );
+}
+
+void RampTool::CalcBounds( int movetype )
+{
+ switch ( movetype )
+ {
+ default:
+ case DRAGTYPE_NONE:
+ {
+ m_bUseBounds = false;
+ m_nMinX = 0;
+ m_nMaxX = 0;
+ }
+ break;
+ case DRAGTYPE_SCRUBBER:
+ {
+ m_bUseBounds = true;
+ m_nMinX = 0;
+ m_nMaxX = w2();
+ }
+ break;
+ }
+}
+
+bool RampTool::PaintBackground()
+{
+ redraw();
+ return false;
+}
+
+void RampTool::OnUndo( void )
+{
+ g_pChoreoView->Undo();
+}
+
+void RampTool::OnRedo( void )
+{
+ g_pChoreoView->Redo();
+}
+
+void RampTool::ForceScrubPositionFromSceneTime( float scenetime )
+{
+ CChoreoEvent *e = GetSafeEvent();
+ if ( !e || !e->GetDuration() )
+ return;
+
+ float t = scenetime - e->GetStartTime();
+ m_flScrub = t;
+ m_flScrubTarget = t;
+ DrawScrubHandles();
+}
+
+void RampTool::ForceScrubPosition( float t )
+{
+ m_flScrub = t;
+ m_flScrubTarget = t;
+
+ CChoreoEvent *e = GetSafeEvent();
+ if ( e && e->GetDuration() )
+ {
+ float realtime = e->GetStartTime() + t;
+
+ g_pChoreoView->SetScrubTime( realtime );
+ g_pChoreoView->SetScrubTargetTime( realtime );
+
+ g_pChoreoView->DrawScrubHandle();
+ }
+
+ DrawScrubHandles();
+}
+
+void RampTool::SetMouseOverPos( int x, int y )
+{
+ m_nMousePos[ 0 ] = x;
+ m_nMousePos[ 1 ] = y;
+}
+
+void RampTool::GetMouseOverPos( int &x, int& y )
+{
+ x = m_nMousePos[ 0 ];
+ y = m_nMousePos[ 1 ];
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : rcPos -
+//-----------------------------------------------------------------------------
+void RampTool::GetMouseOverPosRect( RECT& rcPos )
+{
+ rcPos.top = GetCaptionHeight() + 12;
+ rcPos.left = w2() - 200;
+ rcPos.right = w2() - 5;
+ rcPos.bottom = rcPos.top + 13;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : drawHelper -
+// rcPos -
+//-----------------------------------------------------------------------------
+void RampTool::DrawMouseOverPos( CChoreoWidgetDrawHelper& drawHelper, RECT& rcPos )
+{
+ // Compute time for pixel x
+ float t = GetTimeValueForMouse( m_nMousePos[ 0 ] );
+ CChoreoEvent *e = GetSafeEvent();
+ if ( !e )
+ return;
+
+ t += e->GetStartTime();
+ float snapped = FacePoser_SnapTime( t );
+
+ // Found it, write out description
+ //
+ char sz[ 128 ];
+ if ( t != snapped )
+ {
+ Q_snprintf( sz, sizeof( sz ), "%s", FacePoser_DescribeSnappedTime( t ) );
+ }
+ else
+ {
+ Q_snprintf( sz, sizeof( sz ), "%.3f", t );
+ }
+
+ int len = drawHelper.CalcTextWidth( "Arial", 11, 900, sz );
+
+ RECT rcText = rcPos;
+ rcText.left = max( rcPos.left, rcPos.right - len );
+
+ drawHelper.DrawColoredText( "Arial", 11, 900, RGB( 255, 50, 70 ), rcText, sz );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void RampTool::DrawMouseOverPos()
+{
+ RECT rcPos;
+ GetMouseOverPosRect( rcPos );
+
+ CChoreoWidgetDrawHelper drawHelper( this, rcPos );
+ DrawMouseOverPos( drawHelper, rcPos );
+}
+
+void RampTool::AddFocusRect( RECT& rc )
+{
+ RECT rcFocus = rc;
+
+ POINT offset;
+ offset.x = 0;
+ offset.y = 0;
+ ClientToScreen( (HWND)getHandle(), &offset );
+ OffsetRect( &rcFocus, offset.x, offset.y );
+
+ // Convert to screen space?
+ CFocusRect fr;
+ fr.m_rcFocus = rcFocus;
+ fr.m_rcOrig = rcFocus;
+
+ m_FocusRects.AddToTail( fr );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : drawHelper -
+// rc -
+// left -
+// right -
+//-----------------------------------------------------------------------------
+void RampTool::DrawTimeLine( CChoreoWidgetDrawHelper& drawHelper, RECT& rc, float left, float right )
+{
+ RECT rcLabel;
+ float granularity = 0.5f;
+
+ drawHelper.DrawColoredLine( RGB( 150, 150, 200 ), PS_SOLID, 1, rc.left, rc.top + 2, rc.right, rc.top + 2 );
+
+ float f = SnapTime( left, granularity );
+ while ( f < right )
+ {
+ float frac = ( f - left ) / ( right - left );
+ if ( frac >= 0.0f && frac <= 1.0f )
+ {
+ rcLabel.left = GetPixelForTimeValue( f );
+ rcLabel.top = rc.top + 5;
+ rcLabel.bottom = rcLabel.top + 10;
+
+ if ( f != left )
+ {
+ drawHelper.DrawColoredLine( RGB( 220, 220, 240 ), PS_DOT, 1,
+ rcLabel.left, rc.top, rcLabel.left, h2() );
+ }
+
+ char sz[ 32 ];
+ sprintf( sz, "%.2f", f );
+
+ int textWidth = drawHelper.CalcTextWidth( "Arial", 9, FW_NORMAL, sz );
+
+ rcLabel.right = rcLabel.left + textWidth;
+
+ OffsetRect( &rcLabel, -textWidth / 2, 0 );
+
+ RECT rcOut = rcLabel;
+ if ( rcOut.left <= 0 )
+ {
+ OffsetRect( &rcOut, -rcOut.left + 2, 0 );
+ }
+
+ drawHelper.DrawColoredText( "Arial", 9, FW_NORMAL, RGB( 0, 50, 150 ), rcOut, sz );
+
+ }
+ f += granularity;
+ }
+}
+
+void RampTool::DrawTimingTags( CChoreoWidgetDrawHelper& drawHelper, RECT& rc )
+{
+ CChoreoEvent *rampevent = GetSafeEvent();
+ if ( !rampevent )
+ return;
+
+ CChoreoScene *scene = rampevent->GetScene();
+ if ( !scene )
+ return;
+
+ float starttime = GetTimeValueForMouse( 0 );
+ float endtime = GetTimeValueForMouse( w2() );
+
+ if ( endtime - starttime <= 0.0f )
+ return;
+
+ RECT rcText = rc;
+ rcText.bottom = rcText.top + 10;
+
+ drawHelper.DrawColoredText( "Arial", 9, FW_NORMAL, RGB( 0, 100, 200 ), rcText, "Timing Tags:" );
+
+ // Loop through all events in scene
+
+ int c = scene->GetNumEvents();
+ int i;
+ for ( i = 0; i < c; i++ )
+ {
+ CChoreoEvent *e = scene->GetEvent( i );
+ if ( !e )
+ continue;
+
+ // See if time overlaps
+ if ( !e->HasEndTime() )
+ continue;
+
+ if ( ( e->GetEndTime() - e->GetStartTime() ) < starttime )
+ continue;
+
+ if ( ( e->GetStartTime() - e->GetStartTime() ) > endtime )
+ continue;
+
+ if ( e->GetNumRelativeTags() > 0 )
+ {
+ DrawRelativeTagsForEvent( drawHelper, rc, rampevent, e, starttime, endtime );
+ }
+ if ( e->GetNumAbsoluteTags( CChoreoEvent::PLAYBACK ) > 0 )
+ {
+ DrawAbsoluteTagsForEvent( drawHelper, rc, rampevent, e, starttime, endtime );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : drawHelper -
+// &rc -
+//-----------------------------------------------------------------------------
+void RampTool::DrawAbsoluteTagsForEvent( CChoreoWidgetDrawHelper& drawHelper, RECT &rc, CChoreoEvent *rampevent, CChoreoEvent *event, float starttime, float endtime )
+{
+ if ( !event )
+ return;
+
+ for ( int i = 0; i < event->GetNumAbsoluteTags( CChoreoEvent::PLAYBACK ); i++ )
+ {
+ CEventAbsoluteTag *tag = event->GetAbsoluteTag( CChoreoEvent::PLAYBACK, i );
+ if ( !tag )
+ continue;
+
+ float tagtime = ( event->GetStartTime() + tag->GetPercentage() * event->GetDuration() ) - rampevent->GetStartTime();
+ if ( tagtime < starttime || tagtime > endtime )
+ continue;
+
+ bool clipped = false;
+ int left = GetPixelForTimeValue( tagtime, &clipped );
+ if ( clipped )
+ continue;
+
+ // Don't add gesture tags except for the current event
+ if ( event != rampevent &&
+ event->GetType() == CChoreoEvent::GESTURE )
+ {
+ continue;
+ }
+
+ COLORREF clr = event == rampevent ? RGB( 0, 100, 250 ) : RGB( 100, 100, 100 );
+
+ RECT rcMark;
+ rcMark = rc;
+ rcMark.top = rc.bottom - 8;
+ rcMark.bottom = rc.bottom;
+ rcMark.left = left - 4;
+ rcMark.right = left + 4;
+
+ drawHelper.DrawTriangleMarker( rcMark, clr );
+
+ RECT rcText;
+ rcText = rcMark;
+ rcText.top -= 12;
+
+ int len = drawHelper.CalcTextWidth( "Arial", 9, FW_NORMAL, tag->GetName() );
+ rcText.left = left - len / 2;
+ rcText.right = rcText.left + len + 2;
+
+ rcText.bottom = rcText.top + 10;
+
+ drawHelper.DrawColoredText( "Arial", 9, FW_NORMAL, clr, rcText, tag->GetName() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : drawHelper -
+// rc -
+//-----------------------------------------------------------------------------
+void RampTool::DrawRelativeTagsForEvent( CChoreoWidgetDrawHelper& drawHelper, RECT& rc, CChoreoEvent *rampevent, CChoreoEvent *event, float starttime, float endtime )
+{
+ if ( !event )
+ return;
+
+ //drawHelper.DrawColoredText( "Arial", 9, FW_NORMAL, PEColor( COLOR_PHONEME_TIMING_TAG ), rc, "Timing Tags:" );
+
+ for ( int i = 0; i < event->GetNumRelativeTags(); i++ )
+ {
+ CEventRelativeTag *tag = event->GetRelativeTag( i );
+ if ( !tag )
+ continue;
+
+ //
+ float tagtime = ( event->GetStartTime() + tag->GetPercentage() * event->GetDuration() ) - rampevent->GetStartTime();
+ if ( tagtime < starttime || tagtime > endtime )
+ continue;
+
+ bool clipped = false;
+ int left = GetPixelForTimeValue( tagtime, &clipped );
+ if ( clipped )
+ continue;
+
+ //float frac = ( tagtime - starttime ) / ( endtime - starttime );
+
+ //int left = rc.left + (int)( frac * ( float )( rc.right - rc.left ) + 0.5f );
+
+ COLORREF clr = event == rampevent ? RGB( 0, 100, 250 ) : RGB( 100, 100, 100 );
+
+ RECT rcMark;
+ rcMark = rc;
+ rcMark.top = rc.bottom - 8;
+ rcMark.bottom = rc.bottom;
+ rcMark.left = left - 4;
+ rcMark.right = left + 4;
+
+ drawHelper.DrawTriangleMarker( rcMark, clr );
+
+ RECT rcText;
+ rcText = rc;
+ rcText.bottom = rc.bottom - 10;
+ rcText.top = rcText.bottom - 10;
+
+ int len = drawHelper.CalcTextWidth( "Arial", 9, FW_NORMAL, tag->GetName() );
+ rcText.left = left - len / 2;
+ rcText.right = rcText.left + len + 2;
+
+ drawHelper.DrawColoredText( "Arial", 9, FW_NORMAL, clr, rcText, tag->GetName() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : int
+//-----------------------------------------------------------------------------
+int RampTool::ComputeHPixelsNeeded( void )
+{
+ CChoreoEvent *event = GetSafeEvent();
+ if ( !event )
+ return 0;
+
+ int pixels = 0;
+ float maxtime = event->GetDuration();
+ pixels = (int)( ( maxtime ) * GetPixelsPerSecond() + 10 );
+
+ return pixels;
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void RampTool::RepositionHSlider( void )
+{
+ int pixelsneeded = ComputeHPixelsNeeded();
+
+ if ( pixelsneeded <= w2() - 10 )
+ {
+ m_pHorzScrollBar->setVisible( false );
+ }
+ else
+ {
+ m_pHorzScrollBar->setVisible( true );
+ }
+ m_pHorzScrollBar->setBounds( 0, h2() - m_nScrollbarHeight, w2() - m_nScrollbarHeight, m_nScrollbarHeight );
+
+ m_flLeftOffset = max( 0.f, m_flLeftOffset );
+ m_flLeftOffset = min( (float)pixelsneeded, m_flLeftOffset );
+
+ m_pHorzScrollBar->setRange( 0, pixelsneeded );
+ m_pHorzScrollBar->setValue( (int)m_flLeftOffset );
+ m_pHorzScrollBar->setPagesize( w2() - 10 );
+
+ m_nLastHPixelsNeeded = pixelsneeded;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : float
+//-----------------------------------------------------------------------------
+float RampTool::GetPixelsPerSecond( void )
+{
+ return m_flPixelsPerSecond * (float)g_pChoreoView->GetTimeZoom( GetToolName() ) / 100.0f;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : x -
+//-----------------------------------------------------------------------------
+void RampTool::MoveTimeSliderToPos( int x )
+{
+ m_flLeftOffset = (float)x;
+ m_pHorzScrollBar->setValue( (int)m_flLeftOffset );
+ InvalidateRect( (HWND)m_pHorzScrollBar->getHandle(), NULL, TRUE );
+ InvalidateLayout();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void RampTool::InvalidateLayout( void )
+{
+ if ( m_bSuppressLayout )
+ return;
+
+ if ( ComputeHPixelsNeeded() != m_nLastHPixelsNeeded )
+ {
+ RepositionHSlider();
+ }
+
+ m_bLayoutIsValid = false;
+ redraw();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : st -
+// ed -
+//-----------------------------------------------------------------------------
+void RampTool::GetStartAndEndTime( float& st, float& ed )
+{
+ st = m_flLeftOffset / GetPixelsPerSecond();
+ ed = st + (float)w2() / GetPixelsPerSecond();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : -
+// Output : float
+//-----------------------------------------------------------------------------
+float RampTool::GetEventEndTime()
+{
+ CChoreoEvent *ev = GetSafeEvent();
+ if ( !ev )
+ return 1.0f;
+
+ return ev->GetDuration();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : time -
+// *clipped -
+// Output : int
+//-----------------------------------------------------------------------------
+int RampTool::GetPixelForTimeValue( float time, bool *clipped /*=NULL*/ )
+{
+ if ( clipped )
+ {
+ *clipped = false;
+ }
+
+ float st, ed;
+ GetStartAndEndTime( st, ed );
+
+ float frac = ( time - st ) / ( ed - st );
+ if ( frac < 0.0 || frac > 1.0 )
+ {
+ if ( clipped )
+ {
+ *clipped = true;
+ }
+ }
+
+ int pixel = ( int )( frac * w2() );
+ return pixel;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : mx -
+// clip -
+// Output : float
+//-----------------------------------------------------------------------------
+float RampTool::GetTimeValueForMouse( int mx, bool clip /*=false*/)
+{
+ float st, ed;
+ GetStartAndEndTime( st, ed );
+
+ if ( clip )
+ {
+ if ( mx < 0 )
+ {
+ return st;
+ }
+ if ( mx > w2() )
+ {
+ return ed;
+ }
+ }
+
+ float frac = (float)( mx ) / (float)( w2() );
+ return st + frac * ( ed - st );
+}
+
+void RampTool::OnChangeScale( void )
+{
+ CChoreoScene *scene = g_pChoreoView->GetScene();
+ if ( !scene )
+ {
+ return;
+ }
+
+ // Zoom time in / out
+ CInputParams params;
+ memset( &params, 0, sizeof( params ) );
+
+ strcpy( params.m_szDialogTitle, "Change Zoom" );
+ strcpy( params.m_szPrompt, "New scale (e.g., 2.5x):" );
+
+ Q_snprintf( params.m_szInputText, sizeof( params.m_szInputText ), "%.2f", (float)g_pChoreoView->GetTimeZoom( GetToolName() ) / 100.0f );
+
+ if ( !InputProperties( &params ) )
+ return;
+
+ g_pChoreoView->SetTimeZoom( GetToolName(), clamp( (int)( 100.0f * atof( params.m_szInputText ) ), 1, MAX_TIME_ZOOM ), false );
+
+ m_nLastHPixelsNeeded = -1;
+ m_flLeftOffset= 0.0f;
+ InvalidateLayout();
+ Con_Printf( "Zoom factor %i %%\n", g_pChoreoView->GetTimeZoom( GetToolName() ) );
+}
+
+void RampTool::DrawEventEnd( CChoreoWidgetDrawHelper& drawHelper )
+{
+ CChoreoEvent *e = GetSafeEvent();
+ if ( !e )
+ return;
+
+ float duration = e->GetDuration();
+ if ( !duration )
+ return;
+
+ int leftx = GetPixelForTimeValue( duration );
+ if ( leftx >= w2() )
+ return;
+
+ RECT rcSample;
+ GetSampleTrayRect( rcSample );
+
+ drawHelper.DrawColoredLine(
+ COLOR_CHOREO_ENDTIME, PS_SOLID, 1,
+ leftx, rcSample.top, leftx, rcSample.bottom );
+}
+
+void RampTool::GetSampleTrayRect( RECT& rc )
+{
+ rc.left = 0;
+ rc.right = w2();
+ rc.top = GetCaptionHeight() + 65;
+
+ rc.bottom = h2() - m_nScrollbarHeight-2;
+}
+
+void RampTool::DrawSamplesSimple( CChoreoWidgetDrawHelper& drawHelper, CChoreoEvent *e, bool clearbackground, COLORREF sampleColor, RECT &rcSamples )
+{
+ if ( clearbackground )
+ {
+ drawHelper.DrawFilledRect( RGB( 230, 230, 215 ), rcSamples );
+ }
+
+ if ( !e )
+ return;
+
+ float starttime = e->GetStartTime();
+
+ COLORREF lineColor = sampleColor;
+
+ int width = rcSamples.right - rcSamples.left;
+ if ( width <= 0.0f )
+ return;
+
+ int height = rcSamples.bottom - rcSamples.top;
+ int bottom = rcSamples.bottom;
+
+ float timestepperpixel = e->GetDuration() / (float)width;
+
+ float prev_value = e->GetIntensity( starttime );
+ int prev_x = rcSamples.left;
+ float prev_t = 0.0f;
+
+ for ( float x = rcSamples.left; x < rcSamples.right; x+=3 )
+ {
+ float t = (float)( x - rcSamples.left ) * timestepperpixel;
+
+ float value = e->GetIntensity( starttime + t );
+
+ // Draw segment
+ drawHelper.DrawColoredLine( lineColor, PS_SOLID, 1,
+ prev_x, bottom - prev_value * height,
+ x, bottom - value * height );
+
+ prev_x = x;
+ prev_t = t;
+ prev_value = value;
+ }
+}
+
+void RampTool::DrawSamples( CChoreoWidgetDrawHelper& drawHelper, RECT &rcSamples )
+{
+ drawHelper.DrawFilledRect( RGB( 230, 230, 215 ), rcSamples );
+
+ CChoreoEvent *e = GetSafeEvent();
+ if ( !e )
+ return;
+
+ int rampCount = e->GetRampCount();
+ if ( !rampCount )
+ return;
+
+ float starttime;
+ float endtime;
+
+ GetStartAndEndTime( starttime, endtime );
+
+ COLORREF lineColor = RGB( 0, 0, 255 );
+ COLORREF dotColor = RGB( 0, 0, 255 );
+ COLORREF dotColorSelected = RGB( 240, 80, 20 );
+ COLORREF shadowColor = RGB( 150, 150, 250 );
+
+ int height = rcSamples.bottom - rcSamples.top;
+ int bottom = rcSamples.bottom;
+ int top = rcSamples.top;
+
+ float timestepperpixel = 1.0f / GetPixelsPerSecond();
+
+ float stoptime = min( endtime, e->GetDuration() );
+
+ float prev_t = starttime;
+ float prev_value = e->GetIntensity( prev_t );
+
+ if ( 0 )
+ {
+ COLORREF shadowColor = RGB( 150, 150, 250 );
+
+ // draw hermite version of time step
+ float i0, i1, i2;
+ float time10hz = starttime;
+
+ i0 = e->GetIntensity( time10hz + e->GetStartTime() );
+ i1 = i0;
+ time10hz = starttime + 0.1;
+ i2 = e->GetIntensity( time10hz + e->GetStartTime() );;
+
+ for ( float t = starttime-timestepperpixel; t <= stoptime; t += timestepperpixel )
+ {
+ while (t >= time10hz)
+ {
+ time10hz += 0.1;
+ i0 = i1;
+ i1 = i2;
+ i2 = e->GetIntensity( time10hz + e->GetStartTime() );
+
+ bool clipped;
+ int x = GetPixelForTimeValue( time10hz, &clipped );
+ int y = bottom - i2 * height;
+ int dotsize = 4;
+
+ drawHelper.DrawCircle(
+ shadowColor,
+ x, y,
+ dotsize,
+ false );
+ }
+
+ float value = Hermite_Spline( i0, i1, i2, (t - time10hz + 0.1) / 0.1 );
+
+ int prevx, x;
+
+ bool clipped1, clipped2;
+ x = GetPixelForTimeValue( t, &clipped1 );
+ prevx = GetPixelForTimeValue( prev_t, &clipped2 );
+
+ if ( !clipped1 && !clipped2 )
+ {
+ // Draw segment
+ drawHelper.DrawColoredLine( shadowColor, PS_SOLID, 1,
+ prevx, clamp( bottom - prev_value * height, top, bottom ),
+ x, clamp( bottom - value * height, top, bottom ) );
+ }
+
+ prev_t = t;
+ prev_value = value;
+ }
+ }
+
+
+
+ for ( float t = starttime-timestepperpixel; t <= stoptime; t += timestepperpixel )
+ {
+ float value = e->GetIntensity( t + e->GetStartTime() );
+
+ int prevx, x;
+
+ bool clipped1, clipped2;
+ x = GetPixelForTimeValue( t, &clipped1 );
+ prevx = GetPixelForTimeValue( prev_t, &clipped2 );
+
+ if ( !clipped1 && !clipped2 )
+ {
+ // Draw segment
+ drawHelper.DrawColoredLine( lineColor, PS_SOLID, 1,
+ prevx, bottom - prev_value * height,
+ x, bottom - value * height );
+ }
+
+ prev_t = t;
+ prev_value = value;
+
+ }
+
+ for ( int sample = 0; sample < rampCount; sample++ )
+ {
+ CExpressionSample *start = e->GetRamp( sample );
+
+ /*
+ int pixel = (int)( ( start->time / event_time ) * width + 0.5f);
+ int x = m_rcBounds.left + pixel;
+ float roundedfrac = (float)pixel / (float)width;
+ */
+ float value = start->value;
+ bool clipped = false;
+ int x = GetPixelForTimeValue( start->time, &clipped );
+ if ( clipped )
+ continue;
+ int y = bottom - value * height;
+
+ int dotsize = 6;
+ int dotSizeSelected = 6;
+
+ COLORREF clr = dotColor;
+ COLORREF clrSelected = dotColorSelected;
+
+ drawHelper.DrawCircle(
+ start->selected ? clrSelected : clr,
+ x, y,
+ start->selected ? dotSizeSelected : dotsize,
+ true );
+
+ if ( !start->selected )
+ continue;
+
+ if ( start->GetCurveType() == CURVE_DEFAULT )
+ continue;
+
+ // Draw curve type indicator...
+ char sz[ 128 ];
+ Q_snprintf( sz, sizeof( sz ), "%s", Interpolator_NameForCurveType( start->GetCurveType(), true ) );
+ RECT rc;
+ int fontSize = 9;
+ rc.top = clamp( y + 5, rcSamples.top + 2, rcSamples.bottom - 2 - fontSize );
+ rc.bottom = rc.top + fontSize + 1;
+ rc.left = x - 75;
+ rc.right = x + 175;
+ drawHelper.DrawColoredText( "Arial", fontSize, 500, shadowColor, rc, sz );
+ }
+}
+
+void RampTool::DrawAutoHighlight( mxEvent *event )
+{
+ CChoreoEvent *e = GetSafeEvent();
+ if ( !e )
+ return;
+
+ CExpressionSample *hover = GetSampleUnderMouse( event->x, event->y, 0.0f );
+ RECT rcSamples;
+ GetSampleTrayRect( rcSamples );
+
+ CChoreoWidgetDrawHelper drawHelper( this, rcSamples, true );
+
+ RECT rcClient = rcSamples;
+
+ COLORREF dotColor = RGB( 0, 0, 255 );
+ COLORREF dotColorSelected = RGB( 240, 80, 20 );
+ COLORREF clrHighlighted = RGB( 0, 200, 0 );
+
+ int height = rcClient.bottom - rcClient.top;
+ int bottom = rcClient.bottom;
+
+ int dotsize = 6;
+ int dotSizeSelected = 6;
+ int dotSizeHighlighted = 6;
+
+ COLORREF clr = dotColor;
+ COLORREF clrSelected = dotColorSelected;
+ COLORREF bgColor = RGB( 230, 230, 200 );
+
+ // Fixme, could look at 1st derivative and do more sampling at high rate of change?
+ // or near actual sample points!
+ int sampleCount = e->GetRampCount();
+ for ( int sample = 0; sample < sampleCount; sample++ )
+ {
+ CExpressionSample *start = e->GetRamp( sample );
+
+ float value = start->value;
+ bool clipped = false;
+ int x = GetPixelForTimeValue( start->time, &clipped );
+ if ( clipped )
+ continue;
+ int y = bottom - value * height;
+
+ if ( hover == start )
+ {
+ drawHelper.DrawCircle(
+ bgColor,
+ x, y,
+ dotSizeHighlighted,
+ true );
+
+ drawHelper.DrawCircle(
+ clrHighlighted,
+ x, y,
+ dotSizeHighlighted,
+ false );
+
+
+ }
+ else
+ {
+ drawHelper.DrawCircle(
+ start->selected ? clrSelected : clr,
+ x, y,
+ start->selected ? dotSizeSelected : dotsize,
+ true );
+ }
+ }
+}
+
+int RampTool::NumSamples()
+{
+ CChoreoEvent *e = GetSafeEvent();
+ if ( !e )
+ return 0;
+
+ return e->GetRampCount();
+}
+
+CExpressionSample *RampTool::GetSample( int idx )
+{
+ CChoreoEvent *e = GetSafeEvent();
+ if ( !e )
+ return NULL;
+
+ return e->GetRamp( idx );
+}
+
+CExpressionSample *RampTool::GetSampleUnderMouse( int mx, int my, float tolerance /*= FP_RT_SELECTION_TOLERANCE*/ )
+{
+ CChoreoEvent *e = GetSafeEvent();
+ if ( !e )
+ return NULL;
+
+ RECT rcSamples;
+ GetSampleTrayRect( rcSamples );
+
+ POINT pt;
+ pt.x = mx;
+ pt.y = my;
+
+ if ( !PtInRect( &rcSamples, pt ) )
+ return NULL;
+
+ pt.y -= rcSamples.top;
+
+ float closest_dist = 9999999.f;
+ CExpressionSample *bestsample = NULL;
+
+ int height = rcSamples.bottom - rcSamples.top;
+
+ for ( int i = 0; i < e->GetRampCount(); i++ )
+ {
+ CExpressionSample *sample = e->GetRamp( i );
+ Assert( sample );
+
+ bool clipped = false;
+ int px = GetPixelForTimeValue( sample->time, &clipped );
+ int py = height * ( 1.0f - sample->value );
+
+ int dx = px - pt.x;
+ int dy = py - pt.y;
+
+ float dist = sqrt( (float)(dx * dx + dy * dy) );
+
+ if ( dist < closest_dist )
+ {
+ bestsample = sample;
+ closest_dist = dist;
+ }
+
+ }
+
+ // Not close to any of them!!!
+ if ( ( tolerance != 0.0f ) &&
+ ( closest_dist > tolerance ) )
+ return NULL;
+
+ return bestsample;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void RampTool::SelectPoints( void )
+{
+ RECT rcSelection;
+
+ rcSelection.left = m_nStartX < m_nLastX ? m_nStartX : m_nLastX;
+ rcSelection.right = m_nStartX < m_nLastX ? m_nLastX : m_nStartX;
+
+ rcSelection.top = m_nStartY < m_nLastY ? m_nStartY : m_nLastY;
+ rcSelection.bottom = m_nStartY < m_nLastY ? m_nLastY : m_nStartY;
+
+ int selW = rcSelection.right - rcSelection.left;
+ int selH = rcSelection.bottom - rcSelection.top;
+
+ float tolerance = FP_RT_SELECTION_RECTANGLE_TOLERANCE;
+ // If they are just clicking and releasing in one spot, capture any items w/in a larger tolerance
+ if ( selW <= 2 && selH <= 2 )
+ {
+ tolerance = FP_RT_SELECTION_TOLERANCE;
+
+ CExpressionSample *sample = GetSampleUnderMouse( rcSelection.left + selW * 0.5f, rcSelection.top + selH * 0.5f );
+ if ( sample )
+ {
+ sample->selected = true;
+ return;
+ }
+ }
+ else
+ {
+ InflateRect( &rcSelection, 3, 3 );
+ }
+
+ RECT rcSamples;
+ GetSampleTrayRect( rcSamples );
+
+ int height = rcSamples.bottom - rcSamples.top;
+
+ CChoreoEvent *e = GetSafeEvent();
+ if ( !e )
+ return;
+
+ float duration = e->GetDuration();
+
+ float fleft = (float)GetTimeValueForMouse( rcSelection.left );
+ float fright = (float)GetTimeValueForMouse( rcSelection.right );
+
+ //fleft *= duration;
+ //fright *= duration;
+
+ float ftop = (float)( rcSelection.top - rcSamples.top ) / (float)height;
+ float fbottom = (float)( rcSelection.bottom - rcSamples.top ) / (float)height;
+
+ fleft = clamp( fleft, 0.0f, duration );
+ fright = clamp( fright, 0.0f, duration );
+ ftop = clamp( ftop, 0.0f, 1.0f );
+ fbottom = clamp( fbottom, 0.0f, 1.0f );
+
+ float timestepperpixel = 1.0f / GetPixelsPerSecond();
+ float yfracstepperpixel = 1.0f / (float)height;
+
+ float epsx = tolerance*timestepperpixel;
+ float epsy = tolerance*yfracstepperpixel;
+
+ for ( int i = 0; i < e->GetRampCount(); i++ )
+ {
+ CExpressionSample *sample = e->GetRamp( i );
+
+ if ( sample->time + epsx < fleft )
+ continue;
+
+ if ( sample->time - epsx > fright )
+ continue;
+
+ if ( (1.0f - sample->value ) + epsy < ftop )
+ continue;
+
+ if ( (1.0f - sample->value ) - epsy > fbottom )
+ continue;
+
+ sample->selected = true;
+ }
+
+ redraw();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : int
+//-----------------------------------------------------------------------------
+int RampTool::CountSelected( void )
+{
+ return m_pHelper->CountSelected( false );
+}
+
+void RampTool::MoveSelectedSamples( float dfdx, float dfdy )
+{
+ int selecteditems = CountSelected();
+ if ( !selecteditems )
+ return;
+
+ CChoreoEvent *e = GetSafeEvent();
+ if ( !e )
+ return;
+
+ int c = e->GetRampCount();
+
+ float duration = e->GetDuration();
+ //dfdx *= duration;
+
+ for ( int i = 0; i < c; i++ )
+ {
+ CExpressionSample *sample = e->GetRamp( i );
+ if ( !sample || !sample->selected )
+ continue;
+
+ sample->time += dfdx;
+ sample->time = clamp( sample->time, 0.0f, duration );
+
+ sample->value -= dfdy;
+ sample->value = clamp( sample->value, 0.0f, 1.0f );
+ }
+
+ e->ResortRamp();
+ redraw();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void RampTool::DeselectAll( void )
+{
+ int i;
+
+ int selecteditems = CountSelected();
+ if ( !selecteditems )
+ return;
+
+ CChoreoEvent *e = GetSafeEvent();
+ Assert( e );
+ if ( !e )
+ return;
+
+ for ( i = e->GetRampCount() - 1; i >= 0 ; i-- )
+ {
+ CExpressionSample *sample = e->GetRamp( i );
+ sample->selected = false;
+ }
+
+ redraw();
+}
+
+void RampTool::SelectAll( void )
+{
+ int i;
+
+ CChoreoEvent *e = GetSafeEvent();
+ Assert( e );
+ if ( !e )
+ return;
+
+ for ( i = e->GetRampCount() - 1; i >= 0 ; i-- )
+ {
+ CExpressionSample *sample = e->GetRamp( i );
+ sample->selected = true;
+ }
+
+ redraw();
+}
+
+void RampTool::Delete( void )
+{
+ int i;
+
+ CChoreoEvent *e = GetSafeEvent();
+ if ( !e )
+ return;
+
+ int selecteditems = CountSelected();
+ if ( !selecteditems )
+ return;
+
+ PreDataChanged( "Delete ramp points" );
+
+ for ( i = e->GetRampCount() - 1; i >= 0 ; i-- )
+ {
+ CExpressionSample *sample = e->GetRamp( i );
+ if ( !sample->selected )
+ continue;
+
+ e->DeleteRamp( i );
+ }
+
+ PostDataChanged( "Delete ramp points" );
+}
+
+void RampTool::OnModelChanged()
+{
+ redraw();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *undodescription -
+//-----------------------------------------------------------------------------
+void RampTool::PreDataChanged( char const *undodescription )
+{
+ if ( m_nUndoSetup == 0 )
+ {
+ g_pChoreoView->SetDirty( true );
+ g_pChoreoView->PushUndo( undodescription );
+ }
+ ++m_nUndoSetup;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *redodescription -
+//-----------------------------------------------------------------------------
+void RampTool::PostDataChanged( char const *redodescription )
+{
+ --m_nUndoSetup;
+ if ( m_nUndoSetup == 0 )
+ {
+ g_pChoreoView->PushRedo( redodescription );
+ redraw();
+ }
+}
+
+
+void RampTool::SetMousePositionForEvent( mxEvent *event )
+{
+ POINT pt;
+ GetCursorPos( &pt );
+ ScreenToClient( (HWND)getHandle(), &pt );
+
+ event->x = pt.x;
+ event->y = pt.y;
+}
+
+void RampTool::OnEdgeProperties()
+{
+ CChoreoEvent *e = GetSafeEvent();
+ if ( !e )
+ return;
+
+ CEdgePropertiesParams params;
+ Q_memset( &params, 0, sizeof( params ) );
+ Q_strcpy( params.m_szDialogTitle, "Edge Properties" );
+
+ params.SetFromCurve( e->GetRamp() );
+
+ if ( !EdgeProperties( &params ) )
+ {
+ return;
+ }
+
+ char *undotext = "Change Event Ramp Edge Properties";
+
+ PreDataChanged( undotext );
+
+ // Apply changes.
+ params.ApplyToCurve( e->GetRamp() );
+
+ PostDataChanged( undotext );
+}
+
+void RampTool::GetWorkList( bool reflect, CUtlVector< RampTool * >& list )
+{
+ NOTE_UNUSED( reflect );
+ list.AddToTail( this );
+}