| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101 |
- /******************************************************************************
- Undo supports two modes:
- -Full
- -Partial
- For "Full" mode each Change must contain the entire copy of the data.
- For "Partial" mode each Change contains only information about the data that was changed,
- it is the user's responsibility to design the "Change" class to properly store that information.
- Full mode may be easier to implement, however it may use a lot more memory for big amounts of data.
- /******************************************************************************/
- namespace Edit{
- /******************************************************************************/
- struct _Undo // Undo (do not use this class, use 'Undo' below)
- {
- struct Change
- {
- virtual UInt memUsage()C {return 0;} // override this method and return the memory usage of this Undo Change
- // methods used in "Full" mode
- virtual void create(Ptr user) {} // this is called when current state was requested to be saved , inside this method you should copy entire state of data into this class, 'user'=user data with its value taken from 'Undo.user'
- virtual void apply (Ptr user) {} // this is called when this Undo Change was requested to be applied, inside this method you should copy entire state from this class to data, 'user'=user data with its value taken from 'Undo.user'
- // methods used in "Partial" mode
- virtual void swap(Ptr user) {} // this is called when this Undo Change was requested to be applied, inside this method you should swap the changes between this class and data, 'user'=user data with its value taken from 'Undo.user'
- };
- Ptr user; // custom user data that will be passed to 'Change' methods
- Flt time; // max time between multiple changes to consider them as one
- // apply Undo/Redo
- Bool undo (); // perform Undo by calling 'Change.apply', false on fail (if there are no Undos)
- Bool redo (); // perform Redo by calling 'Change.apply', false on fail (if there are no Redos)
- Bool undoAsChange(); // perform Undo by calling 'Change.apply', false on fail (if there are no Undos), this method applies the Undo as if it is a new change to the data
- // get
- Bool undosAvailable ()C {return undos()>0;} // if any Undos are avaialble
- Bool redosAvailable ()C {return redos()>0;} // if any Redos are avaialble
- Int undos ()C {return _undos;} // get number of available Undos
- Int redos ()C {return changes()-_undos;} // get number of available Redos
- CPtr lastChangeType ()C {return _change_type;} // get last type of change that was applied in CPtr format
- Int lastChangeTypeI()C {return (Int)(IntPtr)_change_type;} // get last type of change that was applied in Int format
- Change* getNextUndo(); // get next undo in line, null is returned if there's no undo
- Change* getNextRedo(); // get next redo in line, null is returned if there's no redo
- Change& operator[]( Int i ) {return _changes [i ];} // get i-th change
- Change* addr ( Int i ) {return _changes.addr (i );} // get i-th change address, null is returned if index is out of range
- Int index (C Change *change)C{return _changes.validIndex(change);} // get index of change, -1 on fail
- // operations
- _Undo& del (); // reset to default empty state, this removes all Undo Changes but keeps max allowed limit settings
- _Undo& forceCreateNextUndo(); // always allow the next 'set' call to create a new Undo Change
- // max allowed limit settings
- Long memUsage()C; _Undo& maxMemUsage(Long limit); // get current memory usage / set max allowed memory usage for all Undo Changes (-1=unlimited, default=-1)
- Int changes ()C; _Undo& maxChanges (Int limit); // get current changes count / set max allowed number of all Undo Changes (-1=unlimited, default=-1)
- private:
- Bool _full;
- Int _undos, _max_changes;
- UInt _change_frame;
- Long _max_mem_usage;
- Dbl _change_time;
- CPtr _change_type;
- Memx<Change> _changes;
- Change* set(CPtr change_type, Bool force_create, Flt extra_time);
- Change* set( Int change_type, Bool force_create, Flt extra_time);
- #if EE_PRIVATE
- void clean(Bool test_mem_usage);
- #endif
- explicit _Undo(Bool full, Ptr user, Flt time);
- T1(TYPE) friend struct Undo;
- };
- /******************************************************************************/
- T1(TYPE) struct Undo : _Undo // 'TYPE' must be based on '_Undo.Change'
- {
- explicit Undo(Bool full, Ptr user=null, Flt time=1.0f); // 'full'=if use "Full" or "Partial" mode, 'user'=custom user data that will be passed to 'Change' methods, 'time'=max time between multiple changes to consider them as one
- TYPE* getNextUndo(); // get next undo in line, null is returned if there's no undo
- TYPE* getNextRedo(); // get next redo in line, null is returned if there's no redo
- TYPE& operator[](Int i); // get i-th change
- TYPE* addr (Int i); // get i-th change address, null is returned if index is out of range
- // create Undo Change
- TYPE* set(CPtr change_type=null, Bool force_create=false, Flt extra_time=0); // create a new Undo Change, call this if data associated with this Undo is going to be changed with a specific type, 'change_type'=unique pointer allowing to differentiate between types (it can point to anything as that data is not accessed but only the memory address is, recommended way is to pass C++ strings like "move", "rotate"), by default new Undo Changes will not be created if in a short while ago (based on 'Undo.time') there was a change with a similar 'change_type', however setting 'force_create' to true will always force creation of a new Undo Change, this method will return the pointer to a new Undo Change if it was created and null if it wasn't. 'extra_time'=extra time for this particular change that would allow it to be considered the same as the last one. In Undo "Partial" mode this method will always return a Change object, in case the new change is of the same type as the last one and was requested within a short amount of time, then the last Change object will be returned.
- TYPE* set( Int change_type , Bool force_create=false, Flt extra_time=0); // create a new Undo Change, call this if data associated with this Undo is going to be changed with a specific type, 'change_type'=unique value allowing to differentiate between types (it can be set to anything , recommended way is to use C++ custom enum value ), by default new Undo Changes will not be created if in a short while ago (based on 'Undo.time') there was a change with a similar 'change_type', however setting 'force_create' to true will always force creation of a new Undo Change, this method will return the pointer to a new Undo Change if it was created and null if it wasn't. 'extra_time'=extra time for this particular change that would allow it to be considered the same as the last one. In Undo "Partial" mode this method will always return a Change object, in case the new change is of the same type as the last one and was requested within a short amount of time, then the last Change object will be returned.
- T1(CHANGE) Undo& replaceClass();
- };
- /******************************************************************************/
- } // namespace
- /******************************************************************************/
- inline Int Elms(C Edit::_Undo &undo) {return undo.changes();}
- /******************************************************************************/
|