diff options
Diffstat (limited to 'Src/external_dependencies/openmpt-trunk/mptrack/Undo.h')
-rw-r--r-- | Src/external_dependencies/openmpt-trunk/mptrack/Undo.h | 229 |
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 |