
A new button is added, "Show/hide outline of solid model". When the outline is hidden, it is rendered using the "solid edge" style. When the outline is shown, it is rendered using the "outline" style. In SolveSpace's true WYSIWYG tradition, the 2d view export follows the rendered view exactly. Moreover, shell edges are not rendered anymore, since there is not much need in them anymore and not drawing them lessens the overlap between various kinds of lines, which already includes entities, solid edges and outlines.
171 lines
4.7 KiB
C++
171 lines
4.7 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(void) {
|
|
unsaved = true;
|
|
PushFromCurrentOnto(&undo);
|
|
UndoClearStack(&redo);
|
|
UndoEnableMenus();
|
|
}
|
|
|
|
void SolveSpaceUI::UndoUndo(void) {
|
|
if(undo.cnt <= 0) return;
|
|
|
|
PushFromCurrentOnto(&redo);
|
|
PopOntoCurrentFrom(&undo);
|
|
UndoEnableMenus();
|
|
}
|
|
|
|
void SolveSpaceUI::UndoRedo(void) {
|
|
if(redo.cnt <= 0) return;
|
|
|
|
PushFromCurrentOnto(&undo);
|
|
PopOntoCurrentFrom(&redo);
|
|
UndoEnableMenus();
|
|
}
|
|
|
|
void SolveSpaceUI::UndoEnableMenus(void) {
|
|
EnableMenuById(GraphicsWindow::MNU_UNDO, undo.cnt > 0);
|
|
EnableMenuById(GraphicsWindow::MNU_REDO, redo.cnt > 0);
|
|
}
|
|
|
|
void SolveSpaceUI::PushFromCurrentOnto(UndoStack *uk) {
|
|
int i;
|
|
|
|
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 = {};
|
|
for(i = 0; i < SK.group.n; i++) {
|
|
Group *src = &(SK.group.elem[i]);
|
|
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.displayEdges = {};
|
|
dest.displayOutlines = {};
|
|
|
|
dest.remap = {};
|
|
src->remap.DeepCopyInto(&(dest.remap));
|
|
|
|
dest.impMesh = {};
|
|
dest.impShell = {};
|
|
dest.impEntity = {};
|
|
ut->group.Add(&dest);
|
|
}
|
|
for(i = 0; i < SK.groupOrder.n; i++) {
|
|
ut->groupOrder.Add(&(SK.groupOrder.elem[i]));
|
|
}
|
|
for(i = 0; i < SK.request.n; i++) {
|
|
ut->request.Add(&(SK.request.elem[i]));
|
|
}
|
|
for(i = 0; i < SK.constraint.n; i++) {
|
|
Constraint *src = &(SK.constraint.elem[i]);
|
|
Constraint dest = *src;
|
|
dest.dogd = {};
|
|
ut->constraint.Add(&dest);
|
|
}
|
|
for(i = 0; i < SK.param.n; i++) {
|
|
ut->param.Add(&(SK.param.elem[i]));
|
|
}
|
|
for(i = 0; i < SK.style.n; i++) {
|
|
ut->style.Add(&(SK.style.elem[i]));
|
|
}
|
|
ut->activeGroup = SS.GW.activeGroup;
|
|
|
|
uk->write = WRAP(uk->write + 1, MAX_UNDO);
|
|
}
|
|
|
|
void SolveSpaceUI::PopOntoCurrentFrom(UndoStack *uk) {
|
|
int i;
|
|
|
|
if(uk->cnt <= 0) oops();
|
|
(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(i = 0; i < SK.groupOrder.n; i++) {
|
|
Group *g = SK.GetGroup(SK.groupOrder.elem[i]);
|
|
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(i = 0; i < ut->groupOrder.n; i++)
|
|
SK.groupOrder.Add(&ut->groupOrder.elem[i]);
|
|
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.ReloadAllImported();
|
|
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) {
|
|
int i;
|
|
for(i = 0; i < ut->group.n; i++) {
|
|
Group *g = &(ut->group.elem[i]);
|
|
|
|
g->remap.Clear();
|
|
}
|
|
ut->group.Clear();
|
|
ut->request.Clear();
|
|
ut->constraint.Clear();
|
|
ut->param.Clear();
|
|
ut->style.Clear();
|
|
*ut = {};
|
|
}
|
|
|