123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229 |
- /*
- * 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
|