GUI: sample edit undo/redo!
it seems to work but if you find bugs/crashes tell me
This commit is contained in:
parent
f45273c89c
commit
afc701b0b9
|
@ -790,7 +790,7 @@ unsigned int DivSample::getCurBufLen() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
DivSampleHistory* DivSample::prepareUndo(bool data) {
|
||||
DivSampleHistory* DivSample::prepareUndo(bool data, bool doNotPush) {
|
||||
DivSampleHistory* h;
|
||||
if (data) {
|
||||
unsigned char* duplicate;
|
||||
|
@ -804,33 +804,77 @@ DivSampleHistory* DivSample::prepareUndo(bool data) {
|
|||
} else {
|
||||
h=new DivSampleHistory(depth,rate,centerRate,loopStart);
|
||||
}
|
||||
while (!redoHist.empty()) {
|
||||
DivSampleHistory* h=redoHist.front();
|
||||
delete h;
|
||||
redoHist.pop_front();
|
||||
if (!doNotPush) {
|
||||
while (!redoHist.empty()) {
|
||||
DivSampleHistory* h=redoHist.back();
|
||||
delete h;
|
||||
redoHist.pop_back();
|
||||
}
|
||||
if (undoHist.size()>100) undoHist.pop_front();
|
||||
undoHist.push_back(h);
|
||||
}
|
||||
undoHist.push_back(h);
|
||||
return h;
|
||||
}
|
||||
|
||||
#define applyHistory \
|
||||
depth=h->depth; \
|
||||
if (h->hasSample) { \
|
||||
initInternal(h->depth,h->samples); \
|
||||
samples=h->samples; \
|
||||
\
|
||||
if (h->length!=getCurBufLen()) logW("undo buffer length not equal to current buffer length! %d != %d\n",h->length,getCurBufLen()); \
|
||||
\
|
||||
void* buf=getCurBuf(); \
|
||||
\
|
||||
if (buf!=NULL && h->data!=NULL) { \
|
||||
memcpy(buf,h->data,h->length); \
|
||||
} \
|
||||
} \
|
||||
rate=h->rate; \
|
||||
centerRate=h->centerRate; \
|
||||
loopStart=h->loopStart;
|
||||
|
||||
|
||||
int DivSample::undo() {
|
||||
return 0;
|
||||
if (undoHist.empty()) return 0;
|
||||
DivSampleHistory* h=undoHist.back();
|
||||
DivSampleHistory* redo=prepareUndo(h->hasSample,true);
|
||||
|
||||
int ret=h->hasSample?2:1;
|
||||
|
||||
applyHistory;
|
||||
|
||||
redoHist.push_back(redo);
|
||||
delete h;
|
||||
undoHist.pop_back();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int DivSample::redo() {
|
||||
return 0;
|
||||
if (redoHist.empty()) return 0;
|
||||
DivSampleHistory* h=redoHist.back();
|
||||
DivSampleHistory* undo=prepareUndo(h->hasSample,true);
|
||||
|
||||
int ret=h->hasSample?2:1;
|
||||
|
||||
applyHistory;
|
||||
|
||||
undoHist.push_back(undo);
|
||||
delete h;
|
||||
redoHist.pop_back();
|
||||
return ret;
|
||||
}
|
||||
|
||||
DivSample::~DivSample() {
|
||||
while (!undoHist.empty()) {
|
||||
DivSampleHistory* h=undoHist.front();
|
||||
DivSampleHistory* h=undoHist.back();
|
||||
delete h;
|
||||
undoHist.pop_front();
|
||||
undoHist.pop_back();
|
||||
}
|
||||
while (!redoHist.empty()) {
|
||||
DivSampleHistory* h=redoHist.front();
|
||||
DivSampleHistory* h=redoHist.back();
|
||||
delete h;
|
||||
redoHist.pop_front();
|
||||
redoHist.pop_back();
|
||||
}
|
||||
if (data8) delete[] data8;
|
||||
if (data16) delete[] data16;
|
||||
|
|
|
@ -189,9 +189,10 @@ struct DivSample {
|
|||
/**
|
||||
* prepare an undo step for this sample.
|
||||
* @param data whether to include sample data.
|
||||
* @param doNotPush if this is true, don't push the DivSampleHistory to the undo history.
|
||||
* @return the undo step.
|
||||
*/
|
||||
DivSampleHistory* prepareUndo(bool data);
|
||||
DivSampleHistory* prepareUndo(bool data, bool doNotPush=false);
|
||||
|
||||
/**
|
||||
* undo. you may need to call DivEngine::renderSamples afterwards.
|
||||
|
|
|
@ -55,10 +55,18 @@ void FurnaceGUI::doAction(int what) {
|
|||
openFileDialog(GUI_FILE_SAVE);
|
||||
break;
|
||||
case GUI_ACTION_UNDO:
|
||||
doUndo();
|
||||
if (curWindow==GUI_WINDOW_SAMPLE_EDIT) {
|
||||
doUndoSample();
|
||||
} else {
|
||||
doUndo();
|
||||
}
|
||||
break;
|
||||
case GUI_ACTION_REDO:
|
||||
doRedo();
|
||||
if (curWindow==GUI_WINDOW_SAMPLE_EDIT) {
|
||||
doRedoSample();
|
||||
} else {
|
||||
doRedo();
|
||||
}
|
||||
break;
|
||||
case GUI_ACTION_PLAY_TOGGLE:
|
||||
if (e->isPlaying() && !e->isStepping()) {
|
||||
|
@ -594,6 +602,8 @@ void FurnaceGUI::doAction(int what) {
|
|||
|
||||
if (end-start<1) break;
|
||||
|
||||
sample->prepareUndo(true);
|
||||
|
||||
if (sampleClipboard!=NULL) {
|
||||
delete[] sampleClipboard;
|
||||
}
|
||||
|
@ -632,6 +642,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
if (curSample<0 || curSample>=(int)e->song.sample.size()) break;
|
||||
if (sampleClipboard==NULL || sampleClipboardLen<1) break;
|
||||
DivSample* sample=e->song.sample[curSample];
|
||||
sample->prepareUndo(true);
|
||||
int pos=(sampleSelStart==-1 || sampleSelStart==sampleSelEnd)?sample->samples:sampleSelStart;
|
||||
|
||||
e->lockEngine([this,sample,pos]() {
|
||||
|
@ -658,6 +669,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
if (curSample<0 || curSample>=(int)e->song.sample.size()) break;
|
||||
if (sampleClipboard==NULL || sampleClipboardLen<1) break;
|
||||
DivSample* sample=e->song.sample[curSample];
|
||||
sample->prepareUndo(true);
|
||||
int pos=(sampleSelStart==-1 || sampleSelStart==sampleSelEnd)?0:sampleSelStart;
|
||||
|
||||
e->lockEngine([this,sample,pos]() {
|
||||
|
@ -685,6 +697,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
if (curSample<0 || curSample>=(int)e->song.sample.size()) break;
|
||||
if (sampleClipboard==NULL || sampleClipboardLen<1) break;
|
||||
DivSample* sample=e->song.sample[curSample];
|
||||
sample->prepareUndo(true);
|
||||
int pos=(sampleSelStart==-1 || sampleSelStart==sampleSelEnd)?0:sampleSelStart;
|
||||
|
||||
e->lockEngine([this,sample,pos]() {
|
||||
|
@ -737,6 +750,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
case GUI_ACTION_SAMPLE_NORMALIZE: {
|
||||
if (curSample<0 || curSample>=(int)e->song.sample.size()) break;
|
||||
DivSample* sample=e->song.sample[curSample];
|
||||
sample->prepareUndo(true);
|
||||
e->lockEngine([this,sample]() {
|
||||
SAMPLE_OP_BEGIN;
|
||||
float maxVal=0.0f;
|
||||
|
@ -783,6 +797,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
case GUI_ACTION_SAMPLE_FADE_IN: {
|
||||
if (curSample<0 || curSample>=(int)e->song.sample.size()) break;
|
||||
DivSample* sample=e->song.sample[curSample];
|
||||
sample->prepareUndo(true);
|
||||
e->lockEngine([this,sample]() {
|
||||
SAMPLE_OP_BEGIN;
|
||||
|
||||
|
@ -812,6 +827,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
case GUI_ACTION_SAMPLE_FADE_OUT: {
|
||||
if (curSample<0 || curSample>=(int)e->song.sample.size()) break;
|
||||
DivSample* sample=e->song.sample[curSample];
|
||||
sample->prepareUndo(true);
|
||||
e->lockEngine([this,sample]() {
|
||||
SAMPLE_OP_BEGIN;
|
||||
|
||||
|
@ -845,6 +861,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
case GUI_ACTION_SAMPLE_SILENCE: {
|
||||
if (curSample<0 || curSample>=(int)e->song.sample.size()) break;
|
||||
DivSample* sample=e->song.sample[curSample];
|
||||
sample->prepareUndo(true);
|
||||
e->lockEngine([this,sample]() {
|
||||
SAMPLE_OP_BEGIN;
|
||||
|
||||
|
@ -868,6 +885,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
case GUI_ACTION_SAMPLE_DELETE: {
|
||||
if (curSample<0 || curSample>=(int)e->song.sample.size()) break;
|
||||
DivSample* sample=e->song.sample[curSample];
|
||||
sample->prepareUndo(true);
|
||||
e->lockEngine([this,sample]() {
|
||||
SAMPLE_OP_BEGIN;
|
||||
|
||||
|
@ -884,6 +902,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
case GUI_ACTION_SAMPLE_TRIM: {
|
||||
if (curSample<0 || curSample>=(int)e->song.sample.size()) break;
|
||||
DivSample* sample=e->song.sample[curSample];
|
||||
sample->prepareUndo(true);
|
||||
e->lockEngine([this,sample]() {
|
||||
SAMPLE_OP_BEGIN;
|
||||
|
||||
|
@ -900,6 +919,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
case GUI_ACTION_SAMPLE_REVERSE: {
|
||||
if (curSample<0 || curSample>=(int)e->song.sample.size()) break;
|
||||
DivSample* sample=e->song.sample[curSample];
|
||||
sample->prepareUndo(true);
|
||||
e->lockEngine([this,sample]() {
|
||||
SAMPLE_OP_BEGIN;
|
||||
|
||||
|
@ -931,6 +951,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
case GUI_ACTION_SAMPLE_INVERT: {
|
||||
if (curSample<0 || curSample>=(int)e->song.sample.size()) break;
|
||||
DivSample* sample=e->song.sample[curSample];
|
||||
sample->prepareUndo(true);
|
||||
e->lockEngine([this,sample]() {
|
||||
SAMPLE_OP_BEGIN;
|
||||
|
||||
|
@ -956,6 +977,7 @@ void FurnaceGUI::doAction(int what) {
|
|||
case GUI_ACTION_SAMPLE_SIGN: {
|
||||
if (curSample<0 || curSample>=(int)e->song.sample.size()) break;
|
||||
DivSample* sample=e->song.sample[curSample];
|
||||
sample->prepareUndo(true);
|
||||
e->lockEngine([this,sample]() {
|
||||
SAMPLE_OP_BEGIN;
|
||||
|
||||
|
|
|
@ -897,6 +897,9 @@ class FurnaceGUI {
|
|||
void doRedo();
|
||||
void editOptions(bool topMenu);
|
||||
|
||||
void doUndoSample();
|
||||
void doRedoSample();
|
||||
|
||||
void play(int row=0);
|
||||
void stop();
|
||||
|
||||
|
|
|
@ -63,14 +63,12 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
for (int i=0; i<17; i++) {
|
||||
if (sampleDepths[i]==NULL) continue;
|
||||
if (ImGui::Selectable(sampleDepths[i])) {
|
||||
sample->prepareUndo(true);
|
||||
sample->depth=i;
|
||||
e->renderSamplesP();
|
||||
updateSampleTex=true;
|
||||
MARK_MODIFIED;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("no undo for sample type change operations!");
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
@ -163,6 +161,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
if (resizeSize>16777215) resizeSize=16777215;
|
||||
}
|
||||
if (ImGui::Button("Resize")) {
|
||||
sample->prepareUndo(true);
|
||||
e->lockEngine([this,sample]() {
|
||||
if (!sample->resize(resizeSize)) {
|
||||
showError("couldn't resize! make sure your sample is 8 or 16-bit.");
|
||||
|
@ -217,6 +216,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
}
|
||||
ImGui::Combo("Filter",&resampleStrat,resampleStrats,6);
|
||||
if (ImGui::Button("Resample")) {
|
||||
sample->prepareUndo(true);
|
||||
e->lockEngine([this,sample]() {
|
||||
if (!sample->resample(resampleTarget,resampleStrat)) {
|
||||
showError("couldn't resample! make sure your sample is 8 or 16-bit.");
|
||||
|
@ -253,6 +253,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
ImGui::SameLine();
|
||||
ImGui::Text("(%.1fdB)",20.0*log10(amplifyVol/100.0f));
|
||||
if (ImGui::Button("Apply")) {
|
||||
sample->prepareUndo(true);
|
||||
e->lockEngine([this,sample]() {
|
||||
SAMPLE_OP_BEGIN;
|
||||
float vol=amplifyVol/100.0f;
|
||||
|
@ -319,6 +320,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
}
|
||||
if (ImGui::Button("Resize")) {
|
||||
int pos=(sampleSelStart==-1 || sampleSelStart==sampleSelEnd)?sample->samples:sampleSelStart;
|
||||
sample->prepareUndo(true);
|
||||
e->lockEngine([this,sample,pos]() {
|
||||
if (!sample->insert(pos,silenceSize)) {
|
||||
showError("couldn't insert! make sure your sample is 8 or 16-bit.");
|
||||
|
@ -437,6 +439,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
}
|
||||
|
||||
if (ImGui::Button("Apply")) {
|
||||
sample->prepareUndo(true);
|
||||
e->lockEngine([this,sample]() {
|
||||
SAMPLE_OP_BEGIN;
|
||||
float res=1.0-pow(sampleFilterRes,0.5f);
|
||||
|
@ -665,6 +668,7 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
sampleDragActive=true;
|
||||
sampleSelStart=-1;
|
||||
sampleSelEnd=-1;
|
||||
if (sampleDragMode) sample->prepareUndo(true);
|
||||
processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y);
|
||||
}
|
||||
}
|
||||
|
@ -827,3 +831,27 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_SAMPLE_EDIT;
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void FurnaceGUI::doUndoSample() {
|
||||
if (!sampleEditOpen) return;
|
||||
if (curSample<0 || curSample>=(int)e->song.sample.size()) return;
|
||||
DivSample* sample=e->song.sample[curSample];
|
||||
e->lockEngine([this,sample]() {
|
||||
if (sample->undo()==2) {
|
||||
e->renderSamples();
|
||||
updateSampleTex=true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void FurnaceGUI::doRedoSample() {
|
||||
if (!sampleEditOpen) return;
|
||||
if (curSample<0 || curSample>=(int)e->song.sample.size()) return;
|
||||
DivSample* sample=e->song.sample[curSample];
|
||||
e->lockEngine([this,sample]() {
|
||||
if (sample->redo()==2) {
|
||||
e->renderSamples();
|
||||
updateSampleTex=true;
|
||||
}
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue