select.c: Remove Draw() call from SelectConnection
[geda-pcb/leaky.git] / src / undo.c
blob5226c5374ad87dda9f8d3895b877b62194d0b723
1 /* $Id$ */
3 /*
4 * COPYRIGHT
6 * PCB, interactive printed circuit board design
7 * Copyright (C) 1994,1995,1996 Thomas Nau
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 * Contact addresses for paper mail and Email:
24 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
25 * Thomas.Nau@rz.uni-ulm.de
29 /* functions used to undo operations
31 * Description:
32 * There are two lists which hold
33 * - information about a command
34 * - data of removed objects
35 * Both lists are organized as first-in-last-out which means that the undo
36 * list can always use the last entry of the remove list.
37 * A serial number is incremented whenever an operation is completed.
38 * An operation itself may consist of several basic instructions.
39 * E.g.: removing all selected objects is one operation with exactly one
40 * serial number even if the remove function is called several times.
42 * a lock flag ensures that no infinite loops occur
45 #ifdef HAVE_CONFIG_H
46 #include "config.h"
47 #endif
49 #include <assert.h>
50 #include <memory.h>
51 #include "global.h"
53 #include "buffer.h"
54 #include "change.h"
55 #include "create.h"
56 #include "data.h"
57 #include "draw.h"
58 #include "error.h"
59 #include "insert.h"
60 #include "misc.h"
61 #include "mirror.h"
62 #include "move.h"
63 #include "mymem.h"
64 #include "polygon.h"
65 #include "remove.h"
66 #include "rotate.h"
67 #include "rtree.h"
68 #include "search.h"
69 #include "set.h"
70 #include "undo.h"
71 #include "strflags.h"
73 #ifdef HAVE_LIBDMALLOC
74 #include <dmalloc.h>
75 #endif
77 RCSID ("$Id$");
79 /* ---------------------------------------------------------------------------
80 * some local data types
82 typedef struct /* information about a change command */
84 char *Name;
86 ChangeNameType, *ChangeNameTypePtr;
88 typedef struct /* information about a move command */
90 LocationType DX, /* movement vector */
91 DY;
93 MoveType, *MoveTypePtr;
95 typedef struct /* information about removed polygon points */
97 LocationType X, Y; /* data */
98 int ID;
99 Cardinal Index; /* index in a polygons array of points */
100 bool last_in_contour; /* Whether the point was the last in its contour */
102 RemovedPointType, *RemovedPointTypePtr;
104 typedef struct /* information about rotation */
106 LocationType CenterX, /* center of rotation */
107 CenterY;
108 BYTE Steps; /* number of steps */
110 RotateType, *RotateTypePtr;
112 typedef struct /* information about moves between layers */
114 Cardinal OriginalLayer; /* the index of the original layer */
116 MoveToLayerType, *MoveToLayerTypePtr;
118 typedef struct /* information about layer changes */
120 int old_index;
121 int new_index;
123 LayerChangeType, *LayerChangeTypePtr;
125 typedef struct /* information about poly clear/restore */
127 bool Clear; /* true was clear, false was restore */
128 LayerTypePtr Layer;
130 ClearPolyType, *ClearPolyTypePtr;
132 typedef struct /* information about netlist lib changes */
134 LibraryTypePtr old;
135 LibraryTypePtr lib;
137 NetlistChangeType, *NetlistChangeTypePtr;
139 typedef struct /* holds information about an operation */
141 int Serial, /* serial number of operation */
142 Type, /* type of operation */
143 Kind, /* type of object with given ID */
144 ID; /* object ID */
145 union /* some additional information */
147 ChangeNameType ChangeName;
148 MoveType Move;
149 RemovedPointType RemovedPoint;
150 RotateType Rotate;
151 MoveToLayerType MoveToLayer;
152 FlagType Flags;
153 BDimension Size;
154 LayerChangeType LayerChange;
155 ClearPolyType ClearPoly;
156 NetlistChangeType NetlistChange;
157 long int CopyID;
159 Data;
161 UndoListType, *UndoListTypePtr;
163 /* ---------------------------------------------------------------------------
164 * some local variables
166 static DataTypePtr RemoveList = NULL; /* list of removed objects */
167 static UndoListTypePtr UndoList = NULL; /* list of operations */
168 static int Serial = 1, /* serial number */
169 SavedSerial;
170 static size_t UndoN, RedoN, /* number of entries */
171 UndoMax;
172 static bool Locked = false; /* do not add entries if */
173 static bool andDraw = true;
174 /* flag is set; prevents from */
175 /* infinite loops */
177 /* ---------------------------------------------------------------------------
178 * some local prototypes
180 static UndoListTypePtr GetUndoSlot (int, int, int);
181 static void DrawRecoveredObject (int, void *, void *, void *);
182 static bool UndoRotate (UndoListTypePtr);
183 static bool UndoChangeName (UndoListTypePtr);
184 static bool UndoCopyOrCreate (UndoListTypePtr);
185 static bool UndoMove (UndoListTypePtr);
186 static bool UndoRemove (UndoListTypePtr);
187 static bool UndoRemovePoint (UndoListTypePtr);
188 static bool UndoInsertPoint (UndoListTypePtr);
189 static bool UndoRemoveContour (UndoListTypePtr);
190 static bool UndoInsertContour (UndoListTypePtr);
191 static bool UndoMoveToLayer (UndoListTypePtr);
192 static bool UndoFlag (UndoListTypePtr);
193 static bool UndoMirror (UndoListTypePtr);
194 static bool UndoChangeSize (UndoListTypePtr);
195 static bool UndoChange2ndSize (UndoListTypePtr);
196 static bool UndoChangeAngles (UndoListTypePtr);
197 static bool UndoChangeClearSize (UndoListTypePtr);
198 static bool UndoChangeMaskSize (UndoListTypePtr);
199 static bool UndoClearPoly (UndoListTypePtr);
200 static int PerformUndo (UndoListTypePtr);
202 /* ---------------------------------------------------------------------------
203 * adds a command plus some data to the undo list
205 static UndoListTypePtr
206 GetUndoSlot (int CommandType, int ID, int Kind)
208 UndoListTypePtr ptr;
209 void *ptr1, *ptr2, *ptr3;
210 int type;
211 static size_t limit = UNDO_WARNING_SIZE;
213 #ifdef DEBUG_ID
214 if (SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, ID, Kind) == NO_TYPE)
215 Message ("hace: ID (%d) and Type (%x) mismatch in AddObject...\n", ID,
216 Kind);
217 #endif
219 /* allocate memory */
220 if (UndoN >= UndoMax)
222 size_t size;
224 UndoMax += STEP_UNDOLIST;
225 size = UndoMax * sizeof (UndoListType);
226 UndoList = (UndoListTypePtr) realloc (UndoList, size);
227 memset (&UndoList[UndoN], 0, STEP_REMOVELIST * sizeof (UndoListType));
229 /* ask user to flush the table because of it's size */
230 if (size > limit)
232 limit = (size / UNDO_WARNING_SIZE + 1) * UNDO_WARNING_SIZE;
233 Message (_("Size of 'undo-list' exceeds %li kb\n"),
234 (long) (size >> 10));
238 /* free structures from the pruned redo list */
240 for (ptr = &UndoList[UndoN]; RedoN; ptr++, RedoN--)
241 switch (ptr->Type)
243 case UNDO_CHANGENAME:
244 free (ptr->Data.ChangeName.Name);
245 break;
246 case UNDO_REMOVE:
247 type =
248 SearchObjectByID (RemoveList, &ptr1, &ptr2, &ptr3, ptr->ID,
249 ptr->Kind);
250 if (type != NO_TYPE)
252 DestroyObject (RemoveList, type, ptr1, ptr2, ptr3);
254 break;
255 default:
256 break;
259 /* copy typefield and serial number to the list */
260 ptr = &UndoList[UndoN++];
261 ptr->Type = CommandType;
262 ptr->Kind = Kind;
263 ptr->ID = ID;
264 ptr->Serial = Serial;
265 return (ptr);
268 /* ---------------------------------------------------------------------------
269 * redraws the recovered object
271 static void
272 DrawRecoveredObject (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
274 if (Type & (LINE_TYPE | TEXT_TYPE | POLYGON_TYPE | ARC_TYPE))
276 LayerTypePtr layer;
278 layer = LAYER_PTR (GetLayerNumber (RemoveList, (LayerTypePtr) Ptr1));
279 DrawObject (Type, (void *) layer, Ptr2, 0);
281 else
282 DrawObject (Type, Ptr1, Ptr2, 0);
285 /* ---------------------------------------------------------------------------
286 * recovers an object from a 'rotate' operation
287 * returns true if anything has been recovered
289 static bool
290 UndoRotate (UndoListTypePtr Entry)
292 void *ptr1, *ptr2, *ptr3;
293 int type;
295 /* lookup entry by it's ID */
296 type =
297 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
298 if (type != NO_TYPE)
300 if (TEST_FLAG (LOCKFLAG, (ArcTypePtr) ptr2))
301 return (false);
302 RotateObject (type, ptr1, ptr2, ptr3,
303 Entry->Data.Rotate.CenterX, Entry->Data.Rotate.CenterY,
304 (4 - Entry->Data.Rotate.Steps) & 0x03);
305 Entry->Data.Rotate.Steps = (4 - Entry->Data.Rotate.Steps) & 0x03;
306 return (true);
308 return (false);
311 /* ---------------------------------------------------------------------------
312 * recovers an object from a clear/restore poly operation
313 * returns true if anything has been recovered
315 static bool
316 UndoClearPoly (UndoListTypePtr Entry)
318 void *ptr1, *ptr2, *ptr3;
319 int type;
321 type =
322 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
323 if (type != NO_TYPE)
325 if (Entry->Data.ClearPoly.Clear)
326 RestoreToPolygon (PCB->Data, type, Entry->Data.ClearPoly.Layer, ptr3);
327 else
328 ClearFromPolygon (PCB->Data, type, Entry->Data.ClearPoly.Layer, ptr3);
329 Entry->Data.ClearPoly.Clear = !Entry->Data.ClearPoly.Clear;
330 return true;
332 return false;
335 /* ---------------------------------------------------------------------------
336 * recovers an object from a 'change name' operation
337 * returns true if anything has been recovered
339 static bool
340 UndoChangeName (UndoListTypePtr Entry)
342 void *ptr1, *ptr2, *ptr3;
343 int type;
345 /* lookup entry by it's ID */
346 type =
347 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
348 if (type != NO_TYPE)
350 if (TEST_FLAG (LOCKFLAG, (TextTypePtr) ptr3))
351 return (false);
352 Entry->Data.ChangeName.Name =
353 (ChangeObjectName (type, ptr1, ptr2, ptr3,
354 Entry->Data.ChangeName.Name));
355 return (true);
357 return (false);
360 /* ---------------------------------------------------------------------------
361 * recovers an object from a 2ndSize change operation
363 static bool
364 UndoChange2ndSize (UndoListTypePtr Entry)
366 void *ptr1, *ptr2, *ptr3;
367 int type;
368 BDimension swap;
370 /* lookup entry by ID */
371 type =
372 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
373 if (type != NO_TYPE)
375 if (TEST_FLAG (LOCKFLAG, (PinTypePtr) ptr2))
376 return (false);
377 swap = ((PinTypePtr) ptr2)->DrillingHole;
378 if (andDraw)
379 EraseObject (type, ptr1, ptr2);
380 ((PinTypePtr) ptr2)->DrillingHole = Entry->Data.Size;
381 Entry->Data.Size = swap;
382 DrawObject (type, ptr1, ptr2, 0);
383 return (true);
385 return (false);
388 /* ---------------------------------------------------------------------------
389 * recovers an object from a ChangeAngles change operation
391 static bool
392 UndoChangeAngles (UndoListTypePtr Entry)
394 void *ptr1, *ptr2, *ptr3;
395 int type;
396 long int old_sa, old_da;
398 /* lookup entry by ID */
399 type =
400 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
401 if (type == ARC_TYPE)
403 LayerTypePtr Layer = (LayerTypePtr) ptr1;
404 ArcTypePtr a = (ArcTypePtr) ptr2;
405 if (TEST_FLAG (LOCKFLAG, a))
406 return (false);
407 r_delete_entry (Layer->arc_tree, (BoxTypePtr) a);
408 old_sa = a->StartAngle;
409 old_da = a->Delta;
410 if (andDraw)
411 EraseObject (type, Layer, a);
412 a->StartAngle = Entry->Data.Move.DX;
413 a->Delta = Entry->Data.Move.DY;
414 SetArcBoundingBox (a);
415 r_insert_entry (Layer->arc_tree, (BoxTypePtr) a, 0);
416 Entry->Data.Move.DX = old_sa;
417 Entry->Data.Move.DY = old_da;;
418 DrawObject (type, ptr1, a, 0);
419 return (true);
421 return (false);
424 /* ---------------------------------------------------------------------------
425 * recovers an object from a clearance size change operation
427 static bool
428 UndoChangeClearSize (UndoListTypePtr Entry)
430 void *ptr1, *ptr2, *ptr3;
431 int type;
432 BDimension swap;
434 /* lookup entry by ID */
435 type =
436 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
437 if (type != NO_TYPE)
439 if (TEST_FLAG (LOCKFLAG, (LineTypePtr) ptr2))
440 return (false);
441 swap = ((PinTypePtr) ptr2)->Clearance;
442 RestoreToPolygon (PCB->Data, type, ptr1, ptr2);
443 if (andDraw)
444 EraseObject (type, ptr1, ptr2);
445 ((PinTypePtr) ptr2)->Clearance = Entry->Data.Size;
446 ClearFromPolygon (PCB->Data, type, ptr1, ptr2);
447 Entry->Data.Size = swap;
448 if (andDraw)
449 DrawObject (type, ptr1, ptr2, 0);
450 return (true);
452 return (false);
455 /* ---------------------------------------------------------------------------
456 * recovers an object from a mask size change operation
458 static bool
459 UndoChangeMaskSize (UndoListTypePtr Entry)
461 void *ptr1, *ptr2, *ptr3;
462 int type;
463 BDimension swap;
465 /* lookup entry by ID */
466 type =
467 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
468 if (type & (VIA_TYPE | PIN_TYPE | PAD_TYPE))
470 if (TEST_FLAG (LOCKFLAG, (PinTypePtr) ptr2))
471 return (false);
472 swap =
473 (type ==
474 PAD_TYPE ? ((PadTypePtr) ptr2)->Mask : ((PinTypePtr) ptr2)->Mask);
475 if (andDraw)
476 EraseObject (type, ptr1, ptr2);
477 if (type == PAD_TYPE)
478 ((PadTypePtr) ptr2)->Mask = Entry->Data.Size;
479 else
480 ((PinTypePtr) ptr2)->Mask = Entry->Data.Size;
481 Entry->Data.Size = swap;
482 if (andDraw)
483 DrawObject (type, ptr1, ptr2, 0);
484 return (true);
486 return (false);
490 /* ---------------------------------------------------------------------------
491 * recovers an object from a Size change operation
493 static bool
494 UndoChangeSize (UndoListTypePtr Entry)
496 void *ptr1, *ptr2, *ptr3;
497 int type;
498 BDimension swap;
500 /* lookup entry by ID */
501 type =
502 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
503 if (type != NO_TYPE)
505 if (TEST_FLAG (LOCKFLAG, (PinTypePtr) ptr2))
506 return (false);
507 /* Wow! can any object be treated as a pin type for size change?? */
508 /* pins, vias, lines, and arcs can. Text can't but it has it's own mechanism */
509 swap = ((PinTypePtr) ptr2)->Thickness;
510 RestoreToPolygon (PCB->Data, type, ptr1, ptr2);
511 if (andDraw)
512 EraseObject (type, ptr1, ptr2);
513 ((PinTypePtr) ptr2)->Thickness = Entry->Data.Size;
514 Entry->Data.Size = swap;
515 ClearFromPolygon (PCB->Data, type, ptr1, ptr2);
516 if (andDraw)
517 DrawObject (type, ptr1, ptr2, 0);
518 return (true);
520 return (false);
523 /* ---------------------------------------------------------------------------
524 * recovers an object from a FLAG change operation
526 static bool
527 UndoFlag (UndoListTypePtr Entry)
529 void *ptr1, *ptr2, *ptr3;
530 int type;
531 FlagType swap;
532 int must_redraw;
534 /* lookup entry by ID */
535 type =
536 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
537 if (type != NO_TYPE)
539 FlagType f1, f2;
540 PinTypePtr pin = (PinTypePtr) ptr2;
542 if (TEST_FLAG (LOCKFLAG, pin))
543 return (false);
545 swap = pin->Flags;
547 must_redraw = 0;
548 f1 = MaskFlags (pin->Flags, ~DRAW_FLAGS);
549 f2 = MaskFlags (Entry->Data.Flags, ~DRAW_FLAGS);
551 if (!FLAGS_EQUAL (f1, f2))
552 must_redraw = 1;
554 if (andDraw && must_redraw)
555 EraseObject (type, ptr1, ptr2);
557 pin->Flags = Entry->Data.Flags;
559 Entry->Data.Flags = swap;
561 if (andDraw && must_redraw)
562 DrawObject (type, ptr1, ptr2, 0);
563 return (true);
565 Message ("hace Internal error: Can't find ID %d type %08x\n", Entry->ID,
566 Entry->Kind);
567 Message ("for UndoFlag Operation. Previous flags: %s\n",
568 flags_to_string (Entry->Data.Flags, 0));
569 return (false);
572 /* ---------------------------------------------------------------------------
573 * recovers an object from a mirror operation
574 * returns true if anything has been recovered
576 static bool
577 UndoMirror (UndoListTypePtr Entry)
579 void *ptr1, *ptr2, *ptr3;
580 int type;
582 /* lookup entry by ID */
583 type =
584 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
585 if (type == ELEMENT_TYPE)
587 ElementTypePtr element = (ElementTypePtr) ptr3;
588 if (TEST_FLAG (LOCKFLAG, element))
589 return (false);
590 if (andDraw)
591 EraseElement (element);
592 MirrorElementCoordinates (PCB->Data, element, Entry->Data.Move.DY);
593 if (andDraw)
594 DrawElement (element, 0);
595 return (true);
597 Message ("hace Internal error: UndoMirror on object type %d\n", type);
598 return (false);
601 /* ---------------------------------------------------------------------------
602 * recovers an object from a 'copy' or 'create' operation
603 * returns true if anything has been recovered
605 static bool
606 UndoCopyOrCreate (UndoListTypePtr Entry)
608 void *ptr1, *ptr2, *ptr3;
609 int type;
611 /* lookup entry by it's ID */
612 type =
613 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
614 if (type != NO_TYPE)
616 if (TEST_FLAG (LOCKFLAG, (PinTypePtr) ptr2))
617 return (false);
618 if (!RemoveList)
619 RemoveList = CreateNewBuffer ();
620 if (andDraw)
621 EraseObject (type, ptr1, ptr2);
622 /* in order to make this re-doable we move it to the RemoveList */
623 MoveObjectToBuffer (RemoveList, PCB->Data, type, ptr1, ptr2, ptr3);
624 Entry->Type = UNDO_REMOVE;
625 return (true);
627 return (false);
630 /* ---------------------------------------------------------------------------
631 * recovers an object from a 'move' operation
632 * returns true if anything has been recovered
634 static bool
635 UndoMove (UndoListTypePtr Entry)
637 void *ptr1, *ptr2, *ptr3;
638 int type;
640 /* lookup entry by it's ID */
641 type =
642 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
643 if (type != NO_TYPE)
645 if (TEST_FLAG (LOCKFLAG, (LineTypePtr) ptr2))
646 return (false);
647 MoveObject (type, ptr1, ptr2, ptr3,
648 -Entry->Data.Move.DX, -Entry->Data.Move.DY);
649 Entry->Data.Move.DX *= -1;
650 Entry->Data.Move.DY *= -1;
651 return (true);
653 return (false);
656 /* ----------------------------------------------------------------------
657 * recovers an object from a 'remove' operation
658 * returns true if anything has been recovered
660 static bool
661 UndoRemove (UndoListTypePtr Entry)
663 void *ptr1, *ptr2, *ptr3;
664 int type;
666 /* lookup entry by it's ID */
667 type =
668 SearchObjectByID (RemoveList, &ptr1, &ptr2, &ptr3, Entry->ID,
669 Entry->Kind);
670 if (type != NO_TYPE)
672 if (andDraw)
673 DrawRecoveredObject (type, ptr1, ptr2, ptr3);
674 MoveObjectToBuffer (PCB->Data, RemoveList, type, ptr1, ptr2, ptr3);
675 Entry->Type = UNDO_CREATE;
676 return (true);
678 return (false);
681 /* ----------------------------------------------------------------------
682 * recovers an object from a 'move to another layer' operation
683 * returns true if anything has been recovered
685 static bool
686 UndoMoveToLayer (UndoListTypePtr Entry)
688 void *ptr1, *ptr2, *ptr3;
689 int type, swap;
691 /* lookup entry by it's ID */
692 type =
693 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
694 if (type != NO_TYPE)
696 if (TEST_FLAG (LOCKFLAG, (LineTypePtr) ptr2))
697 return (false);
698 swap = GetLayerNumber (PCB->Data, (LayerTypePtr) ptr1);
699 MoveObjectToLayer (type, ptr1, ptr2, ptr3,
700 LAYER_PTR (Entry->Data.
701 MoveToLayer.OriginalLayer), true);
702 Entry->Data.MoveToLayer.OriginalLayer = swap;
703 return (true);
705 return (false);
708 /* ---------------------------------------------------------------------------
709 * recovers a removed polygon point
710 * returns true on success
712 static bool
713 UndoRemovePoint (UndoListTypePtr Entry)
715 LayerTypePtr layer;
716 PolygonTypePtr polygon;
717 void *ptr3;
718 int type;
720 /* lookup entry (polygon not point was saved) by it's ID */
721 assert (Entry->Kind == POLYGON_TYPE);
722 type =
723 SearchObjectByID (PCB->Data, (void *) &layer, (void *) &polygon, &ptr3,
724 Entry->ID, Entry->Kind);
725 switch (type)
727 case POLYGON_TYPE: /* restore the removed point */
729 if (TEST_FLAG (LOCKFLAG, polygon))
730 return (false);
731 /* recover the point */
732 if (andDraw && layer->On)
733 ErasePolygon (polygon);
734 InsertPointIntoObject (POLYGON_TYPE, layer, polygon,
735 &Entry->Data.RemovedPoint.Index,
736 Entry->Data.RemovedPoint.X,
737 Entry->Data.RemovedPoint.Y, true,
738 Entry->Data.RemovedPoint.last_in_contour);
740 polygon->Points[Entry->Data.RemovedPoint.Index].ID =
741 Entry->Data.RemovedPoint.ID;
742 if (andDraw && layer->On)
743 DrawPolygon (layer, polygon, 0);
744 Entry->Type = UNDO_INSERT_POINT;
745 Entry->ID = Entry->Data.RemovedPoint.ID;
746 Entry->Kind = POLYGONPOINT_TYPE;
747 return (true);
750 default:
751 return (false);
755 /* ---------------------------------------------------------------------------
756 * recovers an inserted polygon point
757 * returns true on success
759 static bool
760 UndoInsertPoint (UndoListTypePtr Entry)
762 LayerTypePtr layer;
763 PolygonTypePtr polygon;
764 PointTypePtr pnt;
765 int type;
766 Cardinal point_idx;
767 Cardinal hole;
768 bool last_in_contour = false;
770 assert (Entry->Kind == POLYGONPOINT_TYPE);
771 /* lookup entry by it's ID */
772 type =
773 SearchObjectByID (PCB->Data, (void *) &layer, (void *) &polygon,
774 (void *) &pnt, Entry->ID, Entry->Kind);
775 switch (type)
777 case POLYGONPOINT_TYPE: /* removes an inserted polygon point */
779 if (TEST_FLAG (LOCKFLAG, polygon))
780 return (false);
781 if (andDraw && layer->On)
782 ErasePolygon (polygon);
784 /* Check whether this point was at the end of its contour.
785 * If so, we need to flag as such when re-adding the point
786 * so it goes back in the correct place
788 point_idx = polygon_point_idx (polygon, pnt);
789 for (hole = 0; hole < polygon->HoleIndexN; hole++)
790 if (point_idx == polygon->HoleIndex[hole] - 1)
791 last_in_contour = true;
792 if (point_idx == polygon->PointN - 1)
793 last_in_contour = true;
794 Entry->Data.RemovedPoint.last_in_contour = last_in_contour;
796 Entry->Data.RemovedPoint.X = pnt->X;
797 Entry->Data.RemovedPoint.Y = pnt->Y;
798 Entry->Data.RemovedPoint.ID = pnt->ID;
799 Entry->ID = polygon->ID;
800 Entry->Kind = POLYGON_TYPE;
801 Entry->Type = UNDO_REMOVE_POINT;
802 Entry->Data.RemovedPoint.Index = point_idx;
803 DestroyObject (PCB->Data, POLYGONPOINT_TYPE, layer, polygon, pnt);
804 if (andDraw && layer->On)
805 DrawPolygon (layer, polygon, 0);
806 return (true);
809 default:
810 return (false);
814 static bool
815 UndoSwapCopiedObject (UndoListTypePtr Entry)
817 void *ptr1, *ptr2, *ptr3;
818 void *ptr1b, *ptr2b, *ptr3b;
819 AnyObjectType *obj, *obj2;
820 int type;
821 long int swap_id;
823 /* lookup entry by it's ID */
824 type =
825 SearchObjectByID (RemoveList, &ptr1, &ptr2, &ptr3, Entry->Data.CopyID,
826 Entry->Kind);
827 if (type == NO_TYPE)
828 return false;
830 type =
831 SearchObjectByID (PCB->Data, &ptr1b, &ptr2b, &ptr3b, Entry->ID,
832 Entry->Kind);
833 if (type == NO_TYPE)
834 return FALSE;
836 obj = ptr2;
837 obj2 = ptr2b;
839 swap_id = obj->ID;
840 obj->ID = obj2->ID;
841 obj2->ID = swap_id;
843 MoveObjectToBuffer (RemoveList, PCB->Data, type, ptr1b, ptr2b, ptr3b);
845 if (andDraw)
846 DrawRecoveredObject (Entry->Kind, ptr1, ptr2, ptr3);
848 obj = MoveObjectToBuffer (PCB->Data, RemoveList, type, ptr1, ptr2, ptr3);
849 if (Entry->Kind == POLYGON_TYPE)
850 InitClip (PCB->Data, ptr1b, (PolygonType *)obj);
851 return (true);
854 /* ---------------------------------------------------------------------------
855 * recovers an removed polygon point
856 * returns true on success
858 static bool
859 UndoRemoveContour (UndoListTypePtr Entry)
861 assert (Entry->Kind == POLYGON_TYPE);
862 return UndoSwapCopiedObject (Entry);
865 /* ---------------------------------------------------------------------------
866 * recovers an inserted polygon point
867 * returns true on success
869 static bool
870 UndoInsertContour (UndoListTypePtr Entry)
872 assert (Entry->Kind == POLYGON_TYPE);
873 return UndoSwapCopiedObject (Entry);
876 /* ---------------------------------------------------------------------------
877 * undo a layer change
878 * returns true on success
880 static bool
881 UndoLayerChange (UndoListTypePtr Entry)
883 LayerChangeTypePtr l = &Entry->Data.LayerChange;
884 int tmp;
886 tmp = l->new_index;
887 l->new_index = l->old_index;
888 l->old_index = tmp;
890 if (MoveLayer (l->old_index, l->new_index))
891 return false;
892 else
893 return true;
896 /* ---------------------------------------------------------------------------
897 * undo a netlist change
898 * returns true on success
900 static bool
901 UndoNetlistChange (UndoListTypePtr Entry)
903 NetlistChangeTypePtr l = & Entry->Data.NetlistChange;
904 unsigned int i, j;
905 LibraryTypePtr lib, saved;
907 lib = l->lib;
908 saved = l->old;
910 /* iterate over each net */
911 for (i = 0 ; i < lib->MenuN; i++)
913 if (lib->Menu[i].Name)
914 free (lib->Menu[i].Name);
916 if (lib->Menu[i].directory)
917 free (lib->Menu[i].directory);
919 if (lib->Menu[i].Style)
920 free (lib->Menu[i].Style);
922 /* iterate over each pin on the net */
923 for (j = 0; j < lib->Menu[i].EntryN; j++) {
925 if (lib->Menu[i].Entry[j].ListEntry)
926 free (lib->Menu[i].Entry[j].ListEntry);
928 if (lib->Menu[i].Entry[j].AllocatedMemory)
929 free (lib->Menu[i].Entry[j].AllocatedMemory);
931 if (lib->Menu[i].Entry[j].Template)
932 free (lib->Menu[i].Entry[j].Template);
934 if (lib->Menu[i].Entry[j].Package)
935 free (lib->Menu[i].Entry[j].Package);
937 if (lib->Menu[i].Entry[j].Value)
938 free (lib->Menu[i].Entry[j].Value);
940 if (lib->Menu[i].Entry[j].Description)
941 free (lib->Menu[i].Entry[j].Description);
946 if (lib->Menu)
947 free (lib->Menu);
949 *lib = *saved;
951 NetlistChanged (0);
952 return true;
955 /* ---------------------------------------------------------------------------
956 * undo of any 'hard to recover' operation
958 * returns the bitfield for the types of operations that were undone
961 Undo (bool draw)
963 UndoListTypePtr ptr;
964 int Types = 0;
965 int unique;
967 unique = TEST_FLAG (UNIQUENAMEFLAG, PCB);
968 CLEAR_FLAG (UNIQUENAMEFLAG, PCB);
970 andDraw = draw;
974 if (!UndoN)
976 if (!Serial)
977 Message (_("Nothing to undo - buffer is empty\n"));
978 else
979 Serial--;
980 return (false);
983 /* lock undo module to prevent from loops
984 * and loop over all entries with the same serial number
986 ptr = &UndoList[UndoN - 1];
987 if (ptr->Serial != Serial - 1)
989 Message (_("Undo bad serial number %d expecting %d\n"),
990 ptr->Serial, Serial - 1);
991 Serial = ptr->Serial + 1;
992 return (false);
994 LockUndo ();
995 Serial = ptr->Serial;
996 for (; UndoN && ptr->Serial == Serial; ptr--, UndoN--, RedoN++)
997 Types |= PerformUndo (ptr);
998 /* release lock */
999 UnlockUndo ();
1001 while (Types == 0);
1002 if (Types && andDraw)
1003 Draw ();
1005 /* restore the unique flag setting */
1006 if (unique)
1007 SET_FLAG (UNIQUENAMEFLAG, PCB);
1009 return (Types);
1012 static int
1013 PerformUndo (UndoListTypePtr ptr)
1015 switch (ptr->Type)
1017 case UNDO_CHANGENAME:
1018 if (UndoChangeName (ptr))
1019 return (UNDO_CHANGENAME);
1020 break;
1022 case UNDO_CREATE:
1023 if (UndoCopyOrCreate (ptr))
1024 return (UNDO_CREATE);
1025 break;
1027 case UNDO_MOVE:
1028 if (UndoMove (ptr))
1029 return (UNDO_MOVE);
1030 break;
1032 case UNDO_REMOVE:
1033 if (UndoRemove (ptr))
1034 return (UNDO_REMOVE);
1035 break;
1037 case UNDO_REMOVE_POINT:
1038 if (UndoRemovePoint (ptr))
1039 return (UNDO_REMOVE_POINT);
1040 break;
1042 case UNDO_INSERT_POINT:
1043 if (UndoInsertPoint (ptr))
1044 return (UNDO_INSERT_POINT);
1045 break;
1047 case UNDO_REMOVE_CONTOUR:
1048 if (UndoRemoveContour (ptr))
1049 return (UNDO_REMOVE_CONTOUR);
1050 break;
1052 case UNDO_INSERT_CONTOUR:
1053 if (UndoInsertContour (ptr))
1054 return (UNDO_INSERT_CONTOUR);
1055 break;
1057 case UNDO_ROTATE:
1058 if (UndoRotate (ptr))
1059 return (UNDO_ROTATE);
1060 break;
1062 case UNDO_CLEAR:
1063 if (UndoClearPoly (ptr))
1064 return (UNDO_CLEAR);
1065 break;
1067 case UNDO_MOVETOLAYER:
1068 if (UndoMoveToLayer (ptr))
1069 return (UNDO_MOVETOLAYER);
1070 break;
1072 case UNDO_FLAG:
1073 if (UndoFlag (ptr))
1074 return (UNDO_FLAG);
1075 break;
1077 case UNDO_CHANGESIZE:
1078 if (UndoChangeSize (ptr))
1079 return (UNDO_CHANGESIZE);
1080 break;
1082 case UNDO_CHANGECLEARSIZE:
1083 if (UndoChangeClearSize (ptr))
1084 return (UNDO_CHANGECLEARSIZE);
1085 break;
1087 case UNDO_CHANGEMASKSIZE:
1088 if (UndoChangeMaskSize (ptr))
1089 return (UNDO_CHANGEMASKSIZE);
1090 break;
1092 case UNDO_CHANGE2NDSIZE:
1093 if (UndoChange2ndSize (ptr))
1094 return (UNDO_CHANGE2NDSIZE);
1095 break;
1097 case UNDO_CHANGEANGLES:
1098 if (UndoChangeAngles (ptr))
1099 return (UNDO_CHANGEANGLES);
1100 break;
1102 case UNDO_LAYERCHANGE:
1103 if (UndoLayerChange (ptr))
1104 return (UNDO_LAYERCHANGE);
1105 break;
1107 case UNDO_NETLISTCHANGE:
1108 if (UndoNetlistChange (ptr))
1109 return (UNDO_NETLISTCHANGE);
1110 break;
1112 case UNDO_MIRROR:
1113 if (UndoMirror (ptr))
1114 return (UNDO_MIRROR);
1115 break;
1117 return 0;
1120 /* ---------------------------------------------------------------------------
1121 * redo of any 'hard to recover' operation
1123 * returns the number of operations redone
1126 Redo (bool draw)
1128 UndoListTypePtr ptr;
1129 int Types = 0;
1131 andDraw = draw;
1134 if (!RedoN)
1136 Message
1138 ("Nothing to redo. Perhaps changes have been made since last undo\n"));
1139 return (false);
1142 /* lock undo module to prevent from loops
1143 * and loop over all entries with the same serial number
1145 LockUndo ();
1146 ptr = &UndoList[UndoN];
1147 Serial = ptr->Serial;
1148 for (; RedoN && ptr->Serial == Serial; ptr++, UndoN++, RedoN--)
1149 Types |= PerformUndo (ptr);
1150 /* Make next serial number current in case we take a new branch */
1151 Serial++;
1152 UnlockUndo ();
1154 while (Types == 0);
1155 if (Types && andDraw)
1156 Draw ();
1157 return (Types);
1160 /* ---------------------------------------------------------------------------
1161 * restores the serial number of the undo list
1163 void
1164 RestoreUndoSerialNumber (void)
1166 Serial = SavedSerial;
1169 /* ---------------------------------------------------------------------------
1170 * saves the serial number of the undo list
1172 void
1173 SaveUndoSerialNumber (void)
1175 Bumped = false;
1176 SavedSerial = Serial;
1179 /* ---------------------------------------------------------------------------
1180 * increments the serial number of the undo list
1181 * it's not done automatically because some operations perform more
1182 * than one request with the same serial #
1184 void
1185 IncrementUndoSerialNumber (void)
1187 if (!Locked)
1189 /* don't increment if nothing was added */
1190 if (UndoN == 0 || UndoList[UndoN - 1].Serial != Serial)
1191 return;
1192 Serial++;
1193 Bumped = true;
1194 SetChangedFlag (true);
1198 /* ---------------------------------------------------------------------------
1199 * releases memory of the undo- and remove list
1201 void
1202 ClearUndoList (bool Force)
1204 UndoListTypePtr undo;
1206 if (UndoN
1207 && (Force || gui->confirm_dialog ("OK to clear 'undo' buffer?", 0)))
1209 /* release memory allocated by objects in undo list */
1210 for (undo = UndoList; UndoN; undo++, UndoN--)
1212 if (undo->Type == UNDO_CHANGENAME)
1213 free (undo->Data.ChangeName.Name);
1215 free (UndoList);
1216 UndoList = NULL;
1217 if (RemoveList)
1219 FreeDataMemory (RemoveList);
1220 free (RemoveList);
1221 RemoveList = NULL;
1224 /* reset some counters */
1225 UndoN = UndoMax = RedoN = 0;
1228 /* reset counter in any case */
1229 Serial = 1;
1232 /* ---------------------------------------------------------------------------
1233 * adds an object to the list of clearpoly objects
1235 void
1236 AddObjectToClearPolyUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
1237 bool clear)
1239 UndoListTypePtr undo;
1241 if (!Locked)
1243 undo = GetUndoSlot (UNDO_CLEAR, OBJECT_ID (Ptr3), Type);
1244 undo->Data.ClearPoly.Clear = clear;
1245 undo->Data.ClearPoly.Layer = (LayerTypePtr) Ptr1;
1249 /* ---------------------------------------------------------------------------
1250 * adds an object to the list of mirrored objects
1252 void
1253 AddObjectToMirrorUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
1254 LocationType yoff)
1256 UndoListTypePtr undo;
1258 if (!Locked)
1260 undo = GetUndoSlot (UNDO_MIRROR, OBJECT_ID (Ptr3), Type);
1261 undo->Data.Move.DY = yoff;
1265 /* ---------------------------------------------------------------------------
1266 * adds an object to the list of rotated objects
1268 void
1269 AddObjectToRotateUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
1270 LocationType CenterX, LocationType CenterY,
1271 BYTE Steps)
1273 UndoListTypePtr undo;
1275 if (!Locked)
1277 undo = GetUndoSlot (UNDO_ROTATE, OBJECT_ID (Ptr3), Type);
1278 undo->Data.Rotate.CenterX = CenterX;
1279 undo->Data.Rotate.CenterY = CenterY;
1280 undo->Data.Rotate.Steps = Steps;
1284 /* ---------------------------------------------------------------------------
1285 * adds an object to the list of removed objects and removes it from
1286 * the current PCB
1288 void
1289 MoveObjectToRemoveUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1291 UndoListTypePtr undo;
1293 if (!Locked)
1295 if (!RemoveList)
1296 RemoveList = CreateNewBuffer ();
1298 undo = GetUndoSlot (UNDO_REMOVE, OBJECT_ID (Ptr3), Type);
1299 MoveObjectToBuffer (RemoveList, PCB->Data, Type, Ptr1, Ptr2, Ptr3);
1303 /* ---------------------------------------------------------------------------
1304 * adds an object to the list of removed polygon/... points
1306 void
1307 AddObjectToRemovePointUndoList (int Type,
1308 void *Ptr1, void *Ptr2, Cardinal index)
1310 UndoListTypePtr undo;
1311 PolygonTypePtr polygon = (PolygonTypePtr) Ptr2;
1312 Cardinal hole;
1313 bool last_in_contour = false;
1315 if (!Locked)
1317 switch (Type)
1319 case POLYGONPOINT_TYPE:
1321 /* save the ID of the parent object; else it will be
1322 * impossible to recover the point
1324 undo =
1325 GetUndoSlot (UNDO_REMOVE_POINT, OBJECT_ID (polygon),
1326 POLYGON_TYPE);
1327 undo->Data.RemovedPoint.X = polygon->Points[index].X;
1328 undo->Data.RemovedPoint.Y = polygon->Points[index].Y;
1329 undo->Data.RemovedPoint.ID = polygon->Points[index].ID;
1330 undo->Data.RemovedPoint.Index = index;
1332 /* Check whether this point was at the end of its contour.
1333 * If so, we need to flag as such when re-adding the point
1334 * so it goes back in the correct place
1336 for (hole = 0; hole < polygon->HoleIndexN; hole++)
1337 if (index == polygon->HoleIndex[hole] - 1)
1338 last_in_contour = true;
1339 if (index == polygon->PointN - 1)
1340 last_in_contour = true;
1341 undo->Data.RemovedPoint.last_in_contour = last_in_contour;
1343 break;
1348 /* ---------------------------------------------------------------------------
1349 * adds an object to the list of inserted polygon/... points
1351 void
1352 AddObjectToInsertPointUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1354 UndoListTypePtr undo;
1356 if (!Locked)
1357 undo = GetUndoSlot (UNDO_INSERT_POINT, OBJECT_ID (Ptr3), Type);
1360 static void
1361 CopyObjectToUndoList (int undo_type, int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1363 UndoListTypePtr undo;
1364 AnyObjectType *copy;
1366 if (Locked)
1367 return;
1369 if (!RemoveList)
1370 RemoveList = CreateNewBuffer ();
1372 undo = GetUndoSlot (undo_type, OBJECT_ID (Ptr2), Type);
1373 copy = CopyObjectToBuffer (RemoveList, PCB->Data, Type, Ptr1, Ptr2, Ptr3);
1374 undo->Data.CopyID = copy->ID;
1377 /* ---------------------------------------------------------------------------
1378 * adds an object to the list of removed contours
1379 * (Actually just takes a copy of the whole polygon to restore)
1381 void
1382 AddObjectToRemoveContourUndoList (int Type,
1383 LayerType *Layer, PolygonType *Polygon)
1385 CopyObjectToUndoList (UNDO_REMOVE_CONTOUR, Type, Layer, Polygon, NULL);
1388 /* ---------------------------------------------------------------------------
1389 * adds an object to the list of insert contours
1390 * (Actually just takes a copy of the whole polygon to restore)
1392 void
1393 AddObjectToInsertContourUndoList (int Type,
1394 LayerType *Layer, PolygonType *Polygon)
1396 CopyObjectToUndoList (UNDO_INSERT_CONTOUR, Type, Layer, Polygon, NULL);
1399 /* ---------------------------------------------------------------------------
1400 * adds an object to the list of moved objects
1402 void
1403 AddObjectToMoveUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
1404 LocationType DX, LocationType DY)
1406 UndoListTypePtr undo;
1408 if (!Locked)
1410 undo = GetUndoSlot (UNDO_MOVE, OBJECT_ID (Ptr3), Type);
1411 undo->Data.Move.DX = DX;
1412 undo->Data.Move.DY = DY;
1416 /* ---------------------------------------------------------------------------
1417 * adds an object to the list of objects with changed names
1419 void
1420 AddObjectToChangeNameUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
1421 char *OldName)
1423 UndoListTypePtr undo;
1425 if (!Locked)
1427 undo = GetUndoSlot (UNDO_CHANGENAME, OBJECT_ID (Ptr3), Type);
1428 undo->Data.ChangeName.Name = OldName;
1432 /* ---------------------------------------------------------------------------
1433 * adds an object to the list of objects moved to another layer
1435 void
1436 AddObjectToMoveToLayerUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1438 UndoListTypePtr undo;
1440 if (!Locked)
1442 undo = GetUndoSlot (UNDO_MOVETOLAYER, OBJECT_ID (Ptr3), Type);
1443 undo->Data.MoveToLayer.OriginalLayer =
1444 GetLayerNumber (PCB->Data, (LayerTypePtr) Ptr1);
1448 /* ---------------------------------------------------------------------------
1449 * adds an object to the list of created objects
1451 void
1452 AddObjectToCreateUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1454 UndoListTypePtr undo;
1456 if (!Locked)
1457 undo = GetUndoSlot (UNDO_CREATE, OBJECT_ID (Ptr3), Type);
1458 ClearFromPolygon (PCB->Data, Type, Ptr1, Ptr2);
1461 /* ---------------------------------------------------------------------------
1462 * adds an object to the list of objects with flags changed
1464 void
1465 AddObjectToFlagUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1467 UndoListTypePtr undo;
1469 if (!Locked)
1471 undo = GetUndoSlot (UNDO_FLAG, OBJECT_ID (Ptr2), Type);
1472 undo->Data.Flags = ((PinTypePtr) Ptr2)->Flags;
1476 /* ---------------------------------------------------------------------------
1477 * adds an object to the list of objects with Size changes
1479 void
1480 AddObjectToSizeUndoList (int Type, void *ptr1, void *ptr2, void *ptr3)
1482 UndoListTypePtr undo;
1484 if (!Locked)
1486 undo = GetUndoSlot (UNDO_CHANGESIZE, OBJECT_ID (ptr2), Type);
1487 switch (Type)
1489 case PIN_TYPE:
1490 case VIA_TYPE:
1491 undo->Data.Size = ((PinTypePtr) ptr2)->Thickness;
1492 break;
1493 case LINE_TYPE:
1494 case ELEMENTLINE_TYPE:
1495 undo->Data.Size = ((LineTypePtr) ptr2)->Thickness;
1496 break;
1497 case TEXT_TYPE:
1498 case ELEMENTNAME_TYPE:
1499 undo->Data.Size = ((TextTypePtr) ptr2)->Scale;
1500 break;
1501 case PAD_TYPE:
1502 undo->Data.Size = ((PadTypePtr) ptr2)->Thickness;
1503 break;
1504 case ARC_TYPE:
1505 case ELEMENTARC_TYPE:
1506 undo->Data.Size = ((ArcTypePtr) ptr2)->Thickness;
1507 break;
1512 /* ---------------------------------------------------------------------------
1513 * adds an object to the list of objects with Size changes
1515 void
1516 AddObjectToClearSizeUndoList (int Type, void *ptr1, void *ptr2, void *ptr3)
1518 UndoListTypePtr undo;
1520 if (!Locked)
1522 undo = GetUndoSlot (UNDO_CHANGECLEARSIZE, OBJECT_ID (ptr2), Type);
1523 switch (Type)
1525 case PIN_TYPE:
1526 case VIA_TYPE:
1527 undo->Data.Size = ((PinTypePtr) ptr2)->Clearance;
1528 break;
1529 case LINE_TYPE:
1530 undo->Data.Size = ((LineTypePtr) ptr2)->Clearance;
1531 break;
1532 case PAD_TYPE:
1533 undo->Data.Size = ((PadTypePtr) ptr2)->Clearance;
1534 break;
1535 case ARC_TYPE:
1536 undo->Data.Size = ((ArcTypePtr) ptr2)->Clearance;
1537 break;
1542 /* ---------------------------------------------------------------------------
1543 * adds an object to the list of objects with Size changes
1545 void
1546 AddObjectToMaskSizeUndoList (int Type, void *ptr1, void *ptr2, void *ptr3)
1548 UndoListTypePtr undo;
1550 if (!Locked)
1552 undo = GetUndoSlot (UNDO_CHANGEMASKSIZE, OBJECT_ID (ptr2), Type);
1553 switch (Type)
1555 case PIN_TYPE:
1556 case VIA_TYPE:
1557 undo->Data.Size = ((PinTypePtr) ptr2)->Mask;
1558 break;
1559 case PAD_TYPE:
1560 undo->Data.Size = ((PadTypePtr) ptr2)->Mask;
1561 break;
1566 /* ---------------------------------------------------------------------------
1567 * adds an object to the list of objects with 2ndSize changes
1569 void
1570 AddObjectTo2ndSizeUndoList (int Type, void *ptr1, void *ptr2, void *ptr3)
1572 UndoListTypePtr undo;
1574 if (!Locked)
1576 undo = GetUndoSlot (UNDO_CHANGE2NDSIZE, OBJECT_ID (ptr2), Type);
1577 if (Type == PIN_TYPE || Type == VIA_TYPE)
1578 undo->Data.Size = ((PinTypePtr) ptr2)->DrillingHole;
1582 /* ---------------------------------------------------------------------------
1583 * adds an object to the list of changed angles. Note that you must
1584 * call this before changing the angles, passing the new start/delta.
1586 void
1587 AddObjectToChangeAnglesUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1589 UndoListTypePtr undo;
1590 ArcTypePtr a = (ArcTypePtr) Ptr3;
1592 if (!Locked)
1594 undo = GetUndoSlot (UNDO_CHANGEANGLES, OBJECT_ID (Ptr3), Type);
1595 undo->Data.Move.DX = a->StartAngle;
1596 undo->Data.Move.DY = a->Delta;
1600 /* ---------------------------------------------------------------------------
1601 * adds a layer change (new, delete, move) to the undo list.
1603 void
1604 AddLayerChangeToUndoList (int old_index, int new_index)
1606 UndoListTypePtr undo;
1608 if (!Locked)
1610 undo = GetUndoSlot (UNDO_LAYERCHANGE, 0, 0);
1611 undo->Data.LayerChange.old_index = old_index;
1612 undo->Data.LayerChange.new_index = new_index;
1616 /* ---------------------------------------------------------------------------
1617 * adds a netlist change to the undo list
1619 void
1620 AddNetlistLibToUndoList (LibraryTypePtr lib)
1622 UndoListTypePtr undo;
1623 unsigned int i, j;
1624 LibraryTypePtr old;
1626 if (!Locked)
1628 undo = GetUndoSlot (UNDO_NETLISTCHANGE, 0, 0);
1629 /* keep track of where the data needs to go */
1630 undo->Data.NetlistChange.lib = lib;
1632 /* and what the old data is that we'll need to restore */
1633 undo->Data.NetlistChange.old = malloc (sizeof (LibraryTypePtr));
1634 old = undo->Data.NetlistChange.old;
1635 old->MenuN = lib->MenuN;
1636 old->MenuMax = lib->MenuMax;
1637 old->Menu = malloc (old->MenuMax * sizeof (LibraryMenuType));
1638 if (old->Menu == NULL)
1640 fprintf (stderr, "malloc() failed in %s\n", __FUNCTION__);
1641 exit (1);
1644 /* iterate over each net */
1645 for (i = 0 ; i < lib->MenuN; i++)
1647 old->Menu[i].EntryN = lib->Menu[i].EntryN;
1648 old->Menu[i].EntryMax = lib->Menu[i].EntryMax;
1650 old->Menu[i].Name =
1651 lib->Menu[i].Name ? strdup (lib->Menu[i].Name) : NULL;
1653 old->Menu[i].directory =
1654 lib->Menu[i].directory ? strdup (lib->Menu[i].directory) : NULL;
1656 old->Menu[i].Style =
1657 lib->Menu[i].Style ? strdup (lib->Menu[i].Style) : NULL;
1660 old->Menu[i].Entry =
1661 malloc (old->Menu[i].EntryMax * sizeof (LibraryEntryType));
1662 if (old->Menu[i].Entry == NULL)
1664 fprintf (stderr, "malloc() failed in %s\n", __FUNCTION__);
1665 exit (1);
1668 /* iterate over each pin on the net */
1669 for (j = 0; j < lib->Menu[i].EntryN; j++) {
1671 old->Menu[i].Entry[j].ListEntry =
1672 lib->Menu[i].Entry[j].ListEntry ?
1673 strdup (lib->Menu[i].Entry[j].ListEntry) :
1674 NULL;
1676 old->Menu[i].Entry[j].AllocatedMemory =
1677 lib->Menu[i].Entry[j].AllocatedMemory ?
1678 strdup (lib->Menu[i].Entry[j].AllocatedMemory) :
1679 NULL;
1681 old->Menu[i].Entry[j].Template =
1682 lib->Menu[i].Entry[j].Template ?
1683 strdup (lib->Menu[i].Entry[j].Template) :
1684 NULL;
1686 old->Menu[i].Entry[j].Package =
1687 lib->Menu[i].Entry[j].Package ?
1688 strdup (lib->Menu[i].Entry[j].Package) :
1689 NULL;
1691 old->Menu[i].Entry[j].Value =
1692 lib->Menu[i].Entry[j].Value ?
1693 strdup (lib->Menu[i].Entry[j].Value) :
1694 NULL;
1696 old->Menu[i].Entry[j].Description =
1697 lib->Menu[i].Entry[j].Description ?
1698 strdup (lib->Menu[i].Entry[j].Description) :
1699 NULL;
1708 /* ---------------------------------------------------------------------------
1709 * set lock flag
1711 void
1712 LockUndo (void)
1714 Locked = true;
1717 /* ---------------------------------------------------------------------------
1718 * reset lock flag
1720 void
1721 UnlockUndo (void)
1723 Locked = false;
1726 /* ---------------------------------------------------------------------------
1727 * return undo lock state
1729 bool
1730 Undoing (void)
1732 return (Locked);