Revert "add undo to instrument editor (check for diffs on the current DivInstrument in insEdit, record them in a stack)"

This reverts commit 5c9fd69ac1.
This commit is contained in:
tildearrow 2024-08-19 02:49:14 -05:00
parent f1de0bf2b7
commit d3af810462
8 changed files with 55 additions and 307 deletions

View file

@ -17,7 +17,6 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <cassert>
#include "dataErrors.h"
#include "engine.h"
#include "instrument.h"
@ -364,144 +363,6 @@ void DivInstrument::writeFeatureFM(SafeWriter* w, bool fui) {
FEATURE_END;
}
void MemPatch::clear() {
data = nullptr;
offset = 0;
size = 0;
}
bool MemPatch::calcDiff(const void* pre, const void* post, size_t inputSize) {
bool diffValid = false;
size_t firstDiff = 0;
size_t lastDiff = 0;
const uint8_t* preBytes = (const uint8_t*)pre;
const uint8_t* postBytes = (const uint8_t*)post;
for (size_t ii = 0; ii < inputSize; ++ii) {
if (preBytes[ii] != postBytes[ii]) {
lastDiff=ii;
firstDiff=diffValid ? firstDiff : ii;
diffValid=true;
}
}
if (diffValid) {
offset = firstDiff;
size = lastDiff - firstDiff + 1;
data = new uint8_t[size];
// the diff is to make pre into post (MemPatch is general, not specific to
// undo), so copy from postBytes
memcpy(data, postBytes + offset, size);
}
return diffValid;
}
void MemPatch::applyAndReverse(void* target, size_t targetSize) {
if (size == 0) { return; }
assert(offset + size <= targetSize);
uint8_t* targetBytes = (uint8_t*)target;
// swap this->data and its segment on target
for (size_t ii = 0; ii < size; ++ii) {
uint8_t tmp = targetBytes[offset + ii];
targetBytes[offset + ii] = data[ii];
data[ii] = tmp;
}
}
void DivInstrumentUndoStep::clear() {
podPatch.clear();
name.clear();
}
void DivInstrumentUndoStep::applyAndReverse(DivInstrument* target) {
if (nameValid) {
name.swap(target->name);
}
podPatch.applyAndReverse((DivInstrumentPOD*)target, sizeof(DivInstrumentPOD));
}
bool DivInstrumentUndoStep::makeUndoPatch(size_t processTime_, const DivInstrument* pre, const DivInstrument* post) {
processTime = processTime_;
// create the patch that will make post into pre
podPatch.calcDiff((const DivInstrumentPOD*)post, (const DivInstrumentPOD*)pre, sizeof(DivInstrumentPOD));
if (pre->name.compare(post->name) != 0) {
nameValid = true;
name = pre->name;
}
return nameValid || podPatch.isValid();
}
void DivInstrument::recordUndoStepIfChanged(size_t processTime, const DivInstrument* old) {
DivInstrumentUndoStep step;
// generate a patch to go back to old
if (step.makeUndoPatch(processTime, old, this)) {
// make room
if (undoHist.size() >= undoHist.capacity()) {
DivInstrumentUndoStep* step = undoHist.front();
delete step;
undoHist.pop_front();
}
// clear redo
while (!redoHist.empty()) {
delete redoHist.back();
redoHist.pop_back();
}
DivInstrumentUndoStep* stepPtr = new DivInstrumentUndoStep;
*stepPtr = step;
step.clear(); // don't let it delete the data ptr that's been copied!
undoHist.push_back(stepPtr);
logI("DivInstrument::undoHist push (%u off, %u size)", stepPtr->podPatch.offset, stepPtr->podPatch.size);
}
}
int DivInstrument::undo() {
if (undoHist.empty()) { return 0; }
DivInstrumentUndoStep* step = undoHist.back();
undoHist.pop_back();
logI("DivInstrument::undo (%u off, %u size)", step->podPatch.offset, step->podPatch.size);
step->applyAndReverse(this);
// make room
if (redoHist.size() >= redoHist.capacity()) {
DivInstrumentUndoStep* step = redoHist.front();
delete step;
redoHist.pop_front();
}
redoHist.push_back(step);
return 1;
}
int DivInstrument::redo() {
if (redoHist.empty()) { return 0; }
DivInstrumentUndoStep* step = redoHist.back();
redoHist.pop_back();
logI("DivInstrument::redo (%u off, %u size)", step->podPatch.offset, step->podPatch.size);
step->applyAndReverse(this);
// make room
if (undoHist.size() >= undoHist.capacity()) {
DivInstrumentUndoStep* step = undoHist.front();
delete step;
undoHist.pop_front();
}
undoHist.push_back(step);
return 1;
}
void DivInstrument::writeMacro(SafeWriter* w, const DivInstrumentMacro& m) {
if (!m.len) return;

View file

@ -23,10 +23,8 @@
#include "dataErrors.h"
#include "../ta-utils.h"
#include "../pch.h"
#include "../fixedQueue.h"
struct DivSong;
struct DivInstrument;
// NOTICE!
// before adding new instrument types to this struct, please ask me first.
@ -862,7 +860,8 @@ struct DivInstrumentSID2 {
noiseMode(0) {}
};
struct DivInstrumentPOD {
struct DivInstrument {
String name;
DivInstrumentType type;
DivInstrumentFM fm;
DivInstrumentSTD std;
@ -881,63 +880,6 @@ struct DivInstrumentPOD {
DivInstrumentPowerNoise powernoise;
DivInstrumentSID2 sid2;
DivInstrumentPOD() :
type(DIV_INS_FM) {
}
};
struct MemPatch {
MemPatch() :
data(nullptr)
, offset(0)
, size(0) {
}
~MemPatch() {
if (data) {
free(data);
}
}
void clear();
bool calcDiff(const void* pre, const void* post, size_t size);
void applyAndReverse(void* target, size_t inputSize);
bool isValid() const { return size > 0; }
uint8_t* data;
size_t offset;
size_t size;
};
struct DivInstrumentUndoStep {
DivInstrumentUndoStep() :
name(""),
nameValid(false),
processTime(0) {
}
MemPatch podPatch;
String name;
bool nameValid;
size_t processTime;
void clear();
void applyAndReverse(DivInstrument* target);
bool makeUndoPatch(size_t processTime_, const DivInstrument* pre, const DivInstrument* post);
};
struct DivInstrument : DivInstrumentPOD {
String name;
/**
* undo stuff
*/
FixedQueue<DivInstrumentUndoStep*, 128> undoHist;
FixedQueue<DivInstrumentUndoStep*, 128> redoHist;
void recordUndoStepIfChanged(size_t processTime, const DivInstrument* old);
int undo();
int redo();
/**
* these are internal functions.
*/
@ -1022,11 +964,9 @@ struct DivInstrument : DivInstrumentPOD {
* @return whether it was successful.
*/
bool saveDMP(const char* path);
DivInstrument() :
name("") {
// clear and construct DivInstrumentPOD so it doesn't have any garbage in the padding
memset((DivInstrumentPOD*)this, 0, sizeof(DivInstrumentPOD));
new ((DivInstrumentPOD*)this) DivInstrumentPOD;
DivInstrument():
name(""),
type(DIV_INS_FM) {
}
};
#endif

View file

@ -24,7 +24,7 @@
#include "ta-log.h"
template<typename T, size_t items> struct FixedQueue {
size_t readPos, curSize;
size_t readPos, writePos;
T data[items];
T& operator[](size_t pos);
@ -41,21 +41,17 @@ template<typename T, size_t items> struct FixedQueue {
bool push_back(const T& item);
void clear();
bool empty();
size_t writePos();
size_t size();
size_t capacity();
FixedQueue():
readPos(0),
curSize(0) {}
writePos(0) {}
};
template <typename T, size_t items> T& FixedQueue<T,items>::operator[](size_t pos) {
if (pos>=curSize) {
if (pos>=size()) {
logW("accessing invalid position. bug!");
}
size_t idx=readPos+pos;
if (idx>=items) idx-=items;
return data[idx];
return data[(readPos+pos)%items];
}
template <typename T, size_t items> T& FixedQueue<T,items>::front() {
@ -63,13 +59,12 @@ template <typename T, size_t items> T& FixedQueue<T,items>::front() {
}
template <typename T, size_t items> T& FixedQueue<T,items>::back() {
if (curSize==0) return data[0];
size_t idx=readPos+curSize-1;
if (idx>=items) idx-=items;
return data[idx];
if (writePos==0) return data[items-1];
return data[writePos-1];
}
template <typename T, size_t items> bool FixedQueue<T,items>::erase(size_t pos) {
size_t curSize=size();
if (pos>=curSize) {
logW("accessing invalid position. bug!");
return false;
@ -89,56 +84,72 @@ template <typename T, size_t items> bool FixedQueue<T,items>::erase(size_t pos)
p1++;
}
curSize--;
if (writePos>0) {
writePos--;
} else {
writePos=items-1;
}
return true;
}
template <typename T, size_t items> bool FixedQueue<T,items>::pop() {
if (curSize==0) return false;
curSize--;
if (readPos==writePos) return false;
if (++readPos>=items) readPos=0;
return true;
}
template <typename T, size_t items> bool FixedQueue<T,items>::push(const T& item) {
if (curSize==items) {
if (writePos==(readPos-1)) {
//logW("queue overflow!");
return false;
}
size_t idx=readPos+curSize;
if (idx>=items) { idx-=items; }
data[idx]=item;
curSize++;
if (writePos==items-1 && readPos==0) {
//logW("queue overflow!");
return false;
}
data[writePos]=item;
if (++writePos>=items) writePos=0;
return true;
}
template <typename T, size_t items> bool FixedQueue<T,items>::pop_front() {
if (curSize==0) return false;
if (readPos==writePos) return false;
if (++readPos>=items) readPos=0;
curSize--;
return true;
}
template <typename T, size_t items> bool FixedQueue<T,items>::push_back(const T& item) {
if (curSize==items) {
if (writePos==(readPos-1)) {
//logW("queue overflow!");
return false;
}
size_t idx=readPos+curSize;
if (idx>=items) { idx-=items; }
data[idx]=item;
curSize++;
if (writePos==items-1 && readPos==0) {
//logW("queue overflow!");
return false;
}
data[writePos]=item;
if (++writePos>=items) writePos=0;
return true;
}
template <typename T, size_t items> bool FixedQueue<T,items>::pop_back() {
if (curSize==0) return false;
curSize--;
if (readPos==writePos) return false;
if (writePos>0) {
writePos--;
} else {
writePos=items-1;
}
return true;
}
template <typename T, size_t items> bool FixedQueue<T,items>::push_front(const T& item) {
if (curSize==items) {
//logW("queue overflow!");
if (readPos==(writePos+1)) {
//logW("stack overflow!");
return false;
}
if (readPos==0 && writePos==items-1) {
//logW("stack overflow!");
return false;
}
if (readPos>0) {
@ -147,31 +158,23 @@ template <typename T, size_t items> bool FixedQueue<T,items>::push_front(const T
readPos=items-1;
}
data[readPos]=item;
curSize++;
return true;
}
template <typename T, size_t items> void FixedQueue<T,items>::clear() {
readPos=0;
curSize=0;
writePos=0;
}
template <typename T, size_t items> bool FixedQueue<T,items>::empty() {
return curSize==0;
}
template <typename T, size_t items> size_t FixedQueue<T,items>::writePos() {
size_t idx=readPos+curSize;
if (idx>=items) { idx-=items; }
return idx;
return (readPos==writePos);
}
template <typename T, size_t items> size_t FixedQueue<T,items>::size() {
return curSize;
}
template <typename T, size_t items> size_t FixedQueue<T,items>::capacity() {
return items;
if (readPos>writePos) {
return items+writePos-readPos;
}
return writePos-readPos;
}
#endif

View file

@ -605,7 +605,7 @@ void FurnaceGUI::drawDebug() {
}
if (ImGui::TreeNode("Recent Files")) {
ImGui::Text("Items: %d - Max: %d",(int)recentFile.size(),settings.maxRecentFile);
ImGui::Text("readPos: %d - writePos: %d",(int)recentFile.readPos,(int)recentFile.writePos());
ImGui::Text("readPos: %d - writePos: %d",(int)recentFile.readPos,(int)recentFile.writePos);
ImGui::Indent();
for (size_t i=0; i<recentFile.size(); i++) {
ImGui::Text("%d: %s",(int)i,recentFile[i].c_str());

View file

@ -73,8 +73,6 @@ void FurnaceGUI::doAction(int what) {
case GUI_ACTION_UNDO:
if (curWindow==GUI_WINDOW_SAMPLE_EDIT) {
doUndoSample();
} else if (curWindow==GUI_WINDOW_INS_EDIT) {
doUndoInstrument();
} else {
doUndo();
}
@ -82,8 +80,6 @@ void FurnaceGUI::doAction(int what) {
case GUI_ACTION_REDO:
if (curWindow==GUI_WINDOW_SAMPLE_EDIT) {
doRedoSample();
} else if (curWindow==GUI_WINDOW_INS_EDIT) {
doRedoInstrument();
} else {
doRedo();
}

View file

@ -8310,7 +8310,6 @@ FurnaceGUI::FurnaceGUI():
localeRequiresChineseTrad(false),
localeRequiresKorean(false),
prevInsData(NULL),
cachedCurInsPtr(NULL),
pendingLayoutImport(NULL),
pendingLayoutImportLen(0),
pendingLayoutImportStep(0),

View file

@ -2256,8 +2256,6 @@ class FurnaceGUI {
std::vector<ImWchar> localeExtraRanges;
DivInstrument* prevInsData;
DivInstrument cachedCurIns;
DivInstrument* cachedCurInsPtr;
unsigned char* pendingLayoutImport;
size_t pendingLayoutImportLen;
@ -2924,9 +2922,6 @@ class FurnaceGUI {
void doUndoSample();
void doRedoSample();
void doUndoInstrument();
void doRedoInstrument();
void play(int row=0);
void setOrder(unsigned char order, bool forced=false);
void stop();

View file

@ -5250,7 +5250,6 @@ void FurnaceGUI::drawInsEdit() {
ImGui::SetNextWindowSizeConstraints(ImVec2(440.0f*dpiScale,400.0f*dpiScale),ImVec2(canvasW,canvasH));
}
if (ImGui::Begin("Instrument Editor",&insEditOpen,globalWinFlags|(settings.allowEditDocking?0:ImGuiWindowFlags_NoDocking),_("Instrument Editor"))) {
DivInstrument* ins=nullptr;
if (curIns==-2) {
ImGui::SetCursorPosY(ImGui::GetCursorPosY()+(ImGui::GetContentRegionAvail().y-ImGui::GetFrameHeightWithSpacing()+ImGui::GetStyle().ItemSpacing.y)*0.5f);
CENTER_TEXT(_("waiting..."));
@ -5278,7 +5277,6 @@ void FurnaceGUI::drawInsEdit() {
curIns=i;
wavePreviewInit=true;
updateFMPreview=true;
ins = e->song.ins[curIns];
}
}
ImGui::EndCombo();
@ -5301,7 +5299,7 @@ void FurnaceGUI::drawInsEdit() {
ImGui::EndTable();
}
} else {
ins=e->song.ins[curIns];
DivInstrument* ins=e->song.ins[curIns];
if (updateFMPreview) {
renderFMPreview(ins);
updateFMPreview=false;
@ -7740,51 +7738,7 @@ void FurnaceGUI::drawInsEdit() {
ImGui::EndPopup();
}
if (ins) {
bool insChanged = ins != cachedCurInsPtr;
bool delayDiff = ImGui::IsMouseDown(ImGuiMouseButton_Left) || ImGui::IsMouseDown(ImGuiMouseButton_Right) || ImGui::GetIO().WantCaptureKeyboard;
// check against the last cached to see if diff -- note that modifications to instruments happen outside
// drawInsEdit (e.g. cursor inputs are processed and can directly modify macro data)
if (!insChanged && !delayDiff) {
ins->recordUndoStepIfChanged(e->processTime, &cachedCurIns);
}
if (insChanged || !delayDiff) {
cachedCurIns = *ins;
}
cachedCurInsPtr = ins;
} else {
cachedCurInsPtr = nullptr;
}
}
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_INS_EDIT;
ImGui::End();
}
void FurnaceGUI::doUndoInstrument() {
if (!insEditOpen) return;
if (curIns<0 || curIns>=(int)e->song.ins.size()) return;
DivInstrument* ins=e->song.ins[curIns];
// is locking the engine necessary? copied from doUndoSample
e->lockEngine([this,ins]() {
ins->undo();
cachedCurInsPtr=ins;
cachedCurIns=*ins;
});
}
void FurnaceGUI::doRedoInstrument() {
if (!insEditOpen) return;
if (curIns<0 || curIns>=(int)e->song.ins.size()) return;
DivInstrument* ins=e->song.ins[curIns];
// is locking the engine necessary? copied from doRedoSample
e->lockEngine([this,ins]() {
ins->redo();
cachedCurInsPtr=ins;
cachedCurIns=*ins;
});
}