Sequencer - Segment creation & deletion, curve deletion
This commit is contained in:
parent
93aec231c5
commit
4e5991d2ea
4 changed files with 244 additions and 8 deletions
|
@ -315,6 +315,8 @@ struct T_SyncManager : public virtual A_ProjectPathListener
|
||||||
bool addInput( T_String const& name ,
|
bool addInput( T_String const& name ,
|
||||||
const float initial = 0.f ) noexcept
|
const float initial = 0.f ) noexcept
|
||||||
{ return values_.addValue( name , initial ); }
|
{ return values_.addValue( name , initial ); }
|
||||||
|
bool hasInput( T_String const& name ) const noexcept
|
||||||
|
{ return values_.identifiers.contains( name ); }
|
||||||
|
|
||||||
T_Array< T_String > const& inputNames( ) const noexcept
|
T_Array< T_String > const& inputNames( ) const noexcept
|
||||||
{ return values_.identifiers; }
|
{ return values_.identifiers; }
|
||||||
|
|
|
@ -172,6 +172,94 @@ void SyncEditor::SetDuration(
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
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(
|
void SyncEditor::SetSegmentType(
|
||||||
T_SyncCurve const& initial ,
|
T_SyncCurve const& initial ,
|
||||||
const uint32_t segmentIndex ,
|
const uint32_t segmentIndex ,
|
||||||
|
|
|
@ -90,6 +90,25 @@ struct SyncEditor final
|
||||||
float uSize ,
|
float uSize ,
|
||||||
bool scaleCurves ) noexcept;
|
bool scaleCurves ) noexcept;
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Delete a curve's record completely.
|
||||||
|
static void DeleteCurve(
|
||||||
|
T_String const& id ) noexcept;
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Append a segment with the specified amount of units at the end of
|
||||||
|
// the curve. If the curve does not exist it will be created.
|
||||||
|
static void AppendSegment(
|
||||||
|
T_String const& id ,
|
||||||
|
uint32_t nsDuration ) noexcept;
|
||||||
|
|
||||||
|
// Delete a segment from a curve.
|
||||||
|
static void DeleteSegment(
|
||||||
|
T_String const& id ,
|
||||||
|
uint32_t segmentIndex ) noexcept;
|
||||||
|
|
||||||
// Change the type of a segment in a curve.
|
// Change the type of a segment in a curve.
|
||||||
static void SetSegmentType(
|
static void SetSegmentType(
|
||||||
T_SyncCurve const& initial ,
|
T_SyncCurve const& initial ,
|
||||||
|
|
143
ui-sequencer.cc
143
ui-sequencer.cc
|
@ -205,6 +205,7 @@ struct T_SyncViewImpl_
|
||||||
SW_NONE ,
|
SW_NONE ,
|
||||||
SW_INPUT_SELECTOR ,
|
SW_INPUT_SELECTOR ,
|
||||||
SW_OVERRIDE_SELECTOR ,
|
SW_OVERRIDE_SELECTOR ,
|
||||||
|
SW_TRACK ,
|
||||||
SW_SEGMENT ,
|
SW_SEGMENT ,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -215,8 +216,8 @@ struct T_SyncViewImpl_
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
// Sequencer widget methods
|
// Sequencer widget methods
|
||||||
|
|
||||||
void computeMetrics( float innerWidth ) noexcept;
|
|
||||||
void sequencerWidget( ) noexcept;
|
void sequencerWidget( ) noexcept;
|
||||||
|
void computeMetrics( float innerWidth ) noexcept;
|
||||||
void sequencerHeader( ImRect const& bb ) noexcept;
|
void sequencerHeader( ImRect const& bb ) noexcept;
|
||||||
void sequencerBody( ImRect const& bb ) noexcept;
|
void sequencerBody( ImRect const& bb ) noexcept;
|
||||||
void sequencerTracks(
|
void sequencerTracks(
|
||||||
|
@ -242,6 +243,7 @@ struct T_SyncViewImpl_
|
||||||
void displayInputSelector( ) noexcept;
|
void displayInputSelector( ) noexcept;
|
||||||
void displayOverrideSelector( ) noexcept;
|
void displayOverrideSelector( ) noexcept;
|
||||||
|
|
||||||
|
void displayTrackWindow( ) noexcept;
|
||||||
void displaySegmentWindow( ) noexcept;
|
void displaySegmentWindow( ) noexcept;
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
@ -285,7 +287,7 @@ struct T_SyncViewImpl_
|
||||||
// Selected item
|
// Selected item
|
||||||
T_String selId{ };
|
T_String selId{ };
|
||||||
bool selIsOverride;
|
bool selIsOverride;
|
||||||
uint32_t selSegment;
|
T_Optional< uint32_t > selSegment;
|
||||||
T_Optional< uint32_t > selPoint;
|
T_Optional< uint32_t > selPoint;
|
||||||
|
|
||||||
// Sub-windows
|
// Sub-windows
|
||||||
|
@ -337,6 +339,10 @@ bool T_SyncViewImpl_::display( ) noexcept
|
||||||
displayTrackSelectorWindow( );
|
displayTrackSelectorWindow( );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SW_TRACK:
|
||||||
|
displayTrackWindow( );
|
||||||
|
break;
|
||||||
|
|
||||||
case SW_SEGMENT:
|
case SW_SEGMENT:
|
||||||
displaySegmentWindow( );
|
displaySegmentWindow( );
|
||||||
break;
|
break;
|
||||||
|
@ -548,6 +554,15 @@ void T_SyncViewImpl_::sequencerWidget( ) noexcept
|
||||||
curZoomPixel = mPixels;
|
curZoomPixel = mPixels;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
} else if ( mp.type == E_MousePosType::TRACK ) {
|
||||||
|
auto const& dTrack{ dspTracks[ mp.index ] };
|
||||||
|
if ( io.MouseDown[ 0 ] || io.MouseDown[ 1 ] ) {
|
||||||
|
selId = dTrack.id;
|
||||||
|
selIsOverride = dTrack.isOverride;
|
||||||
|
selSegment = {};
|
||||||
|
selPoint = {};
|
||||||
|
sub = E_SubWindow::SW_TRACK;
|
||||||
|
}
|
||||||
} else if ( mp.type == E_MousePosType::SEGMENT ) {
|
} else if ( mp.type == E_MousePosType::SEGMENT ) {
|
||||||
auto const& dSeg{ dspSegments[ mp.index ] };
|
auto const& dSeg{ dspSegments[ mp.index ] };
|
||||||
auto const& dTrack{ dspTracks[ dSeg.track ] };
|
auto const& dTrack{ dspTracks[ dSeg.track ] };
|
||||||
|
@ -1135,6 +1150,102 @@ void T_SyncViewImpl_::displayOverrideSelector( ) noexcept
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void T_SyncViewImpl_::displayTrackWindow( ) 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 track" , &displayed , ImGuiWindowFlags_NoCollapse );
|
||||||
|
if ( !displayed ) {
|
||||||
|
End( );
|
||||||
|
sub = SW_NONE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the curve
|
||||||
|
auto& sync{ Common::Sync( ) };
|
||||||
|
auto const* const curve{ sync.getCurve( selId ) };
|
||||||
|
|
||||||
|
Text( "Curve:" );
|
||||||
|
SameLine( 110 );
|
||||||
|
Text( "%s" , selId.toOSString( ).data( ) );
|
||||||
|
if ( !sync.hasInput( selId ) ) {
|
||||||
|
Text( " " );
|
||||||
|
SameLine( 110 );
|
||||||
|
Text( "No matching input" );
|
||||||
|
}
|
||||||
|
|
||||||
|
Text( "Segments:" );
|
||||||
|
SameLine( 110 );
|
||||||
|
Text( "%d" , curve ? curve->segments.size( ) : 0 );
|
||||||
|
Separator( );
|
||||||
|
|
||||||
|
// Compute total duration
|
||||||
|
const uint32_t duration{ [&](){
|
||||||
|
uint32_t t{ 0 };
|
||||||
|
if ( !curve ) {
|
||||||
|
return 0u;
|
||||||
|
}
|
||||||
|
for ( auto const& s : curve->segments ) {
|
||||||
|
for ( auto const& d : s.durations ) {
|
||||||
|
t += d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}() };
|
||||||
|
const float tDuration{ duration * sync.durationUnitSize( ) };
|
||||||
|
|
||||||
|
Text( "Duration:" );
|
||||||
|
SameLine( 110 );
|
||||||
|
Text( "%d units" , duration );
|
||||||
|
|
||||||
|
Text( " " );
|
||||||
|
SameLine( 110 );
|
||||||
|
Text( "%.3f seconds" , tDuration );
|
||||||
|
|
||||||
|
const float dDuration{ sync.duration( ) };
|
||||||
|
if ( tDuration == 0.f ) {
|
||||||
|
Text( " " );
|
||||||
|
SameLine( 110 );
|
||||||
|
Text( "Empty track" );
|
||||||
|
} else if ( tDuration == dDuration ) {
|
||||||
|
Text( " " );
|
||||||
|
SameLine( 110 );
|
||||||
|
Text( "Covers the whole demo" );
|
||||||
|
} else if ( tDuration > dDuration ) {
|
||||||
|
Text( " " );
|
||||||
|
SameLine( 110 );
|
||||||
|
Text( "Longer than the demo" );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ( curve && !curve->segments.empty( ) ) || tDuration < dDuration ) {
|
||||||
|
Separator( );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( curve && !curve->segments.empty( ) ) {
|
||||||
|
Text( " " );
|
||||||
|
SameLine( 110 );
|
||||||
|
if ( Button( "Clear" , ImVec2{ -1 , 0 } ) ) {
|
||||||
|
SyncEditor::DeleteCurve( selId );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( tDuration < dDuration ) {
|
||||||
|
Text( " " );
|
||||||
|
SameLine( 110 );
|
||||||
|
if ( Button( "Append segment" , ImVec2{ -1 , 0 } ) ) {
|
||||||
|
const uint32_t ns{ std::max( 1u ,
|
||||||
|
( sync.durationUnits( ) - duration ) / 2 ) };
|
||||||
|
SyncEditor::AppendSegment( selId , ns );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
End( );
|
||||||
|
}
|
||||||
|
|
||||||
void T_SyncViewImpl_::displaySegmentWindow( ) noexcept
|
void T_SyncViewImpl_::displaySegmentWindow( ) noexcept
|
||||||
{
|
{
|
||||||
using namespace ImGui;
|
using namespace ImGui;
|
||||||
|
@ -1151,25 +1262,28 @@ void T_SyncViewImpl_::displaySegmentWindow( ) noexcept
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const uint32_t sid{ *selSegment };
|
||||||
|
|
||||||
Text( "Curve:" );
|
Text( "Curve:" );
|
||||||
SameLine( 110 );
|
SameLine( 110 );
|
||||||
Text( "%s" , selId.toOSString( ).data( ) );
|
Text( "%s" , selId.toOSString( ).data( ) );
|
||||||
|
|
||||||
Text( "Index:" );
|
Text( "Index:" );
|
||||||
SameLine( 110 );
|
SameLine( 110 );
|
||||||
Text( "%d" , selSegment );
|
Text( "%d" , sid );
|
||||||
|
|
||||||
Separator( );
|
Separator( );
|
||||||
|
|
||||||
|
// Access curve and segment
|
||||||
auto& sync{ Common::Sync( ) };
|
auto& sync{ Common::Sync( ) };
|
||||||
auto* const curve{ sync.getCurve( selId ) };
|
auto const* const curve{ sync.getCurve( selId ) };
|
||||||
auto& segment{ curve->segments[ selSegment ] };
|
auto const& segment{ curve->segments[ sid ] };
|
||||||
|
|
||||||
// Find start and duration
|
// Find start and duration
|
||||||
uint32_t start{ 0 } , duration{ 0 };
|
uint32_t start{ 0 } , duration{ 0 };
|
||||||
for ( auto i = 0u ; i <= selSegment ; i ++ ) {
|
for ( auto i = 0u ; i <= sid ; i ++ ) {
|
||||||
auto const& s{ curve->segments[ i ] };
|
auto const& s{ curve->segments[ i ] };
|
||||||
auto& tgt{ i == selSegment ? duration : start };
|
auto& tgt{ i == sid ? duration : start };
|
||||||
for ( auto d : s.durations ) {
|
for ( auto d : s.durations ) {
|
||||||
tgt += d;
|
tgt += d;
|
||||||
}
|
}
|
||||||
|
@ -1240,8 +1354,21 @@ void T_SyncViewImpl_::displaySegmentWindow( ) noexcept
|
||||||
SameLine( 110 );
|
SameLine( 110 );
|
||||||
Text( "%f" , sMax );
|
Text( "%f" , sMax );
|
||||||
|
|
||||||
|
Separator( );
|
||||||
|
|
||||||
|
Text( " " );
|
||||||
|
SameLine( 110 );
|
||||||
|
if ( Button( "Delete segment" , ImVec2{ -1 , 0 } ) ) {
|
||||||
|
if ( curve->segments.size( ) > 1 ) {
|
||||||
|
selSegment = ( sid == 0 ? 0 : ( sid - 1 ) );
|
||||||
|
} else {
|
||||||
|
selSegment = {};
|
||||||
|
}
|
||||||
|
SyncEditor::DeleteSegment( selId , sid );
|
||||||
|
}
|
||||||
|
|
||||||
if ( change ) {
|
if ( change ) {
|
||||||
SyncEditor::SetSegmentType( *curve , selSegment ,
|
SyncEditor::SetSegmentType( *curve , sid ,
|
||||||
T_SyncSegment::E_SegmentType( t ) );
|
T_SyncSegment::E_SegmentType( t ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue