Undo.h 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. /******************************************************************************
  2. Undo supports two modes:
  3. -Full
  4. -Partial
  5. For "Full" mode each Change must contain the entire copy of the data.
  6. For "Partial" mode each Change contains only information about the data that was changed,
  7. it is the user's responsibility to design the "Change" class to properly store that information.
  8. Full mode may be easier to implement, however it may use a lot more memory for big amounts of data.
  9. /******************************************************************************/
  10. namespace Edit{
  11. /******************************************************************************/
  12. struct _Undo // Undo (do not use this class, use 'Undo' below)
  13. {
  14. struct Change
  15. {
  16. virtual UInt memUsage()C {return 0;} // override this method and return the memory usage of this Undo Change
  17. // methods used in "Full" mode
  18. 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'
  19. 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'
  20. // methods used in "Partial" mode
  21. 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'
  22. };
  23. Ptr user; // custom user data that will be passed to 'Change' methods
  24. Flt time; // max time between multiple changes to consider them as one
  25. // apply Undo/Redo
  26. Bool undo (); // perform Undo by calling 'Change.apply', false on fail (if there are no Undos)
  27. Bool redo (); // perform Redo by calling 'Change.apply', false on fail (if there are no Redos)
  28. 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
  29. // get
  30. Bool undosAvailable ()C {return undos()>0;} // if any Undos are avaialble
  31. Bool redosAvailable ()C {return redos()>0;} // if any Redos are avaialble
  32. Int undos ()C {return _undos;} // get number of available Undos
  33. Int redos ()C {return changes()-_undos;} // get number of available Redos
  34. CPtr lastChangeType ()C {return _change_type;} // get last type of change that was applied in CPtr format
  35. Int lastChangeTypeI()C {return (Int)(IntPtr)_change_type;} // get last type of change that was applied in Int format
  36. Change* getNextUndo(); // get next undo in line, null is returned if there's no undo
  37. Change* getNextRedo(); // get next redo in line, null is returned if there's no redo
  38. Change& operator[]( Int i ) {return _changes [i ];} // get i-th change
  39. Change* addr ( Int i ) {return _changes.addr (i );} // get i-th change address, null is returned if index is out of range
  40. Int index (C Change *change)C{return _changes.validIndex(change);} // get index of change, -1 on fail
  41. // operations
  42. _Undo& del (); // reset to default empty state, this removes all Undo Changes but keeps max allowed limit settings
  43. _Undo& forceCreateNextUndo(); // always allow the next 'set' call to create a new Undo Change
  44. // max allowed limit settings
  45. Long memUsage()C; _Undo& maxMemUsage(Long limit); // get current memory usage / set max allowed memory usage for all Undo Changes (-1=unlimited, default=-1)
  46. Int changes ()C; _Undo& maxChanges (Int limit); // get current changes count / set max allowed number of all Undo Changes (-1=unlimited, default=-1)
  47. private:
  48. Bool _full;
  49. Int _undos, _max_changes;
  50. UInt _change_frame;
  51. Long _max_mem_usage;
  52. Dbl _change_time;
  53. CPtr _change_type;
  54. Memx<Change> _changes;
  55. Change* set(CPtr change_type, Bool force_create, Flt extra_time);
  56. Change* set( Int change_type, Bool force_create, Flt extra_time);
  57. #if EE_PRIVATE
  58. void clean(Bool test_mem_usage);
  59. #endif
  60. explicit _Undo(Bool full, Ptr user, Flt time);
  61. T1(TYPE) friend struct Undo;
  62. };
  63. /******************************************************************************/
  64. T1(TYPE) struct Undo : _Undo // 'TYPE' must be based on '_Undo.Change'
  65. {
  66. 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
  67. TYPE* getNextUndo(); // get next undo in line, null is returned if there's no undo
  68. TYPE* getNextRedo(); // get next redo in line, null is returned if there's no redo
  69. TYPE& operator[](Int i); // get i-th change
  70. TYPE* addr (Int i); // get i-th change address, null is returned if index is out of range
  71. // create Undo Change
  72. 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.
  73. 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.
  74. T1(CHANGE) Undo& replaceClass();
  75. };
  76. /******************************************************************************/
  77. } // namespace
  78. /******************************************************************************/
  79. inline Int Elms(C Edit::_Undo &undo) {return undo.changes();}
  80. /******************************************************************************/