solvespace/src/undoredo.cpp

155 lines
4.5 KiB
C++

//-----------------------------------------------------------------------------
// The user-visible undo/redo operation; whenever they change something, we
// record our state and push it on a stack, and we pop the stack when they
// select undo.
//
// Copyright 2008-2013 Jonathan Westhues.
//-----------------------------------------------------------------------------
#include "solvespace.h"
void SolveSpaceUI::UndoRemember() {
unsaved = true;
PushFromCurrentOnto(&undo);
UndoClearStack(&redo);
UndoEnableMenus();
}
void SolveSpaceUI::UndoUndo() {
if(undo.cnt <= 0) return;
PushFromCurrentOnto(&redo);
PopOntoCurrentFrom(&undo);
UndoEnableMenus();
}
void SolveSpaceUI::UndoRedo() {
if(redo.cnt <= 0) return;
PushFromCurrentOnto(&undo);
PopOntoCurrentFrom(&redo);
UndoEnableMenus();
}
void SolveSpaceUI::UndoEnableMenus() {
SS.GW.undoMenuItem->SetEnabled(undo.cnt > 0);
SS.GW.redoMenuItem->SetEnabled(redo.cnt > 0);
}
void SolveSpaceUI::PushFromCurrentOnto(UndoStack *uk) {
if(uk->cnt == MAX_UNDO) {
UndoClearState(&(uk->d[uk->write]));
// And then write in to this one again
} else {
(uk->cnt)++;
}
UndoState *ut = &(uk->d[uk->write]);
*ut = {};
ut->group.ReserveMore(SK.group.n);
for(Group &src : SK.group) {
// Shallow copy
Group dest(src);
// And then clean up all the stuff that needs to be a deep copy,
// and zero out all the dynamic stuff that will get regenerated.
dest.clean = false;
dest.solved = {};
dest.polyLoops = {};
dest.bezierLoops = {};
dest.bezierOpens = {};
dest.polyError = {};
dest.thisMesh = {};
dest.runningMesh = {};
dest.thisShell = {};
dest.runningShell = {};
dest.displayMesh = {};
dest.displayOutlines = {};
dest.remap = src.remap;
dest.impMesh = {};
dest.impShell = {};
dest.impEntity = {};
ut->group.Add(&dest);
}
for(auto &src : SK.groupOrder) { ut->groupOrder.Add(&src); }
ut->request.ReserveMore(SK.request.n);
for(auto &src : SK.request) { ut->request.Add(&src); }
ut->constraint.ReserveMore(SK.constraint.n);
for(auto &src : SK.constraint) {
// Shallow copy
Constraint dest(src);
ut->constraint.Add(&dest);
}
ut->param.ReserveMore(SK.param.n);
for(auto &src : SK.param) { ut->param.Add(&src); }
ut->style.ReserveMore(SK.style.n);
for(auto &src : SK.style) { ut->style.Add(&src); }
ut->activeGroup = SS.GW.activeGroup;
uk->write = WRAP(uk->write + 1, MAX_UNDO);
}
void SolveSpaceUI::PopOntoCurrentFrom(UndoStack *uk) {
ssassert(uk->cnt > 0, "Cannot pop from empty undo stack");
(uk->cnt)--;
uk->write = WRAP(uk->write - 1, MAX_UNDO);
UndoState *ut = &(uk->d[uk->write]);
// Free everything in the main copy of the program before replacing it
for(hGroup hg : SK.groupOrder) {
Group *g = SK.GetGroup(hg);
g->Clear();
}
SK.group.Clear();
SK.groupOrder.Clear();
SK.request.Clear();
SK.constraint.Clear();
SK.param.Clear();
SK.style.Clear();
// And then do a shallow copy of the state from the undo list
ut->group.MoveSelfInto(&(SK.group));
for(auto &gh : ut->groupOrder) { SK.groupOrder.Add(&gh); }
ut->request.MoveSelfInto(&(SK.request));
ut->constraint.MoveSelfInto(&(SK.constraint));
ut->param.MoveSelfInto(&(SK.param));
ut->style.MoveSelfInto(&(SK.style));
SS.GW.activeGroup = ut->activeGroup;
// No need to free it, since a shallow copy was made above
*ut = {};
// And reset the state everywhere else in the program, since the
// sketch just changed a lot.
SS.GW.ClearSuper();
SS.TW.ClearSuper();
SS.ReloadAllLinked(SS.saveFile);
SS.GenerateAll(SolveSpaceUI::Generate::ALL);
SS.ScheduleShowTW();
// Activate the group that was active before.
Group *activeGroup = SK.GetGroup(SS.GW.activeGroup);
activeGroup->Activate();
}
void SolveSpaceUI::UndoClearStack(UndoStack *uk) {
while(uk->cnt > 0) {
uk->write = WRAP(uk->write - 1, MAX_UNDO);
(uk->cnt)--;
UndoClearState(&(uk->d[uk->write]));
}
*uk = {}; // for good measure
}
void SolveSpaceUI::UndoClearState(UndoState *ut) {
for(auto &g : ut->group) { g.remap.clear(); }
ut->group.Clear();
ut->request.Clear();
ut->constraint.Clear();
ut->param.Clear();
ut->style.Clear();
*ut = {};
}