#include "externals.hh" #include "common.hh" #include "c-syncedit.hh" /*= T_UndoSyncChanges ========================================================*/ void T_UndoSyncChanges::undo( ) const noexcept { auto& sync{ Common::Sync( ) }; const auto n{ changes_.size( ) }; for ( auto i = 0u ; i < n ; i ++ ) { auto const& c( changes_[ i ] ); if ( c.before ) { sync.setCurve( *c.before ); } else { sync.removeCurve( c.inputId ); } } } void T_UndoSyncChanges::redo( ) const noexcept { auto& sync{ Common::Sync( ) }; const auto n{ changes_.size( ) }; for ( auto i = 0u ; i < n ; i ++ ) { auto const& c( changes_[ i ] ); if ( c.after ) { sync.setCurve( *c.after ); } else { sync.removeCurve( c.inputId ); } } } /*----------------------------------------------------------------------------*/ T_UndoSyncChanges& T_UndoSyncChanges::curveCreation( T_SyncCurve curve ) noexcept { #ifndef NDEBUG { const auto n{ changes_.size( ) }; for ( auto i = 0u ; i < n ; i ++ ) { assert( changes_[ i ].inputId != curve.name ); } } #endif changes_.addNew( true , std::move( curve ) ); return *this; } T_UndoSyncChanges& T_UndoSyncChanges::curveDeletion( T_SyncCurve curve ) noexcept { #ifndef NDEBUG { const auto n{ changes_.size( ) }; for ( auto i = 0u ; i < n ; i ++ ) { assert( changes_[ i ].inputId != curve.name ); } } #endif changes_.addNew( std::move( curve ) ); return *this; } T_UndoSyncChanges& T_UndoSyncChanges::curveReplacement( T_SyncCurve before , T_SyncCurve after ) noexcept { assert( before.name == after.name ); #ifndef NDEBUG { const auto n{ changes_.size( ) }; for ( auto i = 0u ; i < n ; i ++ ) { assert( changes_[ i ].inputId != before.name ); } } #endif changes_.addNew( std::move( before ) , std::move( after ) ); return *this; } /*= T_UndoDurationChanges ====================================================*/ T_UndoDurationChanges::T_UndoDurationChanges( const uint32_t units , const uint32_t oldUnits , const float unitSize , const float oldUnitSize ) noexcept : T_UndoSyncChanges( ) , unitsBefore_{ oldUnits } , unitsAfter_{ units } , uSizeBefore_{ oldUnitSize } , uSizeAfter_{ unitSize } { } void T_UndoDurationChanges::undo( ) const noexcept { Common::Sync( ).setDuration( uSizeBefore_ , unitsBefore_ ); T_UndoSyncChanges::undo( ); } void T_UndoDurationChanges::redo( ) const noexcept { Common::Sync( ).setDuration( uSizeAfter_ , unitsAfter_ ); T_UndoSyncChanges::redo( ); } /*= SyncEditor ===============================================================*/ namespace { T_SyncCurve SESDScaleCurve_( const float uSizeBefore , const float uSizeAfter , T_SyncCurve const& curve ) noexcept { T_SyncCurve nCurve; nCurve.name = curve.name; for ( auto const& segment : curve.segments ) { const auto nsid{ nCurve.segments.add( segment ) }; T_SyncSegment& nSeg{ nCurve.segments[ nsid ] }; const auto nd{ nSeg.durations.size( ) }; for ( auto i = 0u ; i < nd ; i ++ ) { const float duration{ nSeg.durations[ i ] * uSizeBefore }; nSeg.durations[ i ] = std::max( 1u , uint32_t( std::roundf( duration / uSizeAfter ) ) ); #if 0 printf( "initial duration %f (%d units) ; new duration %f (%d units)\n" , duration , segment.durations[ i ] , uSizeAfter * nSeg.durations[ i ] , nSeg.durations[ i ] ); #endif } } return nCurve; } } // namespace void SyncEditor::SetDuration( const uint32_t units , const float uSize , const bool scaleCurves ) noexcept { auto& sync{ Common::Sync( ) }; const float oldUnitSize{ sync.durationUnitSize( ) }; const uint32_t oldUnits{ sync.durationUnits( ) }; if ( oldUnits == units && oldUnitSize == uSize ) { return; } auto& undo{ dynamic_cast< T_UndoDurationChanges& >( Common::Undo( ).add< T_UndoDurationChanges >( units , oldUnits , uSize , oldUnitSize ) ) }; sync.setDuration( uSize , units ); if ( !scaleCurves || uSize == oldUnitSize ) { return; } auto const& curves( sync.curves( ) ); for ( auto const& curve : curves ) { auto nc{ SESDScaleCurve_( oldUnitSize , uSize , curve ) }; undo.curveReplacement( curve , nc ); sync.setCurve( std::move( nc ) ); } } /*----------------------------------------------------------------------------*/ void SyncEditor::ReplaceCurve( T_SyncCurve replacement ) noexcept { auto* const curve{ Common::Sync( ).getCurve( replacement.name ) }; if ( !curve ) { return; } // Create undo entry auto& undo{ dynamic_cast< T_UndoSyncChanges& >( Common::Undo( ).add< T_UndoSyncChanges >( ) ) }; undo.curveReplacement( *curve , replacement ); Common::Sync( ).setCurve( std::move( replacement ) ); } /*----------------------------------------------------------------------------*/ void SyncEditor::DeleteCurve( T_String const& id ) noexcept { auto const* const curve{ Common::Sync( ).getCurve( id ) }; if ( !curve ) { return; } // Create undo entry auto& undo{ dynamic_cast< T_UndoSyncChanges& >( Common::Undo( ).add< T_UndoSyncChanges >( ) ) }; undo.curveDeletion( *curve ); // Delete curve Common::Sync( ).removeCurve( id ); } /*----------------------------------------------------------------------------*/ void SyncEditor::AppendSegment( T_String const& id , uint32_t nsDuration ) noexcept { assert( nsDuration > 0 ); auto& sync{ Common::Sync( ) }; auto const* const curve{ sync.getCurve( id ) }; auto& undo{ dynamic_cast< T_UndoSyncChanges& >( Common::Undo( ).add< T_UndoSyncChanges >( ) ) }; if ( curve && !curve->segments.empty( ) ) { const float lastValue{ [&](){ auto const& lSeg{ curve->segments.last( ) }; return lSeg.values.last( ); }( ) }; auto nCurve{ *curve }; auto& nSeg{ nCurve.segments.addNew( ) }; nSeg.type = T_SyncSegment::LINEAR; nSeg.values.add( lastValue ); nSeg.values.add( lastValue ); nSeg.durations.add( nsDuration ); undo.curveReplacement( *curve , nCurve ); sync.setCurve( std::move( nCurve ) ); } else { T_SyncCurve nCurve; nCurve.name = id; const auto value{ sync.inputs( )[ sync.inputPos( id ) ] }; auto& nSeg{ nCurve.segments.addNew( ) }; nSeg.type = T_SyncSegment::LINEAR; nSeg.values.add( value ); nSeg.values.add( value ); nSeg.durations.add( nsDuration ); undo.curveCreation( nCurve ); sync.setCurve( std::move( nCurve ) ); } } /*----------------------------------------------------------------------------*/ void SyncEditor::DeleteSegment( T_String const& id , const uint32_t segmentIndex ) noexcept { auto& sync{ Common::Sync( ) }; auto const* const curve{ sync.getCurve( id ) }; if ( !curve || segmentIndex >= curve->segments.size( ) ) { return; } auto& undo{ dynamic_cast< T_UndoSyncChanges& >( Common::Undo( ).add< T_UndoSyncChanges >( ) ) }; if ( curve->segments.size( ) == 1 ) { undo.curveDeletion( *curve ); sync.removeCurve( id ); } else { auto nCurve{ *curve }; nCurve.segments.remove( segmentIndex ); undo.curveReplacement( *curve , nCurve ); sync.setCurve( std::move( nCurve ) ); } } /*----------------------------------------------------------------------------*/ void SyncEditor::SetSegmentType( T_SyncCurve const& initial , const uint32_t segmentIndex , const T_SyncSegment::E_SegmentType newType ) noexcept { assert( segmentIndex < initial.segments.size( ) ); T_SyncSegment const& iSegment{ initial.segments[ segmentIndex ] }; if ( iSegment.type == newType ) { return; } // Create new curve T_SyncCurve copy{ initial }; copy.segments[ segmentIndex ].type = newType; // Create undo entry auto& undo{ dynamic_cast< T_UndoSyncChanges& >( Common::Undo( ).add< T_UndoSyncChanges >( ) ) }; undo.curveReplacement( initial , copy ); // Replace curve Common::Sync( ).setCurve( std::move( copy ) ); } /*----------------------------------------------------------------------------*/ void SyncEditor::InsertPoint( T_String const& id , const uint32_t segmentIndex , const uint32_t pointIndex ) noexcept { auto& sync{ Common::Sync( ) }; auto const* const curve{ sync.getCurve( id ) }; if ( !curve || segmentIndex >= curve->segments.size( ) ) { return; } auto const& segment{ curve->segments[ segmentIndex ] }; if ( pointIndex == 0 || pointIndex > segment.values.size( ) || segment.durations[ pointIndex - 1 ] == 1 ) { return; } auto c{ *curve }; auto& ns{ c.segments[ segmentIndex ] }; const auto hd{ ns.durations[ pointIndex - 1 ] / 2 }; // FIXME: this should use the actual value const float hv{ ( ns.values[ pointIndex ] + ns.values[ pointIndex - 1 ] ) * .5f }; ns.durations[ pointIndex - 1 ] -= hd; ns.durations.insert( pointIndex - 1 , hd ); ns.values.insert( pointIndex , hv ); auto& undo{ dynamic_cast< T_UndoSyncChanges& >( Common::Undo( ).add< T_UndoSyncChanges >( ) ) }; undo.curveReplacement( *curve , c ); sync.setCurve( std::move( c ) ); } /*----------------------------------------------------------------------------*/ void SyncEditor::DeletePoint( T_String const& id , const uint32_t segmentIndex , const uint32_t pointIndex ) noexcept { auto& sync{ Common::Sync( ) }; auto const* const curve{ sync.getCurve( id ) }; if ( !curve || segmentIndex >= curve->segments.size( ) ) { return; } auto const& segment{ curve->segments[ segmentIndex ] }; if ( pointIndex == 0 || pointIndex >= segment.values.size( ) ) { return; } auto c{ *curve }; auto& ns{ c.segments[ segmentIndex ] }; ns.durations[ pointIndex ] += ns.durations[ pointIndex - 1 ]; ns.durations.remove( pointIndex - 1 ); ns.values.remove( pointIndex ); auto& undo{ dynamic_cast< T_UndoSyncChanges& >( Common::Undo( ).add< T_UndoSyncChanges >( ) ) }; undo.curveReplacement( *curve , c ); sync.setCurve( std::move( c ) ); }