diff --git a/TODO b/TODO index dd3a582..9b426b4 100644 --- a/TODO +++ b/TODO @@ -33,6 +33,7 @@ Sync / inputs: * Moving tracks * Moving segments * Add curve display +* CLEAN UP THAT FUCKING SPAGHETTI MESS! Misc: * General overhaul (e.g. use tabs) diff --git a/ui-sequencer.cc b/ui-sequencer.cc index d0a6973..d2e4bea 100644 --- a/ui-sequencer.cc +++ b/ui-sequencer.cc @@ -367,7 +367,8 @@ struct T_SyncViewImpl_ const float time ) noexcept; bool handlePointDrag( const float mPixels , - bool mouseDown ) noexcept; + bool mouseDown , + bool shiftPressed ) noexcept; T_MousePos getMousePos( ) const noexcept; @@ -858,7 +859,8 @@ void T_SyncViewImpl_::sequencerWidget( ) noexcept zoomLevel = ( ppu - BarWidth ) / ( BarWidth - width / u ) + 1; } } - } else if ( dnd == E_DNDType::POINT && handlePointDrag( mPixels , io.MouseDown[ 0 ] ) ) { + } else if ( dnd == E_DNDType::POINT + && handlePointDrag( mPixels , io.MouseDown[ 0 ] , io.KeyShift ) ) { return; } else if ( dnd == E_DNDType::CLICK && ( io.MouseDown[ 0 ] || io.MouseDown[ 1 ] ) ) { return; @@ -911,7 +913,8 @@ void T_SyncViewImpl_::sequencerWidget( ) noexcept selId = dTrack.id; selSegment = dSeg.seg; selPoint = dPoint.index; - const bool pdnd{ io.MouseDown[ 0 ] && dPoint.index != 0 }; + const bool pdnd{ io.MouseDown[ 0 ] + && ( dPoint.index != 0 || dSeg.seg != 0 ) }; if ( pdnd ) { assert( selUpdate == E_ChangeType::NONE ); selPointDnDStart = selPointDnDCur = mPixels; @@ -1400,7 +1403,8 @@ void T_SyncViewImpl_::displayTooltips( bool T_SyncViewImpl_::handlePointDrag( const float mPixels , - bool mouseDown ) noexcept + bool mouseDown , + bool shiftPressed ) noexcept { auto& sync( Common::Sync( ) ); @@ -1409,32 +1413,51 @@ bool T_SyncViewImpl_::handlePointDrag( const int32_t diffUnits{ int32_t( round( diff * sync.durationUnits( ) / totalPixels ) ) }; const bool moved{ fabsf( diff ) >= 2 && abs( diffUnits ) > 0 }; const auto ni{ selUpdatingCopies.size( ) }; + const auto sid{ *selSegment }; + const auto pid{ *selPoint }; + assert( pid > 0 || sid > 0 ); + const bool isLastPoint{ [&](){ + auto const& s{ selUpdatingOriginals[ 0 ].segments }; + return sid == s.size( ) - 1 && pid == s[ sid ].durations.size( ); + }( ) }; - // Update the point as necessary - if ( moved ) { + if ( moved && ( shiftPressed || isLastPoint ) ) { + // Increase/decrease duration selUpdatingCopies = selUpdatingOriginals; for ( auto i = 0u ; i < ni ; i ++ ) { auto& copy{ selUpdatingCopies[ i ] }; - auto& seg{ copy.segments[ *selSegment ] }; - if ( *selPoint == seg.durations.size( ) ) { - // We're dragging the end point - // XXX make it work "normally" - seg.durations.last( ) = std::max( 1 , - diffUnits + int32_t( seg.durations.last( ) ) ); - } else { - // We're dragging some other point, move units - // from one side to the other - assert( *selPoint > 0 ); - auto& d0{ seg.durations[ *selPoint - 1 ] }; - auto& d1{ seg.durations[ *selPoint ] }; - const int32_t mmNeg( 1 - d0 ) , mmPos( d1 - 1 ); - const int32_t diff{ diffUnits < mmNeg ? mmNeg - : ( diffUnits > mmPos ? mmPos : diffUnits ) }; - d0 += diff; - d1 -= diff; - } + auto& seg{ copy.segments[ sid ] }; + auto& d{ pid == 0 + ? copy.segments[ sid - 1 ].durations.last( ) + : seg.durations[ pid - 1 ] }; + d = std::max( 1 , diffUnits + int32_t( d ) ); sync.setCurve( copy ); } + + } else if ( moved ) { + // Move the point but keep the sum of before/after durations + // a constant + selUpdatingCopies = selUpdatingOriginals; + for ( auto i = 0u ; i < ni ; i ++ ) { + auto& copy{ selUpdatingCopies[ i ] }; + auto& seg{ copy.segments[ sid ] }; + + auto& d0{ pid == 0 + ? copy.segments[ sid - 1 ].durations.last( ) + : seg.durations[ pid - 1 ] }; + auto& d1{ pid == seg.durations.size( ) + ? copy.segments[ sid + 1 ].durations[ 0 ] + : seg.durations[ pid ] + }; + + const int32_t mmNeg( 1 - d0 ) , mmPos( d1 - 1 ); + const int32_t diff{ diffUnits < mmNeg ? mmNeg + : ( diffUnits > mmPos ? mmPos : diffUnits ) }; + d0 += diff; + d1 -= diff; + sync.setCurve( copy ); + } + } else { selUpdatingCopies.clear( ); for ( auto i = 0u ; i < ni ; i ++ ) {