aboutsummaryrefslogtreecommitdiff
path: root/Src/external_dependencies/openmpt-trunk/mptrack/Undo.h
diff options
context:
space:
mode:
Diffstat (limited to 'Src/external_dependencies/openmpt-trunk/mptrack/Undo.h')
-rw-r--r--Src/external_dependencies/openmpt-trunk/mptrack/Undo.h229
1 files changed, 229 insertions, 0 deletions
diff --git a/Src/external_dependencies/openmpt-trunk/mptrack/Undo.h b/Src/external_dependencies/openmpt-trunk/mptrack/Undo.h
new file mode 100644
index 00000000..0ff30162
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/mptrack/Undo.h
@@ -0,0 +1,229 @@
+/*
+ * Undo.h
+ * ------
+ * Purpose: Editor undo buffer functionality.
+ * Notes : (currently none)
+ * Authors: Olivier Lapicque
+ * OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+
+#pragma once
+
+#include "openmpt/all/BuildSettings.hpp"
+
+#include "../soundlib/ModChannel.h"
+#include "../soundlib/modcommand.h"
+
+OPENMPT_NAMESPACE_BEGIN
+
+class CModDoc;
+struct ModSample;
+
+#define MAX_UNDO_LEVEL 100000 // 100,000 undo steps for each undo type!
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Pattern Undo
+
+
+class CPatternUndo
+{
+protected:
+ static constexpr auto DELETE_PATTERN = PATTERNINDEX_INVALID;
+
+ struct UndoInfo
+ {
+ std::vector<ModChannelSettings> channelInfo; // Optional old channel information (pan / volume / etc.)
+ std::vector<ModCommand> content; // Rescued pattern content
+ const char *description; // Name of this undo action
+ ROWINDEX numPatternRows; // Original number of pattern rows (in case of resize, DELETE_PATTERN in case of deletion)
+ ROWINDEX firstRow, numRows;
+ PATTERNINDEX pattern;
+ CHANNELINDEX firstChannel, numChannels;
+ bool linkToPrevious; // This undo information is linked with the previous undo information
+
+ bool OnlyChannelSettings() const noexcept
+ {
+ return !channelInfo.empty() && numRows < 1 && !linkToPrevious;
+ }
+ };
+
+ using undobuf_t = std::vector<UndoInfo>;
+
+ undobuf_t UndoBuffer;
+ undobuf_t RedoBuffer;
+ CModDoc &modDoc;
+
+ // Pattern undo helper functions
+ PATTERNINDEX Undo(undobuf_t &fromBuf, undobuf_t &toBuf, bool linkedFromPrevious);
+
+ bool PrepareBuffer(undobuf_t &buffer, PATTERNINDEX pattern, CHANNELINDEX firstChn, ROWINDEX firstRow, CHANNELINDEX numChns, ROWINDEX numRows, const char *description, bool linkToPrevious, bool storeChannelInfo) const;
+
+ static CString GetName(const undobuf_t &buffer);
+ static void RearrangePatterns(undobuf_t &buffer, const std::vector<PATTERNINDEX> &newIndex);
+
+public:
+
+ // Removes all undo steps from the buffer.
+ void ClearUndo();
+ // Adds a new action to the undo buffer.
+ bool PrepareUndo(PATTERNINDEX pattern, CHANNELINDEX firstChn, ROWINDEX firstRow, CHANNELINDEX numChns, ROWINDEX numRows, const char *description, bool linkToPrevious = false, bool storeChannelInfo = false);
+ // Adds a new action only affecting channel data to the undo buffer.
+ bool PrepareChannelUndo(CHANNELINDEX firstChn, CHANNELINDEX numChns, const char *description);
+ // Undoes the most recent action.
+ PATTERNINDEX Undo();
+ // Redoes the most recent action.
+ PATTERNINDEX Redo();
+ // Returns true if any actions can currently be undone.
+ bool CanUndo() const { return !UndoBuffer.empty(); }
+ // Returns true if any actions can currently be redone.
+ bool CanRedo() const { return !RedoBuffer.empty(); }
+ // Returns true if a channel-specific action (no pattern data) can currently be undone.
+ bool CanUndoChannelSettings() const { return !UndoBuffer.empty() && UndoBuffer.back().OnlyChannelSettings(); }
+ // Returns true if a channel-specific action (no pattern data) actions can currently be redone.
+ bool CanRedoChannelSettings() const { return !RedoBuffer.empty() && RedoBuffer.back().OnlyChannelSettings(); }
+ // Remove the latest added undo step from the undo buffer
+ void RemoveLastUndoStep();
+ // Get name of next undo item
+ CString GetUndoName() const { return GetName(UndoBuffer); }
+ // Get name of next redo item
+ CString GetRedoName() const { return GetName(RedoBuffer); }
+ // Adjust undo buffers for rearranged patterns
+ void RearrangePatterns(const std::vector<PATTERNINDEX> &newIndex);
+
+ CPatternUndo(CModDoc &parent) : modDoc(parent) { }
+};
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Sample Undo
+
+// We will differentiate between different types of undo actions so that we don't have to copy the whole sample everytime.
+enum sampleUndoTypes
+{
+ sundo_none, // no changes to sample itself, e.g. loop point update
+ sundo_update, // silence, amplify, normalize, dc offset - update complete sample section
+ sundo_delete, // delete part of the sample
+ sundo_invert, // invert sample phase, apply again to undo
+ sundo_reverse, // reverse sample, ditto
+ sundo_unsign, // unsign sample, ditto
+ sundo_insert, // insert data, delete inserted data to undo
+ sundo_replace, // replace complete sample (16->8Bit, up/downsample, downmix to mono, pitch shifting / time stretching, trimming, pasting)
+};
+
+
+class CSampleUndo
+{
+protected:
+
+ struct UndoInfo
+ {
+ ModSample OldSample;
+ mpt::charbuf<MAX_SAMPLENAME> oldName;
+ void *samplePtr = nullptr;
+ const char *description = nullptr;
+ SmpLength changeStart = 0, changeEnd = 0;
+ sampleUndoTypes changeType = sundo_none;
+ };
+
+ using undobuf_t = std::vector<std::vector<UndoInfo>>;
+ undobuf_t UndoBuffer;
+ undobuf_t RedoBuffer;
+
+ CModDoc &modDoc;
+
+ // Sample undo helper functions
+ void ClearUndo(undobuf_t &buffer, const SAMPLEINDEX smp);
+ void DeleteStep(undobuf_t &buffer, const SAMPLEINDEX smp, const size_t step);
+ bool SampleBufferExists(const undobuf_t &buffer, const SAMPLEINDEX smp) const;
+ void RestrictBufferSize(undobuf_t &buffer, size_t &capacity);
+ size_t GetBufferCapacity(const undobuf_t &buffer) const;
+ void RearrangeSamples(undobuf_t &buffer, const std::vector<SAMPLEINDEX> &newIndex);
+
+ bool PrepareBuffer(undobuf_t &buffer, const SAMPLEINDEX smp, sampleUndoTypes changeType, const char *description, SmpLength changeStart, SmpLength changeEnd);
+ bool Undo(undobuf_t &fromBuf, undobuf_t &toBuf, const SAMPLEINDEX smp);
+
+public:
+
+ // Sample undo functions
+ void ClearUndo();
+ void ClearUndo(const SAMPLEINDEX smp) { ClearUndo(UndoBuffer, smp); ClearUndo(RedoBuffer, smp); }
+ bool PrepareUndo(const SAMPLEINDEX smp, sampleUndoTypes changeType, const char *description, SmpLength changeStart = 0, SmpLength changeEnd = 0);
+ bool Undo(const SAMPLEINDEX smp);
+ bool Redo(const SAMPLEINDEX smp);
+ bool CanUndo(const SAMPLEINDEX smp) const { return SampleBufferExists(UndoBuffer, smp) && !UndoBuffer[smp - 1].empty(); }
+ bool CanRedo(const SAMPLEINDEX smp) const { return SampleBufferExists(RedoBuffer, smp) && !RedoBuffer[smp - 1].empty(); }
+ void RemoveLastUndoStep(const SAMPLEINDEX smp);
+ const char *GetUndoName(const SAMPLEINDEX smp) const;
+ const char *GetRedoName(const SAMPLEINDEX smp) const;
+ void RestrictBufferSize();
+ void RearrangeSamples(const std::vector<SAMPLEINDEX> &newIndex) { RearrangeSamples(UndoBuffer, newIndex); RearrangeSamples(RedoBuffer, newIndex); }
+
+ CSampleUndo(CModDoc &parent) : modDoc(parent) { }
+
+ ~CSampleUndo()
+ {
+ ClearUndo();
+ };
+
+};
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Instrument Undo
+
+
+class CInstrumentUndo
+{
+protected:
+
+ struct UndoInfo
+ {
+ ModInstrument instr;
+ const char *description = nullptr;
+ EnvelopeType editedEnvelope = ENV_MAXTYPES;
+ };
+
+ using undobuf_t = std::vector<std::vector<UndoInfo>>;
+ undobuf_t UndoBuffer;
+ undobuf_t RedoBuffer;
+
+ CModDoc &modDoc;
+
+ // Instrument undo helper functions
+ void ClearUndo(undobuf_t &buffer, const INSTRUMENTINDEX ins);
+ void DeleteStep(undobuf_t &buffer, const INSTRUMENTINDEX ins, const size_t step);
+ bool InstrumentBufferExists(const undobuf_t &buffer, const INSTRUMENTINDEX ins) const;
+ void RearrangeInstruments(undobuf_t &buffer, const std::vector<INSTRUMENTINDEX> &newIndex);
+ void RearrangeSamples(undobuf_t &buffer, const INSTRUMENTINDEX ins, std::vector<SAMPLEINDEX> &newIndex);
+
+ bool PrepareBuffer(undobuf_t &buffer, const INSTRUMENTINDEX ins, const char *description, EnvelopeType envType);
+ bool Undo(undobuf_t &fromBuf, undobuf_t &toBuf, const INSTRUMENTINDEX ins);
+
+public:
+
+ // Instrument undo functions
+ void ClearUndo();
+ void ClearUndo(const INSTRUMENTINDEX ins) { ClearUndo(UndoBuffer, ins); ClearUndo(RedoBuffer, ins); }
+ bool PrepareUndo(const INSTRUMENTINDEX ins, const char *description, EnvelopeType envType = ENV_MAXTYPES);
+ bool Undo(const INSTRUMENTINDEX ins);
+ bool Redo(const INSTRUMENTINDEX ins);
+ bool CanUndo(const INSTRUMENTINDEX ins) const { return InstrumentBufferExists(UndoBuffer, ins) && !UndoBuffer[ins - 1].empty(); }
+ bool CanRedo(const INSTRUMENTINDEX ins) const { return InstrumentBufferExists(RedoBuffer, ins) && !RedoBuffer[ins - 1].empty(); }
+ void RemoveLastUndoStep(const INSTRUMENTINDEX ins);
+ const char *GetUndoName(const INSTRUMENTINDEX ins) const;
+ const char *GetRedoName(const INSTRUMENTINDEX ins) const;
+ void RearrangeInstruments(const std::vector<INSTRUMENTINDEX> &newIndex) { RearrangeInstruments(UndoBuffer, newIndex); RearrangeInstruments(RedoBuffer, newIndex); }
+ void RearrangeSamples(const INSTRUMENTINDEX ins, std::vector<SAMPLEINDEX> &newIndex) { RearrangeSamples(UndoBuffer, ins, newIndex); RearrangeSamples(RedoBuffer, ins, newIndex); }
+
+ CInstrumentUndo(CModDoc &parent) : modDoc(parent) { }
+
+ ~CInstrumentUndo()
+ {
+ ClearUndo();
+ };
+};
+
+
+OPENMPT_NAMESPACE_END