Sequencer - Point edition, insertion and deletion
This commit is contained in:
parent
9731adc872
commit
aef7546a57
1 changed files with 193 additions and 16 deletions
209
ui-sequencer.cc
209
ui-sequencer.cc
|
@ -207,6 +207,14 @@ struct T_SyncViewImpl_
|
|||
SW_OVERRIDE_SELECTOR ,
|
||||
SW_TRACK ,
|
||||
SW_SEGMENT ,
|
||||
SW_POINT ,
|
||||
};
|
||||
|
||||
// Type of change in progress
|
||||
enum class E_ChangeType {
|
||||
NONE ,
|
||||
POINT_DND ,
|
||||
POINT_VALUE ,
|
||||
};
|
||||
|
||||
// Make sure all displayed curves/inputs/overrides still exist
|
||||
|
@ -248,6 +256,7 @@ struct T_SyncViewImpl_
|
|||
|
||||
void displayTrackWindow( ) noexcept;
|
||||
void displaySegmentWindow( ) noexcept;
|
||||
void displayPointWindow( ) noexcept;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
|
@ -296,8 +305,11 @@ struct T_SyncViewImpl_
|
|||
T_Optional< uint32_t > selPoint;
|
||||
bool selPointDnD{ false };
|
||||
float selPointDnDStart , selPointDnDCur;
|
||||
T_Optional< T_SyncCurve > selPointDnDOriginal;
|
||||
T_Optional< T_SyncCurve > selPointDnDCopy;
|
||||
|
||||
// Original and copy of curve being modified
|
||||
E_ChangeType selUpdate{ E_ChangeType::NONE };
|
||||
T_Optional< T_SyncCurve > selUpdatingOriginal;
|
||||
T_Optional< T_SyncCurve > selUpdatingCopy;
|
||||
|
||||
// Sub-windows
|
||||
E_SubWindow sub{ SW_NONE };
|
||||
|
@ -355,6 +367,10 @@ bool T_SyncViewImpl_::display( ) noexcept
|
|||
case SW_SEGMENT:
|
||||
displaySegmentWindow( );
|
||||
break;
|
||||
|
||||
case SW_POINT:
|
||||
displayPointWindow( );
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -597,11 +613,12 @@ void T_SyncViewImpl_::sequencerWidget( ) noexcept
|
|||
selPoint = dPoint.index;
|
||||
selPointDnD = io.MouseDown[ 0 ] && dPoint.index != 0;
|
||||
if ( selPointDnD ) {
|
||||
assert( selUpdate == E_ChangeType::NONE );
|
||||
selPointDnDStart = selPointDnDCur = mPixels;
|
||||
selPointDnDOriginal = *sync.getCurve( dTrack.id ); // XXX
|
||||
selUpdatingOriginal = *sync.getCurve( dTrack.id ); // XXX
|
||||
selUpdate = E_ChangeType::POINT_DND;
|
||||
}
|
||||
// sub = E_SubWindow::SW_SEGMENT;
|
||||
#warning fix that shit
|
||||
sub = E_SubWindow::SW_POINT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -833,13 +850,13 @@ void T_SyncViewImpl_::sequencerTrack(
|
|||
|
||||
// If there's a curve, go through all segments
|
||||
const auto units{ Common::Sync( ).durationUnits( ) };
|
||||
const bool useCopy{ sCurve && curve && selPointDnDCopy };
|
||||
const bool useCopy{ sCurve && curve && selUpdatingCopy };
|
||||
const auto nSeg{ curve
|
||||
? ( useCopy ? *selPointDnDCopy : *curve ).segments.size( )
|
||||
? ( useCopy ? *selUpdatingCopy : *curve ).segments.size( )
|
||||
: 0u };
|
||||
uint32_t segStart{ 0 };
|
||||
for ( auto i = 0u ; i < nSeg ; i ++ ) {
|
||||
auto const& seg{ ( useCopy ? *selPointDnDCopy : *curve ).segments[ i ] };
|
||||
auto const& seg{ ( useCopy ? *selUpdatingCopy : *curve ).segments[ i ] };
|
||||
const auto segDur{ [&](){
|
||||
auto t{ 0u };
|
||||
for ( auto d : seg.durations ) {
|
||||
|
@ -1005,8 +1022,8 @@ bool T_SyncViewImpl_::handlePointDrag(
|
|||
|
||||
// Update the point as necessary
|
||||
if ( moved ) {
|
||||
selPointDnDCopy = selPointDnDOriginal; // XXX
|
||||
auto& seg{ selPointDnDCopy->segments[ *selSegment ] };
|
||||
selUpdatingCopy = selUpdatingOriginal; // XXX
|
||||
auto& seg{ selUpdatingCopy->segments[ *selSegment ] };
|
||||
if ( *selPoint == seg.durations.size( ) ) {
|
||||
// We're dragging the end point
|
||||
// XXX make it work "normally"
|
||||
|
@ -1024,21 +1041,23 @@ bool T_SyncViewImpl_::handlePointDrag(
|
|||
d0 += diff;
|
||||
d1 -= diff;
|
||||
}
|
||||
sync.setCurve( *selPointDnDCopy );
|
||||
sync.setCurve( *selUpdatingCopy );
|
||||
} else {
|
||||
selPointDnDCopy.clear( );
|
||||
selUpdatingCopy.clear( );
|
||||
}
|
||||
|
||||
if ( mouseDown ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
assert( selUpdate == E_ChangeType::POINT_DND );
|
||||
selUpdate = E_ChangeType::NONE;
|
||||
selPointDnD = false;
|
||||
sync.setCurve( std::move( *selPointDnDOriginal ) );
|
||||
selPointDnDOriginal.clear( );
|
||||
sync.setCurve( std::move( *selUpdatingOriginal ) );
|
||||
selUpdatingOriginal.clear( );
|
||||
if ( moved ) {
|
||||
SyncEditor::ReplaceCurve( std::move( *selPointDnDCopy ) );
|
||||
selPointDnDCopy.clear( );
|
||||
SyncEditor::ReplaceCurve( std::move( *selUpdatingCopy ) );
|
||||
selUpdatingCopy.clear( );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -1466,6 +1485,164 @@ void T_SyncViewImpl_::displaySegmentWindow( ) noexcept
|
|||
End( );
|
||||
}
|
||||
|
||||
void T_SyncViewImpl_::displayPointWindow( ) noexcept
|
||||
{
|
||||
using namespace ImGui;
|
||||
auto const& dspSize( GetIO( ).DisplaySize );
|
||||
|
||||
// Window set-up
|
||||
SetNextWindowSize( ImVec2( dspSize.x * .25f , dspSize.y * .66f - 20 ) , ImGuiSetCond_Appearing );
|
||||
SetNextWindowPos( ImVec2( dspSize.x * .75f , 20 ) , ImGuiSetCond_Appearing );
|
||||
bool displayed{ true };
|
||||
Begin( "Selected point" , &displayed , ImGuiWindowFlags_NoCollapse );
|
||||
if ( !displayed ) {
|
||||
End( );
|
||||
sub = SW_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
// Access curve, segment and point
|
||||
const uint32_t sid{ *selSegment };
|
||||
const uint32_t pid{ *selPoint };
|
||||
auto& sync{ Common::Sync( ) };
|
||||
auto const* const curve{ selUpdatingCopy
|
||||
? selUpdatingCopy.target( )
|
||||
: sync.getCurve( selId ) };
|
||||
auto const& segment{ curve->segments[ sid ] };
|
||||
|
||||
Text( "Curve:" );
|
||||
SameLine( 110 );
|
||||
Text( "%s" , selId.toOSString( ).data( ) );
|
||||
|
||||
Text( "Segment index:" );
|
||||
SameLine( 110 );
|
||||
Text( "%d" , sid );
|
||||
|
||||
Text( "Point index:" );
|
||||
SameLine( 110 );
|
||||
Text( "%d / %d" , pid , segment.durations.size( ) );
|
||||
|
||||
Separator( );
|
||||
|
||||
// Find start and duration
|
||||
uint32_t segStart{ 0 } , pointPosRel{ 0 };
|
||||
for ( auto i = 0u ; i <= sid ; i ++ ) {
|
||||
auto const& s{ curve->segments[ i ] };
|
||||
auto& tgt{ i == sid ? pointPosRel : segStart };
|
||||
const auto end{ i == sid ? pid : s.durations.size( ) };
|
||||
for ( auto j = 0u ; j < end ; j ++ ) {
|
||||
tgt += s.durations[ j ];
|
||||
}
|
||||
}
|
||||
const uint32_t pointPosAbs{ segStart + pointPosRel };
|
||||
const float tPointPosAbs{ sync.durationUnitSize( ) * pointPosAbs } ,
|
||||
tPointPosRel{ sync.durationUnitSize( ) * pointPosRel };
|
||||
|
||||
Text( "Absolute:" );
|
||||
SameLine( 110 );
|
||||
Text( "%d units" , pointPosAbs );
|
||||
|
||||
Text( " " );
|
||||
SameLine( 110 );
|
||||
Text( "%.3f seconds" , tPointPosAbs );
|
||||
|
||||
Text( "Relative:" );
|
||||
SameLine( 110 );
|
||||
Text( "%d units" , pointPosRel );
|
||||
|
||||
Text( " " );
|
||||
SameLine( 110 );
|
||||
Text( "%.3f seconds" , tPointPosRel );
|
||||
|
||||
Separator( );
|
||||
|
||||
Text( "Value:" );
|
||||
SameLine( 110 );
|
||||
float value{ segment.values[ pid ] };
|
||||
PushItemWidth( -1 );
|
||||
DragFloat( "##value" , &value , .01f , 0 , 0 , "%.6f" );
|
||||
const bool changed{ IsItemActive( ) };
|
||||
PopItemWidth( );
|
||||
|
||||
const bool canUseButtons{ !changed && selUpdate == E_ChangeType::NONE };
|
||||
if ( pid != 0 && pid != segment.durations.size( ) ) {
|
||||
Separator( );
|
||||
Text( " " );
|
||||
SameLine( 110 );
|
||||
if ( Button( "Delete point" , ImVec2{ -1 , 0 } ) && canUseButtons ) {
|
||||
// FIXME move to syncedit
|
||||
auto c{ *curve };
|
||||
auto& ns{ c.segments[ sid ] };
|
||||
ns.durations[ pid ] += ns.durations[ pid - 1 ];
|
||||
ns.durations.remove( pid - 1 );
|
||||
ns.values.remove( pid );
|
||||
SyncEditor::ReplaceCurve( std::move( c ) );
|
||||
selPoint.clear( );
|
||||
sub = SW_SEGMENT;
|
||||
}
|
||||
}
|
||||
|
||||
const auto canInsertBefore{ pid != 0
|
||||
&& segment.durations[ pid - 1 ] > 1 };
|
||||
const auto canInsertAfter{ pid != segment.durations.size( )
|
||||
&& segment.durations[ pid ] > 1 };
|
||||
if ( canInsertAfter || canInsertBefore ) {
|
||||
Separator( );
|
||||
if ( canInsertBefore ) {
|
||||
Text( " " );
|
||||
SameLine( 110 );
|
||||
if ( Button( "Insert before" , ImVec2{ -1 , 0 } ) && canUseButtons ) {
|
||||
// FIXME move to syncedit
|
||||
auto c{ *curve };
|
||||
auto& ns{ c.segments[ sid ] };
|
||||
const auto hd{ ns.durations[ pid - 1 ] / 2 };
|
||||
// FIXME: this should use the actual value
|
||||
const float hv{ ( ns.values[ pid ] + ns.values[ pid - 1 ] ) * .5f };
|
||||
ns.durations[ pid - 1 ] -= hd;
|
||||
ns.durations.insert( pid - 1 , hd );
|
||||
ns.values.insert( pid , hv );
|
||||
SyncEditor::ReplaceCurve( std::move( c ) );
|
||||
(*selPoint) ++;
|
||||
}
|
||||
}
|
||||
if ( canInsertAfter ) {
|
||||
Text( " " );
|
||||
SameLine( 110 );
|
||||
if ( Button( "Insert after" , ImVec2{ -1 , 0 } ) && canUseButtons ) {
|
||||
// FIXME move to syncedit
|
||||
auto c{ *curve };
|
||||
auto& ns{ c.segments[ sid ] };
|
||||
const auto hd{ ns.durations[ pid ] / 2 };
|
||||
// FIXME: this should use the actual value
|
||||
const float hv{ ( ns.values[ pid ] + ns.values[ pid + 1 ] ) * .5f };
|
||||
ns.durations[ pid ] -= hd;
|
||||
ns.durations.insert( pid , hd );
|
||||
ns.values.insert( pid + 1 , hv );
|
||||
SyncEditor::ReplaceCurve( std::move( c ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( changed ) {
|
||||
if ( selUpdate == E_ChangeType::NONE ) {
|
||||
selUpdatingOriginal = *curve;
|
||||
selUpdatingCopy = *curve;
|
||||
selUpdate = E_ChangeType::POINT_VALUE;
|
||||
} else {
|
||||
assert( selUpdate == E_ChangeType::POINT_VALUE );
|
||||
}
|
||||
selUpdatingCopy->segments[ sid ].values[ pid ] = value;
|
||||
sync.setCurve( *selUpdatingCopy );
|
||||
} else if ( selUpdate == E_ChangeType::POINT_VALUE ) {
|
||||
selUpdate = E_ChangeType::NONE;
|
||||
sync.setCurve( *selUpdatingOriginal );
|
||||
SyncEditor::ReplaceCurve( std::move( *selUpdatingCopy ) );
|
||||
selUpdatingCopy.clear( );
|
||||
}
|
||||
|
||||
End( );
|
||||
}
|
||||
|
||||
} // namespace <anon>
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue