diff --git a/Makefile b/Makefile index 1d2b9b1..15f19fd 100644 --- a/Makefile +++ b/Makefile @@ -44,6 +44,7 @@ DEMO = \ demo.cc \ main.cc \ syncview.cc \ + undo.cc \ # END DEMO PARSERCHECK = \ diff --git a/globals.cc b/globals.cc index 07a95c4..f0a2347 100644 --- a/globals.cc +++ b/globals.cc @@ -9,6 +9,7 @@ #include "shaders.hh" #include "sync.hh" #include "texture.hh" +#include "undo.hh" #include "window.hh" @@ -20,6 +21,7 @@ T_OwnPtr< T_TextureManager > Globals::textures_; T_OwnPtr< T_ShaderManager > Globals::shaders_; T_OwnPtr< T_OutputDebugger > Globals::odbg_; T_OwnPtr< T_ScriptManager > Globals::ops_; +T_OwnPtr< T_UndoManager > Globals::undo_; void Globals::Init( ) @@ -32,10 +34,12 @@ void Globals::Init( ) shaders_ = NewOwned< T_ShaderManager >( ); odbg_ = NewOwned< T_OutputDebugger >( ); ops_ = NewOwned< T_ScriptManager >( ); + undo_ = NewOwned< T_UndoManager >( ); } void Globals::Shutdown( ) { + undo_.clear( ); ops_.clear( ); odbg_.clear( ); shaders_.clear( ); diff --git a/globals.hh b/globals.hh index f98bd0f..e35866b 100644 --- a/globals.hh +++ b/globals.hh @@ -12,6 +12,7 @@ struct T_ShaderManager; struct T_OutputDebugger; struct T_SyncManager; struct T_ScriptManager; +class T_UndoManager; struct Globals @@ -27,6 +28,7 @@ struct Globals static T_ShaderManager& Shaders( ) { return *shaders_; } static T_OutputDebugger& ODbg( ) { return *odbg_; } static T_ScriptManager& Ops( ) { return *ops_; } + static T_UndoManager& Undo( ) { return *undo_; } private: static T_OwnPtr< T_FilesWatcher > watcher_; @@ -37,4 +39,5 @@ struct Globals static T_OwnPtr< T_TextureManager > textures_; static T_OwnPtr< T_OutputDebugger > odbg_; static T_OwnPtr< T_ScriptManager > ops_; + static T_OwnPtr< T_UndoManager > undo_; }; diff --git a/undo.cc b/undo.cc new file mode 100644 index 0000000..ef27429 --- /dev/null +++ b/undo.cc @@ -0,0 +1,45 @@ +#include "externals.hh" +#include "undo.hh" + + +/*= A_UndoAction ===============================================================*/ + +A_UndoAction::~A_UndoAction( ) +{} + + +/*= T_UndoManager ==============================================================*/ + +void T_UndoManager::undo( ) noexcept +{ + if ( pos_ > 0 ) { + pos_ --; + actions_[ ( start_ + pos_ ) % MaxUndo ]->undo( ); + } +} + +void T_UndoManager::redo( ) noexcept +{ + if ( pos_ < count_ ) { + pos_ ++; + actions_[ ( start_ + pos_ ) % MaxUndo ]->redo( ); + } +} + +void T_UndoManager::addAction( + P_UndoAction action ) noexcept +{ + assert( action ); + while ( pos_ < count_ ) { + count_ --; + actions_[ ( start_ + count_ ) % MaxUndo ].clear( ); + } + if ( count_ == MaxUndo ) { + actions_[ start_ ] = std::move( action ); + start_ = ( start_ + 1 ) % MaxUndo; + } else { + actions_[ ( start_ + pos_ ) % MaxUndo ] = std::move( action ); + count_ ++; + pos_ ++; + } +} diff --git a/undo.hh b/undo.hh new file mode 100644 index 0000000..0180b45 --- /dev/null +++ b/undo.hh @@ -0,0 +1,57 @@ +#pragma once +#ifndef REAL_BUILD +# include "externals.hh" +#endif + + +// Interface for undo actions +class A_UndoAction +{ + public: + virtual ~A_UndoAction( ) = 0; + virtual void undo( ) const noexcept = 0; + virtual void redo( ) const noexcept = 0; +}; +using P_UndoAction = T_OwnPtr< A_UndoAction >; + + +// Undo manager +class T_UndoManager +{ + private: + static constexpr uint32_t MaxUndo = 1024; + + ebcl::T_StaticArray< P_UndoAction , MaxUndo > actions_; + uint32_t start_{ 0 }; + uint32_t count_{ 0 }; + uint32_t pos_{ 0 }; + + public: + T_UndoManager( ) noexcept = default; + DEF_MOVE( T_UndoManager ); + NO_COPY( T_UndoManager ); + + // Undo last action + void undo( ) noexcept; + // Redo last undone action + void redo( ) noexcept; + + // Add an action using a pointer + void addAction( P_UndoAction action ) noexcept; + + // Construct and add an action + template< + typename T , + typename... Args + > void add( Args&&... args ) noexcept; +}; + + +template< + typename T , + typename... Args +> inline void T_UndoManager::add( + Args&&... args ) noexcept +{ + addAction( NewOwned< T >( std::forward< Args >( args ) ... ) ); +}