(no commit message)
[geda-pcb/pcjc2.git] / src / undo.c
blobca41c74d12f7be36b364f0eb6516498cb92119ac
1 /*
2 * COPYRIGHT
4 * PCB, interactive printed circuit board design
5 * Copyright (C) 1994,1995,1996 Thomas Nau
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * Contact addresses for paper mail and Email:
22 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
23 * Thomas.Nau@rz.uni-ulm.de
27 /* functions used to undo operations
29 * Description:
30 * There are two lists which hold
31 * - information about a command
32 * - data of removed objects
33 * Both lists are organized as first-in-last-out which means that the undo
34 * list can always use the last entry of the remove list.
35 * A serial number is incremented whenever an operation is completed.
36 * An operation itself may consist of several basic instructions.
37 * E.g.: removing all selected objects is one operation with exactly one
38 * serial number even if the remove function is called several times.
40 * a lock flag ensures that no infinite loops occur
43 #ifdef HAVE_CONFIG_H
44 #include "config.h"
45 #endif
47 #include <assert.h>
48 #include <memory.h>
49 #include "global.h"
51 #include "buffer.h"
52 #include "change.h"
53 #include "create.h"
54 #include "data.h"
55 #include "draw.h"
56 #include "error.h"
57 #include "insert.h"
58 #include "misc.h"
59 #include "mirror.h"
60 #include "move.h"
61 #include "mymem.h"
62 #include "polygon.h"
63 #include "remove.h"
64 #include "rotate.h"
65 #include "rtree.h"
66 #include "search.h"
67 #include "set.h"
68 #include "undo.h"
69 #include "strflags.h"
71 #ifdef HAVE_LIBDMALLOC
72 #include <dmalloc.h>
73 #endif
75 static bool between_increment_and_restore = false;
76 static bool added_undo_between_increment_and_restore = false;
78 /* ---------------------------------------------------------------------------
79 * some local data types
81 typedef struct /* information about a change command */
83 char *Name;
84 } ChangeNameType;
86 typedef struct /* information about a move command */
88 Coord DX, DY; /* movement vector */
89 } MoveType;
91 typedef struct /* information about removed polygon points */
93 Coord X, Y; /* data */
94 int ID;
95 Cardinal Index; /* index in a polygons array of points */
96 bool last_in_contour; /* Whether the point was the last in its contour */
97 } RemovedPointType;
99 typedef struct /* information about rotation */
101 Coord CenterX, CenterY; /* center of rotation */
102 Cardinal Steps; /* number of steps */
103 } RotateType;
105 typedef struct /* information about moves between layers */
107 Cardinal OriginalLayer; /* the index of the original layer */
108 } MoveToLayerType;
110 typedef struct /* information about layer changes */
112 int old_index;
113 int new_index;
114 } LayerChangeType;
116 typedef struct /* information about poly clear/restore */
118 bool Clear; /* true was clear, false was restore */
119 LayerType *Layer;
120 } ClearPolyType;
122 typedef struct /* information about netlist lib changes */
124 LibraryType *old;
125 LibraryType *lib;
126 } NetlistChangeType;
128 typedef struct /* holds information about an operation */
130 int Serial, /* serial number of operation */
131 Type, /* type of operation */
132 Kind, /* type of object with given ID */
133 ID; /* object ID */
134 union /* some additional information */
136 ChangeNameType ChangeName;
137 MoveType Move;
138 RemovedPointType RemovedPoint;
139 RotateType Rotate;
140 MoveToLayerType MoveToLayer;
141 FlagType Flags;
142 Coord Size;
143 LayerChangeType LayerChange;
144 ClearPolyType ClearPoly;
145 NetlistChangeType NetlistChange;
146 long int CopyID;
148 Data;
149 } UndoListType;
151 /* ---------------------------------------------------------------------------
152 * some local variables
154 static DataType *RemoveList = NULL; /* list of removed objects */
155 static UndoListType *UndoList = NULL; /* list of operations */
156 static int Serial = 1, /* serial number */
157 SavedSerial;
158 static size_t UndoN, RedoN, /* number of entries */
159 UndoMax;
160 static bool Locked = false; /* do not add entries if */
161 static bool andDraw = true;
162 /* flag is set; prevents from */
163 /* infinite loops */
165 /* ---------------------------------------------------------------------------
166 * some local prototypes
168 static UndoListType *GetUndoSlot (int, int, int);
169 static void DrawRecoveredObject (int, void *, void *, void *);
170 static bool UndoRotate (UndoListType *);
171 static bool UndoChangeName (UndoListType *);
172 static bool UndoCopyOrCreate (UndoListType *);
173 static bool UndoMove (UndoListType *);
174 static bool UndoRemove (UndoListType *);
175 static bool UndoRemovePoint (UndoListType *);
176 static bool UndoInsertPoint (UndoListType *);
177 static bool UndoRemoveContour (UndoListType *);
178 static bool UndoInsertContour (UndoListType *);
179 static bool UndoMoveToLayer (UndoListType *);
180 static bool UndoFlag (UndoListType *);
181 static bool UndoMirror (UndoListType *);
182 static bool UndoChangeSize (UndoListType *);
183 static bool UndoChange2ndSize (UndoListType *);
184 static bool UndoChangeAngles (UndoListType *);
185 static bool UndoChangeClearSize (UndoListType *);
186 static bool UndoChangeMaskSize (UndoListType *);
187 static bool UndoClearPoly (UndoListType *);
188 static int PerformUndo (UndoListType *);
190 /* ---------------------------------------------------------------------------
191 * adds a command plus some data to the undo list
193 static UndoListType *
194 GetUndoSlot (int CommandType, int ID, int Kind)
196 UndoListType *ptr;
197 void *ptr1, *ptr2, *ptr3;
198 int type;
199 static size_t limit = UNDO_WARNING_SIZE;
201 #ifdef DEBUG_ID
202 if (SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, ID, Kind) == NO_TYPE)
203 Message ("hace: ID (%d) and Type (%x) mismatch in AddObject...\n", ID,
204 Kind);
205 #endif
207 /* allocate memory */
208 if (UndoN >= UndoMax)
210 size_t size;
212 UndoMax += STEP_UNDOLIST;
213 size = UndoMax * sizeof (UndoListType);
214 UndoList = (UndoListType *) realloc (UndoList, size);
215 memset (&UndoList[UndoN], 0, STEP_REMOVELIST * sizeof (UndoListType));
217 /* ask user to flush the table because of it's size */
218 if (size > limit)
220 limit = (size / UNDO_WARNING_SIZE + 1) * UNDO_WARNING_SIZE;
221 Message (_("Size of 'undo-list' exceeds %li kb\n"),
222 (long) (size >> 10));
226 /* free structures from the pruned redo list */
228 for (ptr = &UndoList[UndoN]; RedoN; ptr++, RedoN--)
229 switch (ptr->Type)
231 case UNDO_CHANGENAME:
232 free (ptr->Data.ChangeName.Name);
233 break;
234 case UNDO_REMOVE:
235 type =
236 SearchObjectByID (RemoveList, &ptr1, &ptr2, &ptr3, ptr->ID,
237 ptr->Kind);
238 if (type != NO_TYPE)
240 DestroyObject (RemoveList, type, ptr1, ptr2, ptr3);
242 break;
243 default:
244 break;
247 if (between_increment_and_restore)
248 added_undo_between_increment_and_restore = true;
250 /* copy typefield and serial number to the list */
251 ptr = &UndoList[UndoN++];
252 ptr->Type = CommandType;
253 ptr->Kind = Kind;
254 ptr->ID = ID;
255 ptr->Serial = Serial;
256 return (ptr);
259 /* ---------------------------------------------------------------------------
260 * redraws the recovered object
262 static void
263 DrawRecoveredObject (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
265 if (Type & (LINE_TYPE | TEXT_TYPE | POLYGON_TYPE | ARC_TYPE))
267 LayerType *layer;
269 layer = LAYER_PTR (GetLayerNumber (RemoveList, (LayerType *) Ptr1));
270 DrawObject (Type, (void *) layer, Ptr2);
272 else
273 DrawObject (Type, Ptr1, Ptr2);
276 /* ---------------------------------------------------------------------------
277 * recovers an object from a 'rotate' operation
278 * returns true if anything has been recovered
280 static bool
281 UndoRotate (UndoListType *Entry)
283 void *ptr1, *ptr2, *ptr3;
284 int type;
286 /* lookup entry by it's ID */
287 type =
288 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
289 if (type != NO_TYPE)
291 RotateObject (type, ptr1, ptr2, ptr3,
292 Entry->Data.Rotate.CenterX, Entry->Data.Rotate.CenterY,
293 (4 - Entry->Data.Rotate.Steps) & 0x03);
294 Entry->Data.Rotate.Steps = (4 - Entry->Data.Rotate.Steps) & 0x03;
295 return (true);
297 return (false);
300 /* ---------------------------------------------------------------------------
301 * recovers an object from a clear/restore poly operation
302 * returns true if anything has been recovered
304 static bool
305 UndoClearPoly (UndoListType *Entry)
307 void *ptr1, *ptr2, *ptr3;
308 int type;
310 type =
311 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
312 if (type != NO_TYPE)
314 if (Entry->Data.ClearPoly.Clear)
315 RestoreToPolygon (PCB->Data, type, Entry->Data.ClearPoly.Layer, ptr3);
316 else
317 ClearFromPolygon (PCB->Data, type, Entry->Data.ClearPoly.Layer, ptr3);
318 Entry->Data.ClearPoly.Clear = !Entry->Data.ClearPoly.Clear;
319 return true;
321 return false;
324 /* ---------------------------------------------------------------------------
325 * recovers an object from a 'change name' operation
326 * returns true if anything has been recovered
328 static bool
329 UndoChangeName (UndoListType *Entry)
331 void *ptr1, *ptr2, *ptr3;
332 int type;
334 /* lookup entry by it's ID */
335 type =
336 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
337 if (type != NO_TYPE)
339 Entry->Data.ChangeName.Name =
340 (char *)(ChangeObjectName (type, ptr1, ptr2, ptr3,
341 Entry->Data.ChangeName.Name));
342 return (true);
344 return (false);
347 /* ---------------------------------------------------------------------------
348 * recovers an object from a 2ndSize change operation
350 static bool
351 UndoChange2ndSize (UndoListType *Entry)
353 void *ptr1, *ptr2, *ptr3;
354 int type;
355 Coord swap;
357 /* lookup entry by ID */
358 type =
359 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
360 if (type != NO_TYPE)
362 swap = ((PinType *) ptr2)->DrillingHole;
363 if (andDraw)
364 EraseObject (type, ptr1, ptr2);
365 ((PinType *) ptr2)->DrillingHole = Entry->Data.Size;
366 Entry->Data.Size = swap;
367 DrawObject (type, ptr1, ptr2);
368 return (true);
370 return (false);
373 /* ---------------------------------------------------------------------------
374 * recovers an object from a ChangeAngles change operation
376 static bool
377 UndoChangeAngles (UndoListType *Entry)
379 void *ptr1, *ptr2, *ptr3;
380 int type;
381 long int old_sa, old_da;
383 /* lookup entry by ID */
384 type =
385 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
386 if (type == ARC_TYPE)
388 LayerType *Layer = (LayerType *) ptr1;
389 ArcType *a = (ArcType *) ptr2;
390 r_delete_entry (Layer->arc_tree, (BoxType *) a);
391 old_sa = a->StartAngle;
392 old_da = a->Delta;
393 if (andDraw)
394 EraseObject (type, Layer, a);
395 a->StartAngle = Entry->Data.Move.DX;
396 a->Delta = Entry->Data.Move.DY;
397 SetArcBoundingBox (a);
398 r_insert_entry (Layer->arc_tree, (BoxType *) a, 0);
399 Entry->Data.Move.DX = old_sa;
400 Entry->Data.Move.DY = old_da;;
401 DrawObject (type, ptr1, a);
402 return (true);
404 return (false);
407 /* ---------------------------------------------------------------------------
408 * recovers an object from a clearance size change operation
410 static bool
411 UndoChangeClearSize (UndoListType *Entry)
413 void *ptr1, *ptr2, *ptr3;
414 int type;
415 Coord swap;
417 /* lookup entry by ID */
418 type =
419 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
420 if (type != NO_TYPE)
422 swap = ((PinType *) ptr2)->Clearance;
423 RestoreToPolygon (PCB->Data, type, ptr1, ptr2);
424 if (andDraw)
425 EraseObject (type, ptr1, ptr2);
426 ((PinType *) ptr2)->Clearance = Entry->Data.Size;
427 ClearFromPolygon (PCB->Data, type, ptr1, ptr2);
428 Entry->Data.Size = swap;
429 if (andDraw)
430 DrawObject (type, ptr1, ptr2);
431 return (true);
433 return (false);
436 /* ---------------------------------------------------------------------------
437 * recovers an object from a mask size change operation
439 static bool
440 UndoChangeMaskSize (UndoListType *Entry)
442 void *ptr1, *ptr2, *ptr3;
443 int type;
444 Coord swap;
446 /* lookup entry by ID */
447 type =
448 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
449 if (type & (VIA_TYPE | PIN_TYPE | PAD_TYPE))
451 swap =
452 (type ==
453 PAD_TYPE ? ((PadType *) ptr2)->Mask : ((PinType *) ptr2)->Mask);
454 if (andDraw)
455 EraseObject (type, ptr1, ptr2);
456 if (type == PAD_TYPE)
457 ((PadType *) ptr2)->Mask = Entry->Data.Size;
458 else
459 ((PinType *) ptr2)->Mask = Entry->Data.Size;
460 Entry->Data.Size = swap;
461 if (andDraw)
462 DrawObject (type, ptr1, ptr2);
463 return (true);
465 return (false);
469 /* ---------------------------------------------------------------------------
470 * recovers an object from a Size change operation
472 static bool
473 UndoChangeSize (UndoListType *Entry)
475 void *ptr1, *ptr2, *ptr3;
476 int type;
477 Coord swap;
479 /* lookup entry by ID */
480 type =
481 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
482 if (type != NO_TYPE)
484 /* Wow! can any object be treated as a pin type for size change?? */
485 /* pins, vias, lines, and arcs can. Text can't but it has it's own mechanism */
486 swap = ((PinType *) ptr2)->Thickness;
487 RestoreToPolygon (PCB->Data, type, ptr1, ptr2);
488 if (andDraw)
489 EraseObject (type, ptr1, ptr2);
490 ((PinType *) ptr2)->Thickness = Entry->Data.Size;
491 Entry->Data.Size = swap;
492 ClearFromPolygon (PCB->Data, type, ptr1, ptr2);
493 if (andDraw)
494 DrawObject (type, ptr1, ptr2);
495 return (true);
497 return (false);
500 /* ---------------------------------------------------------------------------
501 * recovers an object from a FLAG change operation
503 static bool
504 UndoFlag (UndoListType *Entry)
506 void *ptr1, *ptr2, *ptr3;
507 int type;
508 FlagType swap;
509 int must_redraw;
511 /* lookup entry by ID */
512 type =
513 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
514 if (type != NO_TYPE)
516 FlagType f1, f2;
517 PinType *pin = (PinType *) ptr2;
519 swap = pin->Flags;
521 must_redraw = 0;
522 f1 = MaskFlags (pin->Flags, ~DRAW_FLAGS);
523 f2 = MaskFlags (Entry->Data.Flags, ~DRAW_FLAGS);
525 if (!FLAGS_EQUAL (f1, f2))
526 must_redraw = 1;
528 if (andDraw && must_redraw)
529 EraseObject (type, ptr1, ptr2);
531 pin->Flags = Entry->Data.Flags;
533 Entry->Data.Flags = swap;
535 if (andDraw && must_redraw)
536 DrawObject (type, ptr1, ptr2);
537 return (true);
539 Message ("hace Internal error: Can't find ID %d type %08x\n", Entry->ID,
540 Entry->Kind);
541 Message ("for UndoFlag Operation. Previous flags: %s\n",
542 flags_to_string (Entry->Data.Flags, 0));
543 return (false);
546 /* ---------------------------------------------------------------------------
547 * recovers an object from a mirror operation
548 * returns true if anything has been recovered
550 static bool
551 UndoMirror (UndoListType *Entry)
553 void *ptr1, *ptr2, *ptr3;
554 int type;
556 /* lookup entry by ID */
557 type =
558 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
559 if (type == ELEMENT_TYPE)
561 ElementType *element = (ElementType *) ptr3;
562 if (andDraw)
563 EraseElement (element);
564 MirrorElementCoordinates (PCB->Data, element, Entry->Data.Move.DY);
565 if (andDraw)
566 DrawElement (element);
567 return (true);
569 Message ("hace Internal error: UndoMirror on object type %d\n", type);
570 return (false);
573 /* ---------------------------------------------------------------------------
574 * recovers an object from a 'copy' or 'create' operation
575 * returns true if anything has been recovered
577 static bool
578 UndoCopyOrCreate (UndoListType *Entry)
580 void *ptr1, *ptr2, *ptr3;
581 int type;
583 /* lookup entry by it's ID */
584 type =
585 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
586 if (type != NO_TYPE)
588 if (!RemoveList)
589 RemoveList = CreateNewBuffer ();
590 if (andDraw)
591 EraseObject (type, ptr1, ptr2);
592 /* in order to make this re-doable we move it to the RemoveList */
593 MoveObjectToBuffer (RemoveList, PCB->Data, type, ptr1, ptr2, ptr3);
594 Entry->Type = UNDO_REMOVE;
595 return (true);
597 return (false);
600 /* ---------------------------------------------------------------------------
601 * recovers an object from a 'move' operation
602 * returns true if anything has been recovered
604 static bool
605 UndoMove (UndoListType *Entry)
607 void *ptr1, *ptr2, *ptr3;
608 int type;
610 /* lookup entry by it's ID */
611 type =
612 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
613 if (type != NO_TYPE)
615 MoveObject (type, ptr1, ptr2, ptr3,
616 -Entry->Data.Move.DX, -Entry->Data.Move.DY);
617 Entry->Data.Move.DX *= -1;
618 Entry->Data.Move.DY *= -1;
619 return (true);
621 return (false);
624 /* ----------------------------------------------------------------------
625 * recovers an object from a 'remove' operation
626 * returns true if anything has been recovered
628 static bool
629 UndoRemove (UndoListType *Entry)
631 void *ptr1, *ptr2, *ptr3;
632 int type;
634 /* lookup entry by it's ID */
635 type =
636 SearchObjectByID (RemoveList, &ptr1, &ptr2, &ptr3, Entry->ID,
637 Entry->Kind);
638 if (type != NO_TYPE)
640 if (andDraw)
641 DrawRecoveredObject (type, ptr1, ptr2, ptr3);
642 MoveObjectToBuffer (PCB->Data, RemoveList, type, ptr1, ptr2, ptr3);
643 Entry->Type = UNDO_CREATE;
644 return (true);
646 return (false);
649 /* ----------------------------------------------------------------------
650 * recovers an object from a 'move to another layer' operation
651 * returns true if anything has been recovered
653 static bool
654 UndoMoveToLayer (UndoListType *Entry)
656 void *ptr1, *ptr2, *ptr3;
657 int type, swap;
659 /* lookup entry by it's ID */
660 type =
661 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
662 if (type != NO_TYPE)
664 swap = GetLayerNumber (PCB->Data, (LayerType *) ptr1);
665 MoveObjectToLayer (type, ptr1, ptr2, ptr3,
666 LAYER_PTR (Entry->Data.
667 MoveToLayer.OriginalLayer), true);
668 Entry->Data.MoveToLayer.OriginalLayer = swap;
669 return (true);
671 return (false);
674 /* ---------------------------------------------------------------------------
675 * recovers a removed polygon point
676 * returns true on success
678 static bool
679 UndoRemovePoint (UndoListType *Entry)
681 LayerType *layer;
682 PolygonType *polygon;
683 void *ptr3;
684 int type;
686 /* lookup entry (polygon not point was saved) by it's ID */
687 assert (Entry->Kind == POLYGON_TYPE);
688 type =
689 SearchObjectByID (PCB->Data, (void **) &layer, (void **) &polygon, &ptr3,
690 Entry->ID, Entry->Kind);
691 switch (type)
693 case POLYGON_TYPE: /* restore the removed point */
695 /* recover the point */
696 if (andDraw && layer->On)
697 ErasePolygon (polygon);
698 InsertPointIntoObject (POLYGON_TYPE, layer, polygon,
699 &Entry->Data.RemovedPoint.Index,
700 Entry->Data.RemovedPoint.X,
701 Entry->Data.RemovedPoint.Y, true,
702 Entry->Data.RemovedPoint.last_in_contour);
704 polygon->Points[Entry->Data.RemovedPoint.Index].ID =
705 Entry->Data.RemovedPoint.ID;
706 if (andDraw && layer->On)
707 DrawPolygon (layer, polygon);
708 Entry->Type = UNDO_INSERT_POINT;
709 Entry->ID = Entry->Data.RemovedPoint.ID;
710 Entry->Kind = POLYGONPOINT_TYPE;
711 return (true);
714 default:
715 return (false);
719 /* ---------------------------------------------------------------------------
720 * recovers an inserted polygon point
721 * returns true on success
723 static bool
724 UndoInsertPoint (UndoListType *Entry)
726 LayerType *layer;
727 PolygonType *polygon;
728 PointType *pnt;
729 int type;
730 Cardinal point_idx;
731 Cardinal hole;
732 bool last_in_contour = false;
734 assert (Entry->Kind == POLYGONPOINT_TYPE);
735 /* lookup entry by it's ID */
736 type =
737 SearchObjectByID (PCB->Data, (void **) &layer, (void **) &polygon,
738 (void **) &pnt, Entry->ID, Entry->Kind);
739 switch (type)
741 case POLYGONPOINT_TYPE: /* removes an inserted polygon point */
743 if (andDraw && layer->On)
744 ErasePolygon (polygon);
746 /* Check whether this point was at the end of its contour.
747 * If so, we need to flag as such when re-adding the point
748 * so it goes back in the correct place
750 point_idx = polygon_point_idx (polygon, pnt);
751 for (hole = 0; hole < polygon->HoleIndexN; hole++)
752 if (point_idx == polygon->HoleIndex[hole] - 1)
753 last_in_contour = true;
754 if (point_idx == polygon->PointN - 1)
755 last_in_contour = true;
756 Entry->Data.RemovedPoint.last_in_contour = last_in_contour;
758 Entry->Data.RemovedPoint.X = pnt->X;
759 Entry->Data.RemovedPoint.Y = pnt->Y;
760 Entry->Data.RemovedPoint.ID = pnt->ID;
761 Entry->ID = polygon->ID;
762 Entry->Kind = POLYGON_TYPE;
763 Entry->Type = UNDO_REMOVE_POINT;
764 Entry->Data.RemovedPoint.Index = point_idx;
765 DestroyObject (PCB->Data, POLYGONPOINT_TYPE, layer, polygon, pnt);
766 if (andDraw && layer->On)
767 DrawPolygon (layer, polygon);
768 return (true);
771 default:
772 return (false);
776 static bool
777 UndoSwapCopiedObject (UndoListType *Entry)
779 void *ptr1, *ptr2, *ptr3;
780 void *ptr1b, *ptr2b, *ptr3b;
781 AnyObjectType *obj, *obj2;
782 int type;
783 long int swap_id;
785 /* lookup entry by it's ID */
786 type =
787 SearchObjectByID (RemoveList, &ptr1, &ptr2, &ptr3, Entry->Data.CopyID,
788 Entry->Kind);
789 if (type == NO_TYPE)
790 return false;
792 type =
793 SearchObjectByID (PCB->Data, &ptr1b, &ptr2b, &ptr3b, Entry->ID,
794 Entry->Kind);
795 if (type == NO_TYPE)
796 return FALSE;
798 obj = (AnyObjectType *)ptr2;
799 obj2 = (AnyObjectType *)ptr2b;
801 swap_id = obj->ID;
802 obj->ID = obj2->ID;
803 obj2->ID = swap_id;
805 MoveObjectToBuffer (RemoveList, PCB->Data, type, ptr1b, ptr2b, ptr3b);
807 if (andDraw)
808 DrawRecoveredObject (Entry->Kind, ptr1, ptr2, ptr3);
810 obj = (AnyObjectType *)MoveObjectToBuffer (PCB->Data, RemoveList, type, ptr1, ptr2, ptr3);
811 if (Entry->Kind == POLYGON_TYPE)
812 InitClip (PCB->Data, (LayerType *)ptr1b, (PolygonType *)obj);
813 return (true);
816 /* ---------------------------------------------------------------------------
817 * recovers an removed polygon point
818 * returns true on success
820 static bool
821 UndoRemoveContour (UndoListType *Entry)
823 assert (Entry->Kind == POLYGON_TYPE);
824 return UndoSwapCopiedObject (Entry);
827 /* ---------------------------------------------------------------------------
828 * recovers an inserted polygon point
829 * returns true on success
831 static bool
832 UndoInsertContour (UndoListType *Entry)
834 assert (Entry->Kind == POLYGON_TYPE);
835 return UndoSwapCopiedObject (Entry);
838 /* ---------------------------------------------------------------------------
839 * undo a layer change
840 * returns true on success
842 static bool
843 UndoLayerChange (UndoListType *Entry)
845 LayerChangeType *l = &Entry->Data.LayerChange;
846 int tmp;
848 tmp = l->new_index;
849 l->new_index = l->old_index;
850 l->old_index = tmp;
852 if (MoveLayer (l->old_index, l->new_index))
853 return false;
854 else
855 return true;
858 /* ---------------------------------------------------------------------------
859 * undo a netlist change
860 * returns true on success
862 static bool
863 UndoNetlistChange (UndoListType *Entry)
865 NetlistChangeType *l = & Entry->Data.NetlistChange;
866 unsigned int i, j;
867 LibraryType *lib, *saved;
869 lib = l->lib;
870 saved = l->old;
872 /* iterate over each net */
873 for (i = 0 ; i < lib->MenuN; i++)
875 if (lib->Menu[i].Name)
876 free (lib->Menu[i].Name);
878 if (lib->Menu[i].directory)
879 free (lib->Menu[i].directory);
881 if (lib->Menu[i].Style)
882 free (lib->Menu[i].Style);
884 /* iterate over each pin on the net */
885 for (j = 0; j < lib->Menu[i].EntryN; j++) {
887 if (lib->Menu[i].Entry[j].ListEntry)
888 free (lib->Menu[i].Entry[j].ListEntry);
890 if (lib->Menu[i].Entry[j].AllocatedMemory)
891 free (lib->Menu[i].Entry[j].AllocatedMemory);
893 if (lib->Menu[i].Entry[j].Template)
894 free (lib->Menu[i].Entry[j].Template);
896 if (lib->Menu[i].Entry[j].Package)
897 free (lib->Menu[i].Entry[j].Package);
899 if (lib->Menu[i].Entry[j].Value)
900 free (lib->Menu[i].Entry[j].Value);
902 if (lib->Menu[i].Entry[j].Description)
903 free (lib->Menu[i].Entry[j].Description);
908 if (lib->Menu)
909 free (lib->Menu);
911 *lib = *saved;
913 NetlistChanged (0);
914 return true;
917 /* ---------------------------------------------------------------------------
918 * undo of any 'hard to recover' operation
920 * returns the bitfield for the types of operations that were undone
923 Undo (bool draw)
925 UndoListType *ptr;
926 int Types = 0;
927 int unique;
928 bool error_undoing = false;
930 unique = TEST_FLAG (UNIQUENAMEFLAG, PCB);
931 CLEAR_FLAG (UNIQUENAMEFLAG, PCB);
933 andDraw = draw;
935 if (Serial == 0)
937 Message (_("ERROR: Attempt to Undo() with Serial == 0\n"
938 " Please save your work and report this bug.\n"));
939 return 0;
942 if (UndoN == 0)
944 Message (_("Nothing to undo - buffer is empty\n"));
945 return 0;
948 Serial --;
950 ptr = &UndoList[UndoN - 1];
952 if (ptr->Serial > Serial)
954 Message (_("ERROR: Bad undo serial number %d in undo stack - expecting %d or lower\n"
955 " Please save your work and report this bug.\n"),
956 ptr->Serial, Serial);
958 /* It is likely that the serial number got corrupted through some bad
959 * use of the SaveUndoSerialNumber() / RestoreUndoSerialNumber() APIs.
961 * Reset the serial number to be consistent with that of the last
962 * operation on the undo stack in the hope that this might clear
963 * the problem and allow the user to hit Undo again.
965 Serial = ptr->Serial + 1;
966 return 0;
969 LockUndo (); /* lock undo module to prevent from loops */
971 /* Loop over all entries with the correct serial number */
972 for (; UndoN && ptr->Serial == Serial; ptr--, UndoN--, RedoN++)
974 int undid = PerformUndo (ptr);
975 if (undid == 0)
976 error_undoing = true;
977 Types |= undid;
980 UnlockUndo ();
982 if (error_undoing)
983 Message (_("ERROR: Failed to undo some operations\n"));
985 if (Types && andDraw)
986 Draw ();
988 /* restore the unique flag setting */
989 if (unique)
990 SET_FLAG (UNIQUENAMEFLAG, PCB);
992 return Types;
995 static int
996 PerformUndo (UndoListType *ptr)
998 switch (ptr->Type)
1000 case UNDO_CHANGENAME:
1001 if (UndoChangeName (ptr))
1002 return (UNDO_CHANGENAME);
1003 break;
1005 case UNDO_CREATE:
1006 if (UndoCopyOrCreate (ptr))
1007 return (UNDO_CREATE);
1008 break;
1010 case UNDO_MOVE:
1011 if (UndoMove (ptr))
1012 return (UNDO_MOVE);
1013 break;
1015 case UNDO_REMOVE:
1016 if (UndoRemove (ptr))
1017 return (UNDO_REMOVE);
1018 break;
1020 case UNDO_REMOVE_POINT:
1021 if (UndoRemovePoint (ptr))
1022 return (UNDO_REMOVE_POINT);
1023 break;
1025 case UNDO_INSERT_POINT:
1026 if (UndoInsertPoint (ptr))
1027 return (UNDO_INSERT_POINT);
1028 break;
1030 case UNDO_REMOVE_CONTOUR:
1031 if (UndoRemoveContour (ptr))
1032 return (UNDO_REMOVE_CONTOUR);
1033 break;
1035 case UNDO_INSERT_CONTOUR:
1036 if (UndoInsertContour (ptr))
1037 return (UNDO_INSERT_CONTOUR);
1038 break;
1040 case UNDO_ROTATE:
1041 if (UndoRotate (ptr))
1042 return (UNDO_ROTATE);
1043 break;
1045 case UNDO_CLEAR:
1046 if (UndoClearPoly (ptr))
1047 return (UNDO_CLEAR);
1048 break;
1050 case UNDO_MOVETOLAYER:
1051 if (UndoMoveToLayer (ptr))
1052 return (UNDO_MOVETOLAYER);
1053 break;
1055 case UNDO_FLAG:
1056 if (UndoFlag (ptr))
1057 return (UNDO_FLAG);
1058 break;
1060 case UNDO_CHANGESIZE:
1061 if (UndoChangeSize (ptr))
1062 return (UNDO_CHANGESIZE);
1063 break;
1065 case UNDO_CHANGECLEARSIZE:
1066 if (UndoChangeClearSize (ptr))
1067 return (UNDO_CHANGECLEARSIZE);
1068 break;
1070 case UNDO_CHANGEMASKSIZE:
1071 if (UndoChangeMaskSize (ptr))
1072 return (UNDO_CHANGEMASKSIZE);
1073 break;
1075 case UNDO_CHANGE2NDSIZE:
1076 if (UndoChange2ndSize (ptr))
1077 return (UNDO_CHANGE2NDSIZE);
1078 break;
1080 case UNDO_CHANGEANGLES:
1081 if (UndoChangeAngles (ptr))
1082 return (UNDO_CHANGEANGLES);
1083 break;
1085 case UNDO_LAYERCHANGE:
1086 if (UndoLayerChange (ptr))
1087 return (UNDO_LAYERCHANGE);
1088 break;
1090 case UNDO_NETLISTCHANGE:
1091 if (UndoNetlistChange (ptr))
1092 return (UNDO_NETLISTCHANGE);
1093 break;
1095 case UNDO_MIRROR:
1096 if (UndoMirror (ptr))
1097 return (UNDO_MIRROR);
1098 break;
1100 return 0;
1103 /* ---------------------------------------------------------------------------
1104 * redo of any 'hard to recover' operation
1106 * returns the number of operations redone
1109 Redo (bool draw)
1111 UndoListType *ptr;
1112 int Types = 0;
1113 bool error_undoing = false;
1115 andDraw = draw;
1117 if (RedoN == 0)
1119 Message (_("Nothing to redo. Perhaps changes have been made since last undo\n"));
1120 return 0;
1123 ptr = &UndoList[UndoN];
1125 if (ptr->Serial < Serial)
1127 Message (_("ERROR: Bad undo serial number %d in redo stack - expecting %d or higher\n"
1128 " Please save your work and report this bug.\n"),
1129 ptr->Serial, Serial);
1131 /* It is likely that the serial number got corrupted through some bad
1132 * use of the SaveUndoSerialNumber() / RestoreUndoSerialNumber() APIs.
1134 * Reset the serial number to be consistent with that of the first
1135 * operation on the redo stack in the hope that this might clear
1136 * the problem and allow the user to hit Redo again.
1138 Serial = ptr->Serial;
1139 return 0;
1142 LockUndo (); /* lock undo module to prevent from loops */
1144 /* and loop over all entries with the correct serial number */
1145 for (; RedoN && ptr->Serial == Serial; ptr++, UndoN++, RedoN--)
1147 int undid = PerformUndo (ptr);
1148 if (undid == 0)
1149 error_undoing = true;
1150 Types |= undid;
1153 /* Make next serial number current */
1154 Serial++;
1156 UnlockUndo ();
1158 if (error_undoing)
1159 Message (_("ERROR: Failed to redo some operations\n"));
1161 if (Types && andDraw)
1162 Draw ();
1164 return Types;
1167 /* ---------------------------------------------------------------------------
1168 * restores the serial number of the undo list
1170 void
1171 RestoreUndoSerialNumber (void)
1173 if (added_undo_between_increment_and_restore)
1174 Message (_("ERROR: Operations were added to the Undo stack with an incorrect serial number\n"));
1175 between_increment_and_restore = false;
1176 added_undo_between_increment_and_restore = false;
1177 Serial = SavedSerial;
1180 /* ---------------------------------------------------------------------------
1181 * saves the serial number of the undo list
1183 void
1184 SaveUndoSerialNumber (void)
1186 Bumped = false;
1187 between_increment_and_restore = false;
1188 added_undo_between_increment_and_restore = false;
1189 SavedSerial = Serial;
1192 /* ---------------------------------------------------------------------------
1193 * increments the serial number of the undo list
1194 * it's not done automatically because some operations perform more
1195 * than one request with the same serial #
1197 void
1198 IncrementUndoSerialNumber (void)
1200 if (!Locked)
1202 /* Set the changed flag if anything was added prior to this bump */
1203 if (UndoN > 0 && UndoList[UndoN - 1].Serial == Serial)
1204 SetChangedFlag (true);
1205 Serial++;
1206 Bumped = true;
1207 between_increment_and_restore = true;
1211 /* ---------------------------------------------------------------------------
1212 * releases memory of the undo- and remove list
1214 void
1215 ClearUndoList (bool Force)
1217 UndoListType *undo;
1219 if (UndoN
1220 && (Force || gui->confirm_dialog ("OK to clear 'undo' buffer?", 0)))
1222 /* release memory allocated by objects in undo list */
1223 for (undo = UndoList; UndoN; undo++, UndoN--)
1225 if (undo->Type == UNDO_CHANGENAME)
1226 free (undo->Data.ChangeName.Name);
1228 free (UndoList);
1229 UndoList = NULL;
1230 if (RemoveList)
1232 FreeDataMemory (RemoveList);
1233 free (RemoveList);
1234 RemoveList = NULL;
1237 /* reset some counters */
1238 UndoN = UndoMax = RedoN = 0;
1241 /* reset counter in any case */
1242 Serial = 1;
1245 /* ---------------------------------------------------------------------------
1246 * adds an object to the list of clearpoly objects
1248 void
1249 AddObjectToClearPolyUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
1250 bool clear)
1252 UndoListType *undo;
1254 if (!Locked)
1256 undo = GetUndoSlot (UNDO_CLEAR, OBJECT_ID (Ptr3), Type);
1257 undo->Data.ClearPoly.Clear = clear;
1258 undo->Data.ClearPoly.Layer = (LayerType *) Ptr1;
1262 /* ---------------------------------------------------------------------------
1263 * adds an object to the list of mirrored objects
1265 void
1266 AddObjectToMirrorUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
1267 Coord yoff)
1269 UndoListType *undo;
1271 if (!Locked)
1273 undo = GetUndoSlot (UNDO_MIRROR, OBJECT_ID (Ptr3), Type);
1274 undo->Data.Move.DY = yoff;
1278 /* ---------------------------------------------------------------------------
1279 * adds an object to the list of rotated objects
1281 void
1282 AddObjectToRotateUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
1283 Coord CenterX, Coord CenterY,
1284 BYTE Steps)
1286 UndoListType *undo;
1288 if (!Locked)
1290 undo = GetUndoSlot (UNDO_ROTATE, OBJECT_ID (Ptr3), Type);
1291 undo->Data.Rotate.CenterX = CenterX;
1292 undo->Data.Rotate.CenterY = CenterY;
1293 undo->Data.Rotate.Steps = Steps;
1297 /* ---------------------------------------------------------------------------
1298 * adds an object to the list of removed objects and removes it from
1299 * the current PCB
1301 void
1302 MoveObjectToRemoveUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1304 if (Locked)
1305 return;
1307 if (!RemoveList)
1308 RemoveList = CreateNewBuffer ();
1310 GetUndoSlot (UNDO_REMOVE, OBJECT_ID (Ptr3), Type);
1311 MoveObjectToBuffer (RemoveList, PCB->Data, Type, Ptr1, Ptr2, Ptr3);
1314 /* ---------------------------------------------------------------------------
1315 * adds an object to the list of removed polygon/... points
1317 void
1318 AddObjectToRemovePointUndoList (int Type,
1319 void *Ptr1, void *Ptr2, Cardinal index)
1321 UndoListType *undo;
1322 PolygonType *polygon = (PolygonType *) Ptr2;
1323 Cardinal hole;
1324 bool last_in_contour = false;
1326 if (!Locked)
1328 switch (Type)
1330 case POLYGONPOINT_TYPE:
1332 /* save the ID of the parent object; else it will be
1333 * impossible to recover the point
1335 undo =
1336 GetUndoSlot (UNDO_REMOVE_POINT, OBJECT_ID (polygon),
1337 POLYGON_TYPE);
1338 undo->Data.RemovedPoint.X = polygon->Points[index].X;
1339 undo->Data.RemovedPoint.Y = polygon->Points[index].Y;
1340 undo->Data.RemovedPoint.ID = polygon->Points[index].ID;
1341 undo->Data.RemovedPoint.Index = index;
1343 /* Check whether this point was at the end of its contour.
1344 * If so, we need to flag as such when re-adding the point
1345 * so it goes back in the correct place
1347 for (hole = 0; hole < polygon->HoleIndexN; hole++)
1348 if (index == polygon->HoleIndex[hole] - 1)
1349 last_in_contour = true;
1350 if (index == polygon->PointN - 1)
1351 last_in_contour = true;
1352 undo->Data.RemovedPoint.last_in_contour = last_in_contour;
1354 break;
1359 /* ---------------------------------------------------------------------------
1360 * adds an object to the list of inserted polygon/... points
1362 void
1363 AddObjectToInsertPointUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1365 if (!Locked)
1366 GetUndoSlot (UNDO_INSERT_POINT, OBJECT_ID (Ptr3), Type);
1369 static void
1370 CopyObjectToUndoList (int undo_type, int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1372 UndoListType *undo;
1373 AnyObjectType *copy;
1375 if (Locked)
1376 return;
1378 if (!RemoveList)
1379 RemoveList = CreateNewBuffer ();
1381 undo = GetUndoSlot (undo_type, OBJECT_ID (Ptr2), Type);
1382 copy = (AnyObjectType *)CopyObjectToBuffer (RemoveList, PCB->Data, Type, Ptr1, Ptr2, Ptr3);
1383 undo->Data.CopyID = copy->ID;
1386 /* ---------------------------------------------------------------------------
1387 * adds an object to the list of removed contours
1388 * (Actually just takes a copy of the whole polygon to restore)
1390 void
1391 AddObjectToRemoveContourUndoList (int Type,
1392 LayerType *Layer, PolygonType *Polygon)
1394 CopyObjectToUndoList (UNDO_REMOVE_CONTOUR, Type, Layer, Polygon, NULL);
1397 /* ---------------------------------------------------------------------------
1398 * adds an object to the list of insert contours
1399 * (Actually just takes a copy of the whole polygon to restore)
1401 void
1402 AddObjectToInsertContourUndoList (int Type,
1403 LayerType *Layer, PolygonType *Polygon)
1405 CopyObjectToUndoList (UNDO_INSERT_CONTOUR, Type, Layer, Polygon, NULL);
1408 /* ---------------------------------------------------------------------------
1409 * adds an object to the list of moved objects
1411 void
1412 AddObjectToMoveUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
1413 Coord DX, Coord DY)
1415 UndoListType *undo;
1417 if (!Locked)
1419 undo = GetUndoSlot (UNDO_MOVE, OBJECT_ID (Ptr3), Type);
1420 undo->Data.Move.DX = DX;
1421 undo->Data.Move.DY = DY;
1425 /* ---------------------------------------------------------------------------
1426 * adds an object to the list of objects with changed names
1428 void
1429 AddObjectToChangeNameUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
1430 char *OldName)
1432 UndoListType *undo;
1434 if (!Locked)
1436 undo = GetUndoSlot (UNDO_CHANGENAME, OBJECT_ID (Ptr3), Type);
1437 undo->Data.ChangeName.Name = OldName;
1441 /* ---------------------------------------------------------------------------
1442 * adds an object to the list of objects moved to another layer
1444 void
1445 AddObjectToMoveToLayerUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1447 UndoListType *undo;
1449 if (!Locked)
1451 undo = GetUndoSlot (UNDO_MOVETOLAYER, OBJECT_ID (Ptr3), Type);
1452 undo->Data.MoveToLayer.OriginalLayer =
1453 GetLayerNumber (PCB->Data, (LayerType *) Ptr1);
1457 /* ---------------------------------------------------------------------------
1458 * adds an object to the list of created objects
1460 void
1461 AddObjectToCreateUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1463 if (!Locked)
1464 GetUndoSlot (UNDO_CREATE, OBJECT_ID (Ptr3), Type);
1465 ClearFromPolygon (PCB->Data, Type, Ptr1, Ptr2);
1468 /* ---------------------------------------------------------------------------
1469 * adds an object to the list of objects with flags changed
1471 void
1472 AddObjectToFlagUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1474 UndoListType *undo;
1476 if (!Locked)
1478 undo = GetUndoSlot (UNDO_FLAG, OBJECT_ID (Ptr2), Type);
1479 undo->Data.Flags = ((PinType *) Ptr2)->Flags;
1483 /* ---------------------------------------------------------------------------
1484 * adds an object to the list of objects with Size changes
1486 void
1487 AddObjectToSizeUndoList (int Type, void *ptr1, void *ptr2, void *ptr3)
1489 UndoListType *undo;
1491 if (!Locked)
1493 undo = GetUndoSlot (UNDO_CHANGESIZE, OBJECT_ID (ptr2), Type);
1494 switch (Type)
1496 case PIN_TYPE:
1497 case VIA_TYPE:
1498 undo->Data.Size = ((PinType *) ptr2)->Thickness;
1499 break;
1500 case LINE_TYPE:
1501 case ELEMENTLINE_TYPE:
1502 undo->Data.Size = ((LineType *) ptr2)->Thickness;
1503 break;
1504 case TEXT_TYPE:
1505 case ELEMENTNAME_TYPE:
1506 undo->Data.Size = ((TextType *) ptr2)->Scale;
1507 break;
1508 case PAD_TYPE:
1509 undo->Data.Size = ((PadType *) ptr2)->Thickness;
1510 break;
1511 case ARC_TYPE:
1512 case ELEMENTARC_TYPE:
1513 undo->Data.Size = ((ArcType *) ptr2)->Thickness;
1514 break;
1519 /* ---------------------------------------------------------------------------
1520 * adds an object to the list of objects with Size changes
1522 void
1523 AddObjectToClearSizeUndoList (int Type, void *ptr1, void *ptr2, void *ptr3)
1525 UndoListType *undo;
1527 if (!Locked)
1529 undo = GetUndoSlot (UNDO_CHANGECLEARSIZE, OBJECT_ID (ptr2), Type);
1530 switch (Type)
1532 case PIN_TYPE:
1533 case VIA_TYPE:
1534 undo->Data.Size = ((PinType *) ptr2)->Clearance;
1535 break;
1536 case LINE_TYPE:
1537 undo->Data.Size = ((LineType *) ptr2)->Clearance;
1538 break;
1539 case PAD_TYPE:
1540 undo->Data.Size = ((PadType *) ptr2)->Clearance;
1541 break;
1542 case ARC_TYPE:
1543 undo->Data.Size = ((ArcType *) ptr2)->Clearance;
1544 break;
1549 /* ---------------------------------------------------------------------------
1550 * adds an object to the list of objects with Size changes
1552 void
1553 AddObjectToMaskSizeUndoList (int Type, void *ptr1, void *ptr2, void *ptr3)
1555 UndoListType *undo;
1557 if (!Locked)
1559 undo = GetUndoSlot (UNDO_CHANGEMASKSIZE, OBJECT_ID (ptr2), Type);
1560 switch (Type)
1562 case PIN_TYPE:
1563 case VIA_TYPE:
1564 undo->Data.Size = ((PinType *) ptr2)->Mask;
1565 break;
1566 case PAD_TYPE:
1567 undo->Data.Size = ((PadType *) ptr2)->Mask;
1568 break;
1573 /* ---------------------------------------------------------------------------
1574 * adds an object to the list of objects with 2ndSize changes
1576 void
1577 AddObjectTo2ndSizeUndoList (int Type, void *ptr1, void *ptr2, void *ptr3)
1579 UndoListType *undo;
1581 if (!Locked)
1583 undo = GetUndoSlot (UNDO_CHANGE2NDSIZE, OBJECT_ID (ptr2), Type);
1584 if (Type == PIN_TYPE || Type == VIA_TYPE)
1585 undo->Data.Size = ((PinType *) ptr2)->DrillingHole;
1589 /* ---------------------------------------------------------------------------
1590 * adds an object to the list of changed angles. Note that you must
1591 * call this before changing the angles, passing the new start/delta.
1593 void
1594 AddObjectToChangeAnglesUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1596 UndoListType *undo;
1597 ArcType *a = (ArcType *) Ptr3;
1599 if (!Locked)
1601 undo = GetUndoSlot (UNDO_CHANGEANGLES, OBJECT_ID (Ptr3), Type);
1602 undo->Data.Move.DX = a->StartAngle;
1603 undo->Data.Move.DY = a->Delta;
1607 /* ---------------------------------------------------------------------------
1608 * adds a layer change (new, delete, move) to the undo list.
1610 void
1611 AddLayerChangeToUndoList (int old_index, int new_index)
1613 UndoListType *undo;
1615 if (!Locked)
1617 undo = GetUndoSlot (UNDO_LAYERCHANGE, 0, 0);
1618 undo->Data.LayerChange.old_index = old_index;
1619 undo->Data.LayerChange.new_index = new_index;
1623 /* ---------------------------------------------------------------------------
1624 * adds a netlist change to the undo list
1626 void
1627 AddNetlistLibToUndoList (LibraryType *lib)
1629 UndoListType *undo;
1630 unsigned int i, j;
1631 LibraryType *old;
1633 if (!Locked)
1635 undo = GetUndoSlot (UNDO_NETLISTCHANGE, 0, 0);
1636 /* keep track of where the data needs to go */
1637 undo->Data.NetlistChange.lib = lib;
1639 /* and what the old data is that we'll need to restore */
1640 undo->Data.NetlistChange.old = (LibraryType *)malloc (sizeof (LibraryType));
1641 old = undo->Data.NetlistChange.old;
1642 old->MenuN = lib->MenuN;
1643 old->MenuMax = lib->MenuMax;
1644 old->Menu = (LibraryMenuType *)malloc (old->MenuMax * sizeof (LibraryMenuType));
1645 if (old->Menu == NULL)
1647 fprintf (stderr, "malloc() failed in %s\n", __FUNCTION__);
1648 exit (1);
1651 /* iterate over each net */
1652 for (i = 0 ; i < lib->MenuN; i++)
1654 old->Menu[i].EntryN = lib->Menu[i].EntryN;
1655 old->Menu[i].EntryMax = lib->Menu[i].EntryMax;
1657 old->Menu[i].Name =
1658 lib->Menu[i].Name ? strdup (lib->Menu[i].Name) : NULL;
1660 old->Menu[i].directory =
1661 lib->Menu[i].directory ? strdup (lib->Menu[i].directory) : NULL;
1663 old->Menu[i].Style =
1664 lib->Menu[i].Style ? strdup (lib->Menu[i].Style) : NULL;
1667 old->Menu[i].Entry =
1668 (LibraryEntryType *)malloc (old->Menu[i].EntryMax * sizeof (LibraryEntryType));
1669 if (old->Menu[i].Entry == NULL)
1671 fprintf (stderr, "malloc() failed in %s\n", __FUNCTION__);
1672 exit (1);
1675 /* iterate over each pin on the net */
1676 for (j = 0; j < lib->Menu[i].EntryN; j++) {
1678 old->Menu[i].Entry[j].ListEntry =
1679 lib->Menu[i].Entry[j].ListEntry ?
1680 strdup (lib->Menu[i].Entry[j].ListEntry) :
1681 NULL;
1683 old->Menu[i].Entry[j].AllocatedMemory =
1684 lib->Menu[i].Entry[j].AllocatedMemory ?
1685 strdup (lib->Menu[i].Entry[j].AllocatedMemory) :
1686 NULL;
1688 old->Menu[i].Entry[j].Template =
1689 lib->Menu[i].Entry[j].Template ?
1690 strdup (lib->Menu[i].Entry[j].Template) :
1691 NULL;
1693 old->Menu[i].Entry[j].Package =
1694 lib->Menu[i].Entry[j].Package ?
1695 strdup (lib->Menu[i].Entry[j].Package) :
1696 NULL;
1698 old->Menu[i].Entry[j].Value =
1699 lib->Menu[i].Entry[j].Value ?
1700 strdup (lib->Menu[i].Entry[j].Value) :
1701 NULL;
1703 old->Menu[i].Entry[j].Description =
1704 lib->Menu[i].Entry[j].Description ?
1705 strdup (lib->Menu[i].Entry[j].Description) :
1706 NULL;
1715 /* ---------------------------------------------------------------------------
1716 * set lock flag
1718 void
1719 LockUndo (void)
1721 Locked = true;
1724 /* ---------------------------------------------------------------------------
1725 * reset lock flag
1727 void
1728 UnlockUndo (void)
1730 Locked = false;
1733 /* ---------------------------------------------------------------------------
1734 * return undo lock state
1736 bool
1737 Undoing (void)
1739 return (Locked);