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 ,
|
||||
const float initial = 0.f ) noexcept
|
||||
{ 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
|
||||
{ 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(
|
||||
T_SyncCurve const& initial ,
|
||||
const uint32_t segmentIndex ,
|
||||
|
|
|
@ -90,6 +90,25 @@ struct SyncEditor final
|
|||
float uSize ,
|
||||
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.
|
||||
static void SetSegmentType(
|
||||
T_SyncCurve const& initial ,
|
||||
|
|
143
ui-sequencer.cc
143
ui-sequencer.cc
|
@ -205,6 +205,7 @@ struct T_SyncViewImpl_
|
|||
SW_NONE ,
|
||||
SW_INPUT_SELECTOR ,
|
||||
SW_OVERRIDE_SELECTOR ,
|
||||
SW_TRACK ,
|
||||
SW_SEGMENT ,
|
||||
};
|
||||
|
||||
|
@ -215,8 +216,8 @@ struct T_SyncViewImpl_
|
|||
//----------------------------------------------------------------------
|
||||
// Sequencer widget methods
|
||||
|
||||
void computeMetrics( float innerWidth ) noexcept;
|
||||
void sequencerWidget( ) noexcept;
|
||||
void computeMetrics( float innerWidth ) noexcept;
|
||||
void sequencerHeader( ImRect const& bb ) noexcept;
|
||||
void sequencerBody( ImRect const& bb ) noexcept;
|
||||
void sequencerTracks(
|
||||
|
@ -242,6 +243,7 @@ struct T_SyncViewImpl_
|
|||
void displayInputSelector( ) noexcept;
|
||||
void displayOverrideSelector( ) noexcept;
|
||||
|
||||
void displayTrackWindow( ) noexcept;
|
||||
void displaySegmentWindow( ) noexcept;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
@ -285,7 +287,7 @@ struct T_SyncViewImpl_
|
|||
// Selected item
|
||||
T_String selId{ };
|
||||
bool selIsOverride;
|
||||
uint32_t selSegment;
|
||||
T_Optional< uint32_t > selSegment;
|
||||
T_Optional< uint32_t > selPoint;
|
||||
|
||||
// Sub-windows
|
||||
|
@ -337,6 +339,10 @@ bool T_SyncViewImpl_::display( ) noexcept
|
|||
displayTrackSelectorWindow( );
|
||||
break;
|
||||
|
||||
case SW_TRACK:
|
||||
displayTrackWindow( );
|
||||
break;
|
||||
|
||||
case SW_SEGMENT:
|
||||
displaySegmentWindow( );
|
||||
break;
|
||||
|
@ -548,6 +554,15 @@ void T_SyncViewImpl_::sequencerWidget( ) noexcept
|
|||
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 ) {
|
||||
auto const& dSeg{ dspSegments[ mp.index ] };
|
||||
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
|
||||
{
|
||||
using namespace ImGui;
|
||||
|
@ -1151,25 +1262,28 @@ void T_SyncViewImpl_::displaySegmentWindow( ) noexcept
|
|||
return;
|
||||
}
|
||||
|
||||
const uint32_t sid{ *selSegment };
|
||||
|
||||
Text( "Curve:" );
|
||||
SameLine( 110 );
|
||||
Text( "%s" , selId.toOSString( ).data( ) );
|
||||
|
||||
Text( "Index:" );
|
||||
SameLine( 110 );
|
||||
Text( "%d" , selSegment );
|
||||
Text( "%d" , sid );
|
||||
|
||||
Separator( );
|
||||
|
||||
// Access curve and segment
|
||||
auto& sync{ Common::Sync( ) };
|
||||
auto* const curve{ sync.getCurve( selId ) };
|
||||
auto& segment{ curve->segments[ selSegment ] };
|
||||
auto const* const curve{ sync.getCurve( selId ) };
|
||||
auto const& segment{ curve->segments[ sid ] };
|
||||
|
||||
// Find start and duration
|
||||
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& tgt{ i == selSegment ? duration : start };
|
||||
auto& tgt{ i == sid ? duration : start };
|
||||
for ( auto d : s.durations ) {
|
||||
tgt += d;
|
||||
}
|
||||
|
@ -1240,8 +1354,21 @@ void T_SyncViewImpl_::displaySegmentWindow( ) noexcept
|
|||
SameLine( 110 );
|
||||
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 ) {
|
||||
SyncEditor::SetSegmentType( *curve , selSegment ,
|
||||
SyncEditor::SetSegmentType( *curve , sid ,
|
||||
T_SyncSegment::E_SegmentType( t ) );
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue