1 //-----------------------------------------------------------------------------
2 // The user-visible undo/redo operation; whenever they change something, we
3 // record our state and push it on a stack, and we pop the stack when they
4 // select undo.
5 //
6 // Copyright 2008-2013 Jonathan Westhues.
7 //-----------------------------------------------------------------------------
8 #include "solvespace.h"
9
UndoRemember(void)10 void SolveSpaceUI::UndoRemember(void) {
11 unsaved = true;
12 PushFromCurrentOnto(&undo);
13 UndoClearStack(&redo);
14 UndoEnableMenus();
15 }
16
UndoUndo(void)17 void SolveSpaceUI::UndoUndo(void) {
18 if(undo.cnt <= 0) return;
19
20 PushFromCurrentOnto(&redo);
21 PopOntoCurrentFrom(&undo);
22 UndoEnableMenus();
23 }
24
UndoRedo(void)25 void SolveSpaceUI::UndoRedo(void) {
26 if(redo.cnt <= 0) return;
27
28 PushFromCurrentOnto(&undo);
29 PopOntoCurrentFrom(&redo);
30 UndoEnableMenus();
31 }
32
UndoEnableMenus(void)33 void SolveSpaceUI::UndoEnableMenus(void) {
34 EnableMenuById(GraphicsWindow::MNU_UNDO, undo.cnt > 0);
35 EnableMenuById(GraphicsWindow::MNU_REDO, redo.cnt > 0);
36 }
37
PushFromCurrentOnto(UndoStack * uk)38 void SolveSpaceUI::PushFromCurrentOnto(UndoStack *uk) {
39 int i;
40
41 if(uk->cnt == MAX_UNDO) {
42 UndoClearState(&(uk->d[uk->write]));
43 // And then write in to this one again
44 } else {
45 (uk->cnt)++;
46 }
47
48 UndoState *ut = &(uk->d[uk->write]);
49 *ut = {};
50 for(i = 0; i < SK.group.n; i++) {
51 Group *src = &(SK.group.elem[i]);
52 Group dest = *src;
53 // And then clean up all the stuff that needs to be a deep copy,
54 // and zero out all the dynamic stuff that will get regenerated.
55 dest.clean = false;
56 dest.solved = {};
57 dest.polyLoops = {};
58 dest.bezierLoops = {};
59 dest.bezierOpens = {};
60 dest.polyError = {};
61 dest.thisMesh = {};
62 dest.runningMesh = {};
63 dest.thisShell = {};
64 dest.runningShell = {};
65 dest.displayMesh = {};
66 dest.displayEdges = {};
67 dest.displayOutlines = {};
68
69 dest.remap = {};
70 src->remap.DeepCopyInto(&(dest.remap));
71
72 dest.impMesh = {};
73 dest.impShell = {};
74 dest.impEntity = {};
75 ut->group.Add(&dest);
76 }
77 for(i = 0; i < SK.groupOrder.n; i++) {
78 ut->groupOrder.Add(&(SK.groupOrder.elem[i]));
79 }
80 for(i = 0; i < SK.request.n; i++) {
81 ut->request.Add(&(SK.request.elem[i]));
82 }
83 for(i = 0; i < SK.constraint.n; i++) {
84 Constraint *src = &(SK.constraint.elem[i]);
85 Constraint dest = *src;
86 dest.dogd = {};
87 ut->constraint.Add(&dest);
88 }
89 for(i = 0; i < SK.param.n; i++) {
90 ut->param.Add(&(SK.param.elem[i]));
91 }
92 for(i = 0; i < SK.style.n; i++) {
93 ut->style.Add(&(SK.style.elem[i]));
94 }
95 ut->activeGroup = SS.GW.activeGroup;
96
97 uk->write = WRAP(uk->write + 1, MAX_UNDO);
98 }
99
PopOntoCurrentFrom(UndoStack * uk)100 void SolveSpaceUI::PopOntoCurrentFrom(UndoStack *uk) {
101 int i;
102
103 if(uk->cnt <= 0) oops();
104 (uk->cnt)--;
105 uk->write = WRAP(uk->write - 1, MAX_UNDO);
106
107 UndoState *ut = &(uk->d[uk->write]);
108
109 // Free everything in the main copy of the program before replacing it
110 for(i = 0; i < SK.groupOrder.n; i++) {
111 Group *g = SK.GetGroup(SK.groupOrder.elem[i]);
112 g->Clear();
113 }
114 SK.group.Clear();
115 SK.groupOrder.Clear();
116 SK.request.Clear();
117 SK.constraint.Clear();
118 SK.param.Clear();
119 SK.style.Clear();
120
121 // And then do a shallow copy of the state from the undo list
122 ut->group.MoveSelfInto(&(SK.group));
123 for(i = 0; i < ut->groupOrder.n; i++)
124 SK.groupOrder.Add(&ut->groupOrder.elem[i]);
125 ut->request.MoveSelfInto(&(SK.request));
126 ut->constraint.MoveSelfInto(&(SK.constraint));
127 ut->param.MoveSelfInto(&(SK.param));
128 ut->style.MoveSelfInto(&(SK.style));
129 SS.GW.activeGroup = ut->activeGroup;
130
131 // No need to free it, since a shallow copy was made above
132 *ut = {};
133
134 // And reset the state everywhere else in the program, since the
135 // sketch just changed a lot.
136 SS.GW.ClearSuper();
137 SS.TW.ClearSuper();
138 SS.ReloadAllImported();
139 SS.GenerateAll(SolveSpaceUI::GENERATE_ALL);
140 SS.ScheduleShowTW();
141
142 // Activate the group that was active before.
143 Group *activeGroup = SK.GetGroup(SS.GW.activeGroup);
144 activeGroup->Activate();
145 }
146
UndoClearStack(UndoStack * uk)147 void SolveSpaceUI::UndoClearStack(UndoStack *uk) {
148 while(uk->cnt > 0) {
149 uk->write = WRAP(uk->write - 1, MAX_UNDO);
150 (uk->cnt)--;
151 UndoClearState(&(uk->d[uk->write]));
152 }
153 *uk = {}; // for good measure
154 }
155
UndoClearState(UndoState * ut)156 void SolveSpaceUI::UndoClearState(UndoState *ut) {
157 int i;
158 for(i = 0; i < ut->group.n; i++) {
159 Group *g = &(ut->group.elem[i]);
160
161 g->remap.Clear();
162 }
163 ut->group.Clear();
164 ut->request.Clear();
165 ut->constraint.Clear();
166 ut->param.Clear();
167 ut->style.Clear();
168 *ut = {};
169 }
170
171