//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // //============================================================================= #ifndef CURVEEDITORHELPERS_H #define CURVEEDITORHELPERS_H #ifdef _WIN32 #pragma once #endif #include "mxtk/mx.h" struct CExpressionSample; template< class T > class CCurveEditorHelper { public: CCurveEditorHelper( T *outer ); int GetBestCurveTypeForSelectedSamples( bool reflect ); int CountSelected( bool reflect ); void ChangeCurveType( bool forward, bool shiftdown, bool altdown ); void SetCurveTypeForSelectedSamples( bool reflect, int curvetype ); void SetCurveTypeForSample( int curvetype, CExpressionSample *sample ); void ToggleHoldTypeForSelectedSamples( bool reflect ); void ToggleHoldTypeForSample( CExpressionSample *sample ); bool HelperHandleEvent( mxEvent *event ); private: T *GetOuter(); private: T *m_pOuter; }; template< class T > CCurveEditorHelper::CCurveEditorHelper( T *pOuter ) : m_pOuter( pOuter ) { Assert( pOuter ); } template< class T > T *CCurveEditorHelper::GetOuter() { return m_pOuter; } template< class T > int CCurveEditorHelper::GetBestCurveTypeForSelectedSamples( bool reflect ) { int numSelected = CountSelected( reflect ); if ( !numSelected ) return CURVE_DEFAULT; CUtlMap< int, int > counts( 0, 0, DefLessFunc( int ) ); CUtlVector< T * > workList; GetOuter()->GetWorkList( reflect, workList ); for ( int w = 0; w < workList.Count(); ++w ) { int numSamples = workList[ w ]->NumSamples(); if ( !numSamples ) continue; for ( int i = numSamples - 1; i >= 0 ; i-- ) { CExpressionSample *sample = workList[ w ]->GetSample( i ); if ( !sample->selected ) continue; int curveType = sample->GetCurveType(); int idx = counts.Find( curveType ); if ( idx == counts.InvalidIndex() ) { idx = counts.Insert( curveType, 0 ); } counts[ idx ]++; } } int maxType = CURVE_DEFAULT; int maxCount = -1; for ( int i = counts.FirstInorder(); i != counts.InvalidIndex(); i = counts.NextInorder( i ) ) { if ( counts[ i ] > maxType ) { maxCount = counts[ i ]; maxType = counts.Key( i ); } } return maxType; } template< class T > int CCurveEditorHelper::CountSelected( bool reflect ) { int numSelected = 0; CUtlVector< T * > workList; GetOuter()->GetWorkList( reflect, workList ); for ( int w = 0; w < workList.Count(); ++w ) { int numSamples = workList[ w ]->NumSamples(); if ( !numSamples ) continue; for ( int i = 0 ; i < numSamples; ++i ) { CExpressionSample *sample = workList[ w ]->GetSample( i ); if ( !sample || !sample->selected ) continue; ++numSelected; } } return numSelected; } template< class T > void CCurveEditorHelper::ChangeCurveType( bool forward, bool shiftdown, bool altdown ) { // If holding ctrl and shift, only do inbound bool inbound = shiftdown; // if holding ctrl, shift + alt, do both inbound and outbound bool outbound = !shiftdown || altdown; // if holding ctrl + alt, do outbound // if holding just ctrl, do outbound int numSelected = CountSelected( false ); if ( !numSelected ) return; int curveType = GetBestCurveTypeForSelectedSamples( false ); int sides[ 2 ]; Interpolator_CurveInterpolatorsForType( curveType, sides[ 0 ], sides[ 1 ] ); int dir = forward ? 1 : -1; for ( int i = 0; i < 2; ++i ) { if ( i == 0 && !inbound ) continue; if ( i == 1 && !outbound ) continue; sides[ i ] += dir; if ( sides[ i ] < 0 ) { sides[ i ] = NUM_INTERPOLATE_TYPES - 1; } else if ( sides[ i ] >= NUM_INTERPOLATE_TYPES ) { sides[ i ] = INTERPOLATE_DEFAULT; } } curveType = MAKE_CURVE_TYPE( sides[ 0 ], sides[ 1 ] ); SetCurveTypeForSelectedSamples( false, curveType ); } template< class T > void CCurveEditorHelper::SetCurveTypeForSelectedSamples( bool reflect, int curvetype ) { int numSelected = CountSelected( reflect ); if ( !numSelected ) return; GetOuter()->PreDataChanged( "Set curve type" ); CUtlVector< T * > workList; GetOuter()->GetWorkList( reflect, workList ); for ( int w = 0; w < workList.Count(); ++w ) { int numSamples = workList[ w ]->NumSamples(); for ( int i = 0 ; i < numSamples; ++i ) { CExpressionSample *sample = workList[ w ]->GetSample( i ); if ( !sample->selected ) continue; sample->SetCurveType( curvetype ); } } GetOuter()->PostDataChanged( "Set curve type" ); } template< class T > void CCurveEditorHelper::SetCurveTypeForSample( int curvetype, CExpressionSample *sample ) { GetOuter()->PreDataChanged( "Set curve type" ); sample->SetCurveType( curvetype ); GetOuter()->PostDataChanged( "Set curve type" ); } template< class T > void CCurveEditorHelper::ToggleHoldTypeForSelectedSamples( bool reflect ) { int numSelected = CountSelected( reflect ); if ( !numSelected ) return; GetOuter()->PreDataChanged( "Set hold out value" ); CUtlVector< T * > workList; GetOuter()->GetWorkList( reflect, workList ); for ( int w = 0; w < workList.Count(); ++w ) { int numSamples = workList[ w ]->NumSamples(); int newValue = -1; for ( int i = 0 ; i < numSamples; ++i ) { CExpressionSample *sample = workList[ w ]->GetSample( i ); if ( !sample->selected ) continue; // First one controls setting int l, r; Interpolator_CurveInterpolatorsForType( sample->GetCurveType(), l, r ); if ( newValue == -1 ) { newValue = ( r == INTERPOLATE_HOLD ) ? 0 : 1; } int newCurveType = MAKE_CURVE_TYPE( l, newValue == 1 ? INTERPOLATE_HOLD : l ); sample->SetCurveType( newCurveType ); } } GetOuter()->PostDataChanged( "Set hold out value" ); } template< class T > void CCurveEditorHelper::ToggleHoldTypeForSample( CExpressionSample *sample ) { GetOuter()->PreDataChanged( "Set hold out value" ); int l, r; Interpolator_CurveInterpolatorsForType( sample->GetCurveType(), l, r ); if ( r == INTERPOLATE_HOLD ) { r = l; } else { r = INTERPOLATE_HOLD; } int newCurveType = MAKE_CURVE_TYPE( l, r ); sample->SetCurveType( newCurveType ); GetOuter()->PostDataChanged( "Set hold out value" ); } template< class T > bool CCurveEditorHelper::HelperHandleEvent( mxEvent *event ) { bool handled = false; switch ( event->event ) { case mxEvent::KeyDown: { switch ( event->key ) { default: // Hotkey pressed if ( event->key >= '0' && event->key <= '9' ) { bool shiftdown = GetAsyncKeyState( VK_SHIFT ) ? true : false; handled = true; // Get curve type int curveType = Interpolator_CurveTypeForHotkey( event->key ); if ( curveType >= 0 ) { if ( CountSelected( shiftdown ) <= 0 ) { GetOuter()->SetMousePositionForEvent( event ); CExpressionSample *hover = GetOuter()->GetSampleUnderMouse( event->x, event->y, 0.0f ); // Deal with highlighted item if ( hover ) { SetCurveTypeForSample( curveType, hover ); } } else { SetCurveTypeForSelectedSamples( shiftdown, curveType ); } } } break; case 'H': { handled = true; bool shiftdown = GetAsyncKeyState( VK_SHIFT ) ? true : false; if ( CountSelected( shiftdown ) <= 0 ) { GetOuter()->SetMousePositionForEvent( event ); CExpressionSample *hover = GetOuter()->GetSampleUnderMouse( event->x, event->y, 0.0f ); // Deal with highlighted item if ( hover ) { ToggleHoldTypeForSample( hover ); } } else { ToggleHoldTypeForSelectedSamples( shiftdown ); } } break; case VK_UP: { bool shiftdown = GetAsyncKeyState( VK_SHIFT ) ? true : false; bool altdown = GetAsyncKeyState( VK_MENU ) ? true : false; if ( GetAsyncKeyState( VK_CONTROL ) ) { ChangeCurveType( false, shiftdown, altdown ); } } break; case VK_DOWN: { bool shiftdown = GetAsyncKeyState( VK_SHIFT ) ? true : false; bool altdown = GetAsyncKeyState( VK_MENU ) ? true : false; if ( GetAsyncKeyState( VK_CONTROL ) ) { ChangeCurveType( true, shiftdown, altdown ); } } break; } } } return handled; } #endif // CURVEEDITORHELPERS_H