Sequencer - Edit demo duration

This commit is contained in:
Emmanuel BENOîT 2017-11-22 14:14:49 +01:00
parent 5445021664
commit bd8eb2ff02
6 changed files with 275 additions and 32 deletions

1
TODO
View file

@ -37,7 +37,6 @@ Sync / inputs:
* Value changes
* Duration changes
* Point insertion
* Total duration / duration unit changes
* Compaction
* Local changes vs file update
* Editing single values

11
main.cc
View file

@ -10,8 +10,7 @@
#include "rendertarget.hh"
#include "sync.hh"
#include "syncview.hh"
using ebcl::T_Optional;
#include "undo.hh"
/*= T_Main ===================================================================*/
@ -205,9 +204,17 @@ void T_Main::handleCapture( )
void T_Main::makeUI( )
{
using namespace ImGui;
auto& undo( Globals::Undo( ) );
bool eSequencer{ sequencer };
if ( BeginMainMenuBar( ) ) {
if ( BeginMenu( "File" ) ) {
if ( MenuItem( "Undo" , "C-z" , false , undo.canUndo( ) ) ) {
undo.undo( );
}
if ( MenuItem( "Redo" , "C-Z" , false , undo.canRedo( ) ) ) {
undo.redo( );
}
Separator( );
if ( MenuItem( "Quit" ) ) {
done = true;
}

View file

@ -348,6 +348,9 @@ struct T_SyncManager : public virtual A_MouseCtrl
void setCurve( T_SyncCurve curve );
void removeCurve( T_String const& curve ) noexcept;
T_Array< T_SyncCurve > const& curves( ) const noexcept
{ return curves_.curves.values( ); }
private:
void curvesChanged_( );
bool loadCurves_( bool& missing );

View file

@ -3,7 +3,7 @@
#include "globals.hh"
/*= T_UndoSyncChanges ==========================================================*/
/*= T_UndoSyncChanges ========================================================*/
void T_UndoSyncChanges::undo( ) const noexcept
{
@ -33,7 +33,7 @@ void T_UndoSyncChanges::redo( ) const noexcept
}
}
/*------------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
T_UndoSyncChanges& T_UndoSyncChanges::curveCreation(
T_SyncCurve curve ) noexcept
@ -81,3 +81,91 @@ T_UndoSyncChanges& T_UndoSyncChanges::curveReplacement(
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
{
Globals::Sync( ).setDuration( uSizeBefore_ , unitsBefore_ );
T_UndoSyncChanges::undo( );
}
void T_UndoDurationChanges::redo( ) const noexcept
{
Globals::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 ) ) );
printf( "initial duration %f (%d units) ; new duration %f (%d units)\n" ,
duration , segment.durations[ i ] ,
uSizeAfter * nSeg.durations[ i ] ,
nSeg.durations[ i ] );
}
}
return nCurve;
}
} // namespace <anon>
void SyncEditor::SetDuration(
const uint32_t units ,
const float uSize ,
const bool scaleCurves ) noexcept
{
auto& sync{ Globals::Sync( ) };
const float oldUnitSize{ sync.durationUnitSize( ) };
const uint32_t oldUnits{ sync.durationUnits( ) };
if ( oldUnits == units && oldUnitSize == uSize ) {
return;
}
auto& undo{ dynamic_cast< T_UndoDurationChanges& >(
Globals::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 ) );
}
}

View file

@ -3,7 +3,7 @@
#include "undo.hh"
/*= GENERAL STRUCTURE FOR SYNC EDITOR UNDOS ====================================*/
/*= GENERAL STRUCTURE FOR SYNC EDITOR UNDOS ==================================*/
class T_UndoSyncChanges : public A_UndoAction
{
@ -51,3 +51,42 @@ class T_UndoSyncChanges : public A_UndoAction
T_SyncCurve before ,
T_SyncCurve after ) noexcept;
};
/*= DURATION CHANGES =========================================================*/
class T_UndoDurationChanges final : public T_UndoSyncChanges
{
private:
uint32_t unitsBefore_ , unitsAfter_;
float uSizeBefore_ , uSizeAfter_;
public:
T_UndoDurationChanges(
uint32_t units ,
uint32_t oldUnits ,
float unitSize ,
float oldUnitSize ) noexcept;
T_UndoDurationChanges( ) noexcept = delete;
DEF_MOVE( T_UndoDurationChanges );
NO_COPY( T_UndoDurationChanges );
void undo( ) const noexcept override;
void redo( ) const noexcept override;
};
/*= EDITION FUNCTIONS ========================================================*/
struct SyncEditor final
{
// Change the duration of the demo using the specified unit count and
// size. If scaleCurves is true and the unit size has changed, the
// curves' durations will be scaled so that the timings match as
// closely as possible.
static void SetDuration(
uint32_t units ,
float uSize ,
bool scaleCurves ) noexcept;
};

View file

@ -2,38 +2,130 @@
#include "syncview.hh"
#include "globals.hh"
#include "window.hh"
#include "syncedit.hh"
#define IMGUI_DEFINE_MATH_OPERATORS
#include <imgui_internal.h>
using namespace ebcl;
/*= FAKE TABS HELPER ===========================================================*/
namespace {
bool FakeTab_(
char const* const name ,
const bool disabled ,
const float width = 0.f )
{
using namespace ImGui;
if ( disabled ) {
PushItemFlag( ImGuiItemFlags_Disabled , true );
PushStyleVar( ImGuiStyleVar_Alpha ,
GetStyle( ).Alpha * .5f );
}
const bool rv( Button( name , ImVec2{ width , 0.f } ) );
if ( disabled ) {
PopItemFlag( );
PopStyleVar( );
}
return rv;
/*= FAKE TABS HELPER =========================================================*/
bool FakeTab_(
char const* const name ,
const bool disabled ,
const float width = 0.f )
{
using namespace ImGui;
if ( disabled ) {
PushItemFlag( ImGuiItemFlags_Disabled , true );
PushStyleVar( ImGuiStyleVar_Alpha ,
GetStyle( ).Alpha * .5f );
}
} // namespace <anon>
const bool rv( Button( name , ImVec2{ width , 0.f } ) );
if ( disabled ) {
PopItemFlag( );
PopStyleVar( );
}
return rv;
}
/*= T_SyncViewImpl_ ============================================================*/
namespace {
/*= T_ChangeDurationDialog_ ==================================================*/
class T_ChangeDurationDialog_ : public A_ModalDialog
{
private:
const uint32_t units0_;
const float uSize0_;
const uint32_t uPerMinute0_;
uint32_t units_;
float uSize_;
uint32_t uPerMinute_;
bool scale_{ true };
protected:
bool drawDialog( ) noexcept override;
void onOK( ) noexcept override;
public:
T_ChangeDurationDialog_(
uint32_t units ,
float uSize ) noexcept;
};
/*----------------------------------------------------------------------------*/
T_ChangeDurationDialog_::T_ChangeDurationDialog_(
const uint32_t units ,
const float uSize ) noexcept
: A_ModalDialog{ "Set demo duration...##duration-dialog" } ,
units0_{ units } , uSize0_{ std::max( 1.f / 60.f , uSize ) } ,
uPerMinute0_{ uint32_t( ImClamp( roundf( 60.f / uSize0_ ) , 1.f , 3600.f ) ) } ,
units_{ units0_ } , uSize_{ uSize0_ } , uPerMinute_{ uPerMinute0_ }
{
setInitialSize( 300.f , 180.f );
}
bool T_ChangeDurationDialog_::drawDialog( ) noexcept
{
using namespace ImGui;
int tUnits( units_ );
if ( DragInt( "Duration##units" , &tUnits , .1f , 1 , INT32_MAX , "%.0f unit(s)" ) ) {
units_ = uint32_t( std::min( INT32_MAX , std::max( 1 , tUnits ) ) );
}
float tDuration( units_ * uSize_ );
if ( DragFloat( "##seconds" , &tDuration , 1.f , .001f , FLT_MAX , "%.3f second(s)" ) ) {
units_ = std::min( uint32_t( INT32_MAX ) , std::max( 1u ,
uint32_t( roundf( tDuration / uSize_ ) ) ) );
}
Separator( );
int tUsize( floorf( uSize_ * 1000.f ) );
if ( SliderInt( "Units" , &tUsize , 16 , 2000 , "%.0f ms" ) ) {
const float pDur{ uSize_ * units_ };
uSize_ = std::min( 2.f , std::max( 1.f / 60.f ,
.001f * tUsize ) );
uPerMinute_ = roundf( 60.f / uSize_ );
units_ = uint32_t( roundf( pDur / uSize_ ) );
}
int tPerMin( uPerMinute_ );
if ( SliderInt( "Units/minute" , &tPerMin , 30 , 3600 ) ) {
const float pDur{ uSize_ * units_ };
uPerMinute_ = std::max( 30u , std::min( 3600u , uint32_t( tPerMin ) ) );
uSize_ = 60.f / uPerMinute_;
units_ = uint32_t( roundf( pDur / uSize_ ) );
}
if ( uPerMinute0_ == uPerMinute_ ) {
PushItemFlag( ImGuiItemFlags_Disabled , true );
PushStyleVar( ImGuiStyleVar_Alpha ,
GetStyle( ).Alpha * .5f );
}
Checkbox( "Scale curves" , &scale_ );
if ( uPerMinute0_ == uPerMinute_ ) {
PopItemFlag( );
PopStyleVar( );
}
return units_ != units0_ || uPerMinute_ != uPerMinute0_;
}
void T_ChangeDurationDialog_::onOK( ) noexcept
{
SyncEditor::SetDuration( units_ ,
uPerMinute_ != uPerMinute0_ ? uSize_ : uSize0_ ,
scale_ );
}
/*= T_SyncViewImpl_ ==========================================================*/
struct T_SyncViewImpl_
{
@ -94,7 +186,7 @@ struct T_SyncViewImpl_
constexpr float T_SyncViewImpl_::BarWidth;
/*------------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
bool T_SyncViewImpl_::display( ) noexcept
{
@ -168,6 +260,20 @@ bool T_SyncViewImpl_::display( ) noexcept
VerticalSeparator( );
SameLine( );
if ( Button( ICON_FA_CLOCK_O , BtSize ) ) {
Globals::Window( ).pushDialog( NewOwned< T_ChangeDurationDialog_ >(
sync.durationUnits( ) , sync.durationUnitSize( ) ) );
}
if ( IsItemHovered( ) ) {
BeginTooltip( );
Text( "Change duration and time units." );
EndTooltip( );
}
SameLine( );
VerticalSeparator( );
SameLine( );
if ( Button( ICON_FA_LINE_CHART ) ) {
const bool displaySelector{ sub == SW_CURVE_SELECTOR
|| sub == SW_OVERRIDE_SELECTOR };
@ -425,7 +531,7 @@ void T_SyncViewImpl_::sequencerBody(
}
}
/*------------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
void T_SyncViewImpl_::displayCurveSelectorWindow( ) noexcept
{
@ -597,9 +703,10 @@ void T_SyncViewImpl_::displayOverrideSelector( ) noexcept
EndChild( );
}
} // namespace <anon>
} // namespace
/*= T_SyncView =================================================================*/
/*= T_SyncView ===============================================================*/
T_SyncView::T_SyncView( ) noexcept
: A_PrivateImplementation( new T_SyncViewImpl_( ) )