Undo.h 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. /*
  2. * Undo.h
  3. * ------
  4. * Purpose: Editor undo buffer functionality.
  5. * Notes : (currently none)
  6. * Authors: Olivier Lapicque
  7. * OpenMPT Devs
  8. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  9. */
  10. #pragma once
  11. #include "openmpt/all/BuildSettings.hpp"
  12. #include "../soundlib/ModChannel.h"
  13. #include "../soundlib/modcommand.h"
  14. OPENMPT_NAMESPACE_BEGIN
  15. class CModDoc;
  16. struct ModSample;
  17. #define MAX_UNDO_LEVEL 100000 // 100,000 undo steps for each undo type!
  18. /////////////////////////////////////////////////////////////////////////////////////////
  19. // Pattern Undo
  20. class CPatternUndo
  21. {
  22. protected:
  23. static constexpr auto DELETE_PATTERN = PATTERNINDEX_INVALID;
  24. struct UndoInfo
  25. {
  26. std::vector<ModChannelSettings> channelInfo; // Optional old channel information (pan / volume / etc.)
  27. std::vector<ModCommand> content; // Rescued pattern content
  28. const char *description; // Name of this undo action
  29. ROWINDEX numPatternRows; // Original number of pattern rows (in case of resize, DELETE_PATTERN in case of deletion)
  30. ROWINDEX firstRow, numRows;
  31. PATTERNINDEX pattern;
  32. CHANNELINDEX firstChannel, numChannels;
  33. bool linkToPrevious; // This undo information is linked with the previous undo information
  34. bool OnlyChannelSettings() const noexcept
  35. {
  36. return !channelInfo.empty() && numRows < 1 && !linkToPrevious;
  37. }
  38. };
  39. using undobuf_t = std::vector<UndoInfo>;
  40. undobuf_t UndoBuffer;
  41. undobuf_t RedoBuffer;
  42. CModDoc &modDoc;
  43. // Pattern undo helper functions
  44. PATTERNINDEX Undo(undobuf_t &fromBuf, undobuf_t &toBuf, bool linkedFromPrevious);
  45. bool PrepareBuffer(undobuf_t &buffer, PATTERNINDEX pattern, CHANNELINDEX firstChn, ROWINDEX firstRow, CHANNELINDEX numChns, ROWINDEX numRows, const char *description, bool linkToPrevious, bool storeChannelInfo) const;
  46. static CString GetName(const undobuf_t &buffer);
  47. static void RearrangePatterns(undobuf_t &buffer, const std::vector<PATTERNINDEX> &newIndex);
  48. public:
  49. // Removes all undo steps from the buffer.
  50. void ClearUndo();
  51. // Adds a new action to the undo buffer.
  52. bool PrepareUndo(PATTERNINDEX pattern, CHANNELINDEX firstChn, ROWINDEX firstRow, CHANNELINDEX numChns, ROWINDEX numRows, const char *description, bool linkToPrevious = false, bool storeChannelInfo = false);
  53. // Adds a new action only affecting channel data to the undo buffer.
  54. bool PrepareChannelUndo(CHANNELINDEX firstChn, CHANNELINDEX numChns, const char *description);
  55. // Undoes the most recent action.
  56. PATTERNINDEX Undo();
  57. // Redoes the most recent action.
  58. PATTERNINDEX Redo();
  59. // Returns true if any actions can currently be undone.
  60. bool CanUndo() const { return !UndoBuffer.empty(); }
  61. // Returns true if any actions can currently be redone.
  62. bool CanRedo() const { return !RedoBuffer.empty(); }
  63. // Returns true if a channel-specific action (no pattern data) can currently be undone.
  64. bool CanUndoChannelSettings() const { return !UndoBuffer.empty() && UndoBuffer.back().OnlyChannelSettings(); }
  65. // Returns true if a channel-specific action (no pattern data) actions can currently be redone.
  66. bool CanRedoChannelSettings() const { return !RedoBuffer.empty() && RedoBuffer.back().OnlyChannelSettings(); }
  67. // Remove the latest added undo step from the undo buffer
  68. void RemoveLastUndoStep();
  69. // Get name of next undo item
  70. CString GetUndoName() const { return GetName(UndoBuffer); }
  71. // Get name of next redo item
  72. CString GetRedoName() const { return GetName(RedoBuffer); }
  73. // Adjust undo buffers for rearranged patterns
  74. void RearrangePatterns(const std::vector<PATTERNINDEX> &newIndex);
  75. CPatternUndo(CModDoc &parent) : modDoc(parent) { }
  76. };
  77. /////////////////////////////////////////////////////////////////////////////////////////
  78. // Sample Undo
  79. // We will differentiate between different types of undo actions so that we don't have to copy the whole sample everytime.
  80. enum sampleUndoTypes
  81. {
  82. sundo_none, // no changes to sample itself, e.g. loop point update
  83. sundo_update, // silence, amplify, normalize, dc offset - update complete sample section
  84. sundo_delete, // delete part of the sample
  85. sundo_invert, // invert sample phase, apply again to undo
  86. sundo_reverse, // reverse sample, ditto
  87. sundo_unsign, // unsign sample, ditto
  88. sundo_insert, // insert data, delete inserted data to undo
  89. sundo_replace, // replace complete sample (16->8Bit, up/downsample, downmix to mono, pitch shifting / time stretching, trimming, pasting)
  90. };
  91. class CSampleUndo
  92. {
  93. protected:
  94. struct UndoInfo
  95. {
  96. ModSample OldSample;
  97. mpt::charbuf<MAX_SAMPLENAME> oldName;
  98. void *samplePtr = nullptr;
  99. const char *description = nullptr;
  100. SmpLength changeStart = 0, changeEnd = 0;
  101. sampleUndoTypes changeType = sundo_none;
  102. };
  103. using undobuf_t = std::vector<std::vector<UndoInfo>>;
  104. undobuf_t UndoBuffer;
  105. undobuf_t RedoBuffer;
  106. CModDoc &modDoc;
  107. // Sample undo helper functions
  108. void ClearUndo(undobuf_t &buffer, const SAMPLEINDEX smp);
  109. void DeleteStep(undobuf_t &buffer, const SAMPLEINDEX smp, const size_t step);
  110. bool SampleBufferExists(const undobuf_t &buffer, const SAMPLEINDEX smp) const;
  111. void RestrictBufferSize(undobuf_t &buffer, size_t &capacity);
  112. size_t GetBufferCapacity(const undobuf_t &buffer) const;
  113. void RearrangeSamples(undobuf_t &buffer, const std::vector<SAMPLEINDEX> &newIndex);
  114. bool PrepareBuffer(undobuf_t &buffer, const SAMPLEINDEX smp, sampleUndoTypes changeType, const char *description, SmpLength changeStart, SmpLength changeEnd);
  115. bool Undo(undobuf_t &fromBuf, undobuf_t &toBuf, const SAMPLEINDEX smp);
  116. public:
  117. // Sample undo functions
  118. void ClearUndo();
  119. void ClearUndo(const SAMPLEINDEX smp) { ClearUndo(UndoBuffer, smp); ClearUndo(RedoBuffer, smp); }
  120. bool PrepareUndo(const SAMPLEINDEX smp, sampleUndoTypes changeType, const char *description, SmpLength changeStart = 0, SmpLength changeEnd = 0);
  121. bool Undo(const SAMPLEINDEX smp);
  122. bool Redo(const SAMPLEINDEX smp);
  123. bool CanUndo(const SAMPLEINDEX smp) const { return SampleBufferExists(UndoBuffer, smp) && !UndoBuffer[smp - 1].empty(); }
  124. bool CanRedo(const SAMPLEINDEX smp) const { return SampleBufferExists(RedoBuffer, smp) && !RedoBuffer[smp - 1].empty(); }
  125. void RemoveLastUndoStep(const SAMPLEINDEX smp);
  126. const char *GetUndoName(const SAMPLEINDEX smp) const;
  127. const char *GetRedoName(const SAMPLEINDEX smp) const;
  128. void RestrictBufferSize();
  129. void RearrangeSamples(const std::vector<SAMPLEINDEX> &newIndex) { RearrangeSamples(UndoBuffer, newIndex); RearrangeSamples(RedoBuffer, newIndex); }
  130. CSampleUndo(CModDoc &parent) : modDoc(parent) { }
  131. ~CSampleUndo()
  132. {
  133. ClearUndo();
  134. };
  135. };
  136. /////////////////////////////////////////////////////////////////////////////////////////
  137. // Instrument Undo
  138. class CInstrumentUndo
  139. {
  140. protected:
  141. struct UndoInfo
  142. {
  143. ModInstrument instr;
  144. const char *description = nullptr;
  145. EnvelopeType editedEnvelope = ENV_MAXTYPES;
  146. };
  147. using undobuf_t = std::vector<std::vector<UndoInfo>>;
  148. undobuf_t UndoBuffer;
  149. undobuf_t RedoBuffer;
  150. CModDoc &modDoc;
  151. // Instrument undo helper functions
  152. void ClearUndo(undobuf_t &buffer, const INSTRUMENTINDEX ins);
  153. void DeleteStep(undobuf_t &buffer, const INSTRUMENTINDEX ins, const size_t step);
  154. bool InstrumentBufferExists(const undobuf_t &buffer, const INSTRUMENTINDEX ins) const;
  155. void RearrangeInstruments(undobuf_t &buffer, const std::vector<INSTRUMENTINDEX> &newIndex);
  156. void RearrangeSamples(undobuf_t &buffer, const INSTRUMENTINDEX ins, std::vector<SAMPLEINDEX> &newIndex);
  157. bool PrepareBuffer(undobuf_t &buffer, const INSTRUMENTINDEX ins, const char *description, EnvelopeType envType);
  158. bool Undo(undobuf_t &fromBuf, undobuf_t &toBuf, const INSTRUMENTINDEX ins);
  159. public:
  160. // Instrument undo functions
  161. void ClearUndo();
  162. void ClearUndo(const INSTRUMENTINDEX ins) { ClearUndo(UndoBuffer, ins); ClearUndo(RedoBuffer, ins); }
  163. bool PrepareUndo(const INSTRUMENTINDEX ins, const char *description, EnvelopeType envType = ENV_MAXTYPES);
  164. bool Undo(const INSTRUMENTINDEX ins);
  165. bool Redo(const INSTRUMENTINDEX ins);
  166. bool CanUndo(const INSTRUMENTINDEX ins) const { return InstrumentBufferExists(UndoBuffer, ins) && !UndoBuffer[ins - 1].empty(); }
  167. bool CanRedo(const INSTRUMENTINDEX ins) const { return InstrumentBufferExists(RedoBuffer, ins) && !RedoBuffer[ins - 1].empty(); }
  168. void RemoveLastUndoStep(const INSTRUMENTINDEX ins);
  169. const char *GetUndoName(const INSTRUMENTINDEX ins) const;
  170. const char *GetRedoName(const INSTRUMENTINDEX ins) const;
  171. void RearrangeInstruments(const std::vector<INSTRUMENTINDEX> &newIndex) { RearrangeInstruments(UndoBuffer, newIndex); RearrangeInstruments(RedoBuffer, newIndex); }
  172. void RearrangeSamples(const INSTRUMENTINDEX ins, std::vector<SAMPLEINDEX> &newIndex) { RearrangeSamples(UndoBuffer, ins, newIndex); RearrangeSamples(RedoBuffer, ins, newIndex); }
  173. CInstrumentUndo(CModDoc &parent) : modDoc(parent) { }
  174. ~CInstrumentUndo()
  175. {
  176. ClearUndo();
  177. };
  178. };
  179. OPENMPT_NAMESPACE_END