1 {
2 *****************************************************************************
3 * *
4 * This file is part of the ZCAD *
5 * *
6 * See the file COPYING.modifiedLGPL.txt, included in this distribution, *
7 * for details about the copyright. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
12 * *
13 *****************************************************************************
14 }
15 {
16 @author(Andrey Zubarev <zamtmn@yandex.ru>)
17 }
18 {$MODE OBJFPC}
19 {$H+}
20 unit zeundostack;
21 {$INCLUDE def.inc}
22 interface
23 uses gzctnrvectortypes,zebaseundocommands,varmandef,uzbtypesbase,
24 gzctnrvectorpobjects,sysutils,uzbtypes,uzbmemman;
25 const BeginUndo:GDBString='BeginUndo';
26 EndUndo:GDBString='EndUndo';
27 type
28 TUndoRedoResult=(URROk,
29 URRNoCommandsToUndoInOverlayMode,
30 URRNoCommandsToUndo,
31 URRNoCommandsToRedo);
32 TOnUndoRedoProc=procedure of object;
33 PTZctnrVectorUndoCommands=^TZctnrVectorUndoCommands;
34 TZctnrVectorUndoCommands=object(specialize GZVectorPObects{-}<PTElementaryCommand,TElementaryCommand>{//})
35 public
36 CurrentCommand:TArrayIndex;
37 currentcommandstartmarker:TArrayIndex;
38 startmarkercount:GDBInteger;
39 onUndoRedo:TOnUndoRedoProc;
40 procedure PushStartMarker(CommandName:GDBString);
41 procedure PushEndMarker;
42 procedure PushStone;
43 procedure PushChangeCommand(_obj:GDBPointer;_fieldsize:PtrInt);overload;
undonull44 function undo(out msg:string;prevheap:TArrayIndex;overlay:GDBBoolean):TUndoRedoResult;
45 procedure KillLastCommand;
redonull46 function redo(out msg:string):TUndoRedoResult;
47 constructor init;
48 procedure doOnUndoRedo;
PushBackDatanull49 function PushBackData(const data:GDBPointer):TArrayIndex;virtual;
50 Procedure ClearFrom(cc:TArrayIndex);
51
CreateTTypedChangeCommandnull52 function CreateTTypedChangeCommand(PDataInstance:GDBPointer;PType:PUserTypeDescriptor):PTTypedChangeCommand;overload;
PushCreateTTypedChangeCommandnull53 function PushCreateTTypedChangeCommand(PDataInstance:GDBPointer;PType:PUserTypeDescriptor):PTTypedChangeCommand;overload;
54
55 end;
56 implementation
57
58 procedure TZctnrVectorUndoCommands.doOnUndoRedo;
59 begin
60 if assigned(onUndoRedo)then
61 onUndoRedo;
62 end;
63
64 procedure TZctnrVectorUndoCommands.PushStartMarker(CommandName:GDBString);
65 var
66 pmarker:PTMarkerCommand;
67 begin
68 inc(startmarkercount);
69 if startmarkercount=1 then
70 begin
71 GDBGetMem({$IFDEF DEBUGBUILD}'{30D8D2A8-1130-40FB-81BC-10C7D9A1FF38}',{$ENDIF}pointer(pmarker),sizeof(TMarkerCommand));
72 pmarker^.init(CommandName,-1);
73 currentcommandstartmarker:=self.PushBackData(pmarker);
74 inc(CurrentCommand);
75 end;
76 end;
77 procedure TZctnrVectorUndoCommands.PushStone;
78 var
79 pmarker:PTMarkerCommand;
80 begin
81 //inc(startmarkercount);
82 //if startmarkercount=1 then
83 begin
84 GDBGetMem({$IFDEF DEBUGBUILD}'{30D8D2A8-1130-40FB-81BC-10C7D9A1FF38}',{$ENDIF}pointer(pmarker),sizeof(TMarkerCommand));
85 pmarker^.init('StoneMarker',-2);
86 currentcommandstartmarker:=self.PushBackData(pmarker);
87 inc(CurrentCommand);
88 end;
89 end;
90 procedure TZctnrVectorUndoCommands.PushEndMarker;
91 var
92 pmarker:PTMarkerCommand;
93 begin
94 dec(startmarkercount);
95 if startmarkercount=0 then
96 begin
97 GDBGetMem({$IFDEF DEBUGBUILD}'{F5F5F128-96B3-4AB9-81A1-2B86E0C95EF4}',{$ENDIF}pointer(pmarker),sizeof(TMarkerCommand));
98 pmarker^.init('EndMarker',currentcommandstartmarker);
99 currentcommandstartmarker:=-1;
100 self.PushBackData(pmarker);
101 inc(CurrentCommand);
102 startmarkercount:=0;
103 end;
104 end;
105 //procedure TZctnrVectorUndoCommands.PushTypedChangeCommand(_obj:GDBPointer;_PTypeManager:PUserTypeDescriptor);overload;
106 procedure TZctnrVectorUndoCommands.PushChangeCommand(_obj:GDBPointer;_fieldsize:PtrInt);
107 var
108 pcc:PTChangeCommand;
109 begin
110 if CurrentCommand>0 then
111 begin
112 pcc:=pointer(self.getDataMutable(CurrentCommand-1));
113 if pcc^.GetCommandType=TTC_ChangeCommand then
114 if (pcc^.Addr=_obj)
115 and(pcc^.datasize=_fieldsize) then
116 exit;
117 end;
118 GDBGetMem({$IFDEF DEBUGBUILD}'{3A3AAA8F-40EB-415B-BDC2-798712E9F402}',{$ENDIF}pointer(pcc),sizeof(TChangeCommand));
119 pcc^.init(_obj,_fieldsize);
120 inc(CurrentCommand);
121 PushBackData(pcc);
122 end;
123 procedure TZctnrVectorUndoCommands.KillLastCommand;
124 var
125 pcc:PTElementaryCommand;
126 mcounter:integer;
127 begin
128 begin
129 mcounter:=0;
130 repeat
131 pcc:=self.getDataMutable(CurrentCommand-1);
132
133 if pcc^.GetCommandType=TTC_MEnd then
134 begin
135 inc(mcounter);
136 pcc^.Done;
137 end
138 else if pcc^.GetCommandType=TTC_MBegin then
139 begin
140 dec(mcounter);
141 pcc^.Done;
142 end
143 else
144 pcc^.Done;
145 dec(CurrentCommand);
146 until mcounter=0;
147 end;
148 count:=self.CurrentCommand;
149 end;
undonull150 function TZctnrVectorUndoCommands.undo(out msg:string;prevheap:TArrayIndex;overlay:GDBBoolean):TUndoRedoResult;
151 var
152 pcc:PTElementaryCommand;
153 mcounter:integer;
154 begin
155 msg:='';
156 result:=URROk;
157 if CurrentCommand>prevheap then
158 begin
159 mcounter:=0;
160 repeat
161 pcc:=self.getDataMutable(CurrentCommand-1);
162
163 if pcc^.GetCommandType=TTC_MEnd then
164 begin
165 inc(mcounter);
166 //pcc^.undo;
167 end
168 else if pcc^.GetCommandType=TTC_MBegin then
169 begin
170 dec(mcounter);
171 if mcounter=0 then
172 {HistoryOutStr}msg:=msg+('Undo "'+PTMarkerCommand(pcc)^.Name+'"');
173 //pcc^.undo;
174 end
175 else if pcc^.GetCommandType=TTC_MNotUndableIfOverlay then
176 begin
177 if overlay then
178 result:=URRNoCommandsToUndo;
179 end
180 else
181 pcc^.undo;
182
183 if (pcc^.GetCommandType<>TTC_MNotUndableIfOverlay)then
184 dec(CurrentCommand)
185 else
186 if not overlay then
187 dec(CurrentCommand);
188 until mcounter=0;
189 end
190 else
191 begin
192 if overlay then
193 result:=URRNoCommandsToUndo
194 else
195 result:=URRNoCommandsToUndoInOverlayMode;
196 end;
197 {DC:=gdb.GetCurrentDWG^.CreateDrawingRC;
198 gdb.GetCurrentROOT^.FormatAfterEdit(gdb.GetCurrentDWG^,dc);}
199 doOnUndoRedo;
200 end;
redonull201 function TZctnrVectorUndoCommands.redo(out msg:string):TUndoRedoResult;
202 var
203 pcc:PTElementaryCommand;
204 mcounter:integer;
205 begin
206 if CurrentCommand<count then
207 begin
208 {pcc:=pointer(self.getDataMutable(CurrentCommand));
209 pcc^.Comit;
210 inc(CurrentCommand);}
211 mcounter:=0;
212 repeat
213 pcc:=self.getDataMutable(CurrentCommand);
214
215 if pcc^.GetCommandType=TTC_MEnd then
216 begin
217 inc(mcounter);
218 pcc^.undo;
219 end
220 else if pcc^.GetCommandType=TTC_MBegin then
221 begin
222 if mcounter=0 then
223 {HistoryOutStr}msg:=msg+('Redo "'+PTMarkerCommand(pcc)^.Name+'"');
224 dec(mcounter);
225 pcc^.undo;
226 end
227 else pcc^.comit;
228 inc(CurrentCommand);
229 until mcounter=0;
230 result:=URROk;
231 end
232 else
233 result:=URRNoCommandsToRedo;
234 {dc:=gdb.GetCurrentDWG^.CreateDrawingRC;
235 gdb.GetCurrentROOT^.FormatAfterEdit(gdb.GetCurrentDWG^,dc);}
236 doOnUndoRedo;
237 end;
238
239 constructor TZctnrVectorUndoCommands.init;
240 begin
241 inherited init({$IFDEF DEBUGBUILD}'{EF79AD53-2ECF-4848-8EDA-C498803A4188}',{$ENDIF}1);
242 CurrentCommand:=0;
243 onUndoRedo:=nil;;
244 end;
245 procedure TZctnrVectorUndoCommands.ClearFrom(cc:TArrayIndex);
246 begin
247 cleareraseobjfrom2(cc);
248 CurrentCommand:=Count;
249 end;
250
TZctnrVectorUndoCommands.PushBackDatanull251 function TZctnrVectorUndoCommands.PushBackData(const data:GDBPointer):TArrayIndex;
252 begin
253 if self.CurrentCommand<count then
254 self.cleareraseobjfrom2(self.CurrentCommand);
255 result:=inherited PushBackData(data);
256 end;
CreateTTypedChangeCommandnull257 function TZctnrVectorUndoCommands.CreateTTypedChangeCommand(PDataInstance:GDBPointer;PType:PUserTypeDescriptor):PTTypedChangeCommand;overload;
258 begin
259 gdbgetmem({$IFDEF DEBUGBUILD}'{6D631C2E-57FF-4553-991B-332464B7495E}',{$ENDIF}result,sizeof(TTypedChangeCommand));
260 result^.Assign(PDataInstance,PType);
261 end;
PushCreateTTypedChangeCommandnull262 function TZctnrVectorUndoCommands.PushCreateTTypedChangeCommand(PDataInstance:GDBPointer;PType:PUserTypeDescriptor):PTTypedChangeCommand;overload;
263 begin
264 if CurrentCommand>0 then
265 begin
266 result:=pointer(self.getDataMutable(CurrentCommand-1));
267 if result^.GetCommandType=TTC_ChangeCommand then
268 if (result^.Addr=PDataInstance)
269 and(result^.PTypeManager=PType)
270 then
271 exit;
272 end;
273 result:=CreateTTypedChangeCommand(PDataInstance,PType);
274 {if CurrentCommand<>count then
275 self.cleareraseobjfrom2(CurrentCommand);}
276
277 PushBackData(result);
278 inc(CurrentCommand);
279 end;
280
281 begin
282 end.
283
284