Introduce POLYGONHOLE_MODE for creating holes in polygons
[geda-pcb/gde.git] / src / undo.c
blob68ea8ff624172c6f28346ab5a10794638219d8df
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) MyRealloc (UndoList, size,
227 "AddCommandToUndoList()");
228 memset (&UndoList[UndoN], 0, STEP_REMOVELIST * sizeof (UndoListType));
230 /* ask user to flush the table because of it's size */
231 if (size > limit)
233 limit = (size / UNDO_WARNING_SIZE + 1) * UNDO_WARNING_SIZE;
234 Message (_("Size of 'undo-list' exceeds %li kb\n"),
235 (long) (size >> 10));
239 /* free structures from the pruned redo list */
241 for (ptr = &UndoList[UndoN]; RedoN; ptr++, RedoN--)
242 switch (ptr->Type)
244 case UNDO_CHANGENAME:
245 SaveFree (ptr->Data.ChangeName.Name);
246 break;
247 case UNDO_REMOVE:
248 type =
249 SearchObjectByID (RemoveList, &ptr1, &ptr2, &ptr3, ptr->ID,
250 ptr->Kind);
251 if (type != NO_TYPE)
253 DestroyObject (RemoveList, type, ptr1, ptr2, ptr3);
255 break;
256 default:
257 break;
260 /* copy typefield and serial number to the list */
261 ptr = &UndoList[UndoN++];
262 ptr->Type = CommandType;
263 ptr->Kind = Kind;
264 ptr->ID = ID;
265 ptr->Serial = Serial;
266 return (ptr);
269 /* ---------------------------------------------------------------------------
270 * redraws the recovered object
272 static void
273 DrawRecoveredObject (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
275 if (Type & (LINE_TYPE | TEXT_TYPE | POLYGON_TYPE | ARC_TYPE))
277 LayerTypePtr layer;
279 layer = LAYER_PTR (GetLayerNumber (RemoveList, (LayerTypePtr) Ptr1));
280 DrawObject (Type, (void *) layer, Ptr2, 0);
282 else
283 DrawObject (Type, Ptr1, Ptr2, 0);
286 /* ---------------------------------------------------------------------------
287 * recovers an object from a 'rotate' operation
288 * returns true if anything has been recovered
290 static bool
291 UndoRotate (UndoListTypePtr Entry)
293 void *ptr1, *ptr2, *ptr3;
294 int type;
296 /* lookup entry by it's ID */
297 type =
298 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
299 if (type != NO_TYPE)
301 if (TEST_FLAG (LOCKFLAG, (ArcTypePtr) ptr2))
302 return (false);
303 RotateObject (type, ptr1, ptr2, ptr3,
304 Entry->Data.Rotate.CenterX, Entry->Data.Rotate.CenterY,
305 (4 - Entry->Data.Rotate.Steps) & 0x03);
306 Entry->Data.Rotate.Steps = (4 - Entry->Data.Rotate.Steps) & 0x03;
307 return (true);
309 return (false);
312 /* ---------------------------------------------------------------------------
313 * recovers an object from a clear/restore poly operation
314 * returns true if anything has been recovered
316 static bool
317 UndoClearPoly (UndoListTypePtr Entry)
319 void *ptr1, *ptr2, *ptr3;
320 int type;
322 type =
323 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
324 if (type != NO_TYPE)
326 if (Entry->Data.ClearPoly.Clear)
327 RestoreToPolygon (PCB->Data, type, Entry->Data.ClearPoly.Layer, ptr3);
328 else
329 ClearFromPolygon (PCB->Data, type, Entry->Data.ClearPoly.Layer, ptr3);
330 Entry->Data.ClearPoly.Clear = !Entry->Data.ClearPoly.Clear;
331 return true;
333 return false;
336 /* ---------------------------------------------------------------------------
337 * recovers an object from a 'change name' operation
338 * returns true if anything has been recovered
340 static bool
341 UndoChangeName (UndoListTypePtr Entry)
343 void *ptr1, *ptr2, *ptr3;
344 int type;
346 /* lookup entry by it's ID */
347 type =
348 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
349 if (type != NO_TYPE)
351 if (TEST_FLAG (LOCKFLAG, (TextTypePtr) ptr3))
352 return (false);
353 Entry->Data.ChangeName.Name =
354 (ChangeObjectName (type, ptr1, ptr2, ptr3,
355 Entry->Data.ChangeName.Name));
356 return (true);
358 return (false);
361 /* ---------------------------------------------------------------------------
362 * recovers an object from a 2ndSize change operation
364 static bool
365 UndoChange2ndSize (UndoListTypePtr Entry)
367 void *ptr1, *ptr2, *ptr3;
368 int type;
369 BDimension swap;
371 /* lookup entry by ID */
372 type =
373 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
374 if (type != NO_TYPE)
376 if (TEST_FLAG (LOCKFLAG, (PinTypePtr) ptr2))
377 return (false);
378 swap = ((PinTypePtr) ptr2)->DrillingHole;
379 if (andDraw)
380 EraseObject (type, ptr1, ptr2);
381 ((PinTypePtr) ptr2)->DrillingHole = Entry->Data.Size;
382 Entry->Data.Size = swap;
383 DrawObject (type, ptr1, ptr2, 0);
384 return (true);
386 return (false);
389 /* ---------------------------------------------------------------------------
390 * recovers an object from a ChangeAngles change operation
392 static bool
393 UndoChangeAngles (UndoListTypePtr Entry)
395 void *ptr1, *ptr2, *ptr3;
396 int type;
397 long int old_sa, old_da;
399 /* lookup entry by ID */
400 type =
401 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
402 if (type == ARC_TYPE)
404 LayerTypePtr Layer = (LayerTypePtr) ptr1;
405 ArcTypePtr a = (ArcTypePtr) ptr2;
406 if (TEST_FLAG (LOCKFLAG, a))
407 return (false);
408 r_delete_entry (Layer->arc_tree, (BoxTypePtr) a);
409 old_sa = a->StartAngle;
410 old_da = a->Delta;
411 if (andDraw)
412 EraseObject (type, Layer, a);
413 a->StartAngle = Entry->Data.Move.DX;
414 a->Delta = Entry->Data.Move.DY;
415 SetArcBoundingBox (a);
416 r_insert_entry (Layer->arc_tree, (BoxTypePtr) a, 0);
417 Entry->Data.Move.DX = old_sa;
418 Entry->Data.Move.DY = old_da;;
419 DrawObject (type, ptr1, a, 0);
420 return (true);
422 return (false);
425 /* ---------------------------------------------------------------------------
426 * recovers an object from a clearance size change operation
428 static bool
429 UndoChangeClearSize (UndoListTypePtr Entry)
431 void *ptr1, *ptr2, *ptr3;
432 int type;
433 BDimension swap;
435 /* lookup entry by ID */
436 type =
437 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
438 if (type != NO_TYPE)
440 if (TEST_FLAG (LOCKFLAG, (LineTypePtr) ptr2))
441 return (false);
442 swap = ((PinTypePtr) ptr2)->Clearance;
443 RestoreToPolygon (PCB->Data, type, ptr1, ptr2);
444 if (andDraw)
445 EraseObject (type, ptr1, ptr2);
446 ((PinTypePtr) ptr2)->Clearance = Entry->Data.Size;
447 ClearFromPolygon (PCB->Data, type, ptr1, ptr2);
448 Entry->Data.Size = swap;
449 if (andDraw)
450 DrawObject (type, ptr1, ptr2, 0);
451 return (true);
453 return (false);
456 /* ---------------------------------------------------------------------------
457 * recovers an object from a mask size change operation
459 static bool
460 UndoChangeMaskSize (UndoListTypePtr Entry)
462 void *ptr1, *ptr2, *ptr3;
463 int type;
464 BDimension swap;
466 /* lookup entry by ID */
467 type =
468 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
469 if (type & (VIA_TYPE | PIN_TYPE | PAD_TYPE))
471 if (TEST_FLAG (LOCKFLAG, (PinTypePtr) ptr2))
472 return (false);
473 swap =
474 (type ==
475 PAD_TYPE ? ((PadTypePtr) ptr2)->Mask : ((PinTypePtr) ptr2)->Mask);
476 if (andDraw)
477 EraseObject (type, ptr1, ptr2);
478 if (type == PAD_TYPE)
479 ((PadTypePtr) ptr2)->Mask = Entry->Data.Size;
480 else
481 ((PinTypePtr) ptr2)->Mask = Entry->Data.Size;
482 Entry->Data.Size = swap;
483 if (andDraw)
484 DrawObject (type, ptr1, ptr2, 0);
485 return (true);
487 return (false);
491 /* ---------------------------------------------------------------------------
492 * recovers an object from a Size change operation
494 static bool
495 UndoChangeSize (UndoListTypePtr Entry)
497 void *ptr1, *ptr2, *ptr3;
498 int type;
499 BDimension swap;
501 /* lookup entry by ID */
502 type =
503 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
504 if (type != NO_TYPE)
506 if (TEST_FLAG (LOCKFLAG, (PinTypePtr) ptr2))
507 return (false);
508 /* Wow! can any object be treated as a pin type for size change?? */
509 /* pins, vias, lines, and arcs can. Text can't but it has it's own mechanism */
510 swap = ((PinTypePtr) ptr2)->Thickness;
511 RestoreToPolygon (PCB->Data, type, ptr1, ptr2);
512 if (andDraw)
513 EraseObject (type, ptr1, ptr2);
514 ((PinTypePtr) ptr2)->Thickness = Entry->Data.Size;
515 Entry->Data.Size = swap;
516 ClearFromPolygon (PCB->Data, type, ptr1, ptr2);
517 if (andDraw)
518 DrawObject (type, ptr1, ptr2, 0);
519 return (true);
521 return (false);
524 /* ---------------------------------------------------------------------------
525 * recovers an object from a FLAG change operation
527 static bool
528 UndoFlag (UndoListTypePtr Entry)
530 void *ptr1, *ptr2, *ptr3;
531 int type;
532 FlagType swap;
533 int must_redraw;
535 /* lookup entry by ID */
536 type =
537 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
538 if (type != NO_TYPE)
540 FlagType f1, f2;
541 PinTypePtr pin = (PinTypePtr) ptr2;
543 if (TEST_FLAG (LOCKFLAG, pin))
544 return (false);
546 swap = pin->Flags;
548 must_redraw = 0;
549 f1 = MaskFlags (pin->Flags, ~DRAW_FLAGS);
550 f2 = MaskFlags (Entry->Data.Flags, ~DRAW_FLAGS);
552 if (!FLAGS_EQUAL (f1, f2))
553 must_redraw = 1;
555 if (andDraw && must_redraw)
556 EraseObject (type, ptr1, ptr2);
558 pin->Flags = Entry->Data.Flags;
560 Entry->Data.Flags = swap;
562 if (andDraw && must_redraw)
563 DrawObject (type, ptr1, ptr2, 0);
564 return (true);
566 Message ("hace Internal error: Can't find ID %d type %08x\n", Entry->ID,
567 Entry->Kind);
568 Message ("for UndoFlag Operation. Previous flags: %s\n",
569 flags_to_string (Entry->Data.Flags, 0));
570 return (false);
573 /* ---------------------------------------------------------------------------
574 * recovers an object from a mirror operation
575 * returns true if anything has been recovered
577 static bool
578 UndoMirror (UndoListTypePtr Entry)
580 void *ptr1, *ptr2, *ptr3;
581 int type;
583 /* lookup entry by ID */
584 type =
585 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
586 if (type == ELEMENT_TYPE)
588 ElementTypePtr element = (ElementTypePtr) ptr3;
589 if (TEST_FLAG (LOCKFLAG, element))
590 return (false);
591 if (andDraw)
592 EraseElement (element);
593 MirrorElementCoordinates (PCB->Data, element, Entry->Data.Move.DY);
594 if (andDraw)
595 DrawElement (element, 0);
596 return (true);
598 Message ("hace Internal error: UndoMirror on object type %d\n", type);
599 return (false);
602 /* ---------------------------------------------------------------------------
603 * recovers an object from a 'copy' or 'create' operation
604 * returns true if anything has been recovered
606 static bool
607 UndoCopyOrCreate (UndoListTypePtr Entry)
609 void *ptr1, *ptr2, *ptr3;
610 int type;
612 /* lookup entry by it's ID */
613 type =
614 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
615 if (type != NO_TYPE)
617 if (TEST_FLAG (LOCKFLAG, (PinTypePtr) ptr2))
618 return (false);
619 if (!RemoveList)
620 RemoveList = CreateNewBuffer ();
621 if (andDraw)
622 EraseObject (type, ptr1, ptr2);
623 /* in order to make this re-doable we move it to the RemoveList */
624 MoveObjectToBuffer (RemoveList, PCB->Data, type, ptr1, ptr2, ptr3);
625 Entry->Type = UNDO_REMOVE;
626 return (true);
628 return (false);
631 /* ---------------------------------------------------------------------------
632 * recovers an object from a 'move' operation
633 * returns true if anything has been recovered
635 static bool
636 UndoMove (UndoListTypePtr Entry)
638 void *ptr1, *ptr2, *ptr3;
639 int type;
641 /* lookup entry by it's ID */
642 type =
643 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
644 if (type != NO_TYPE)
646 if (TEST_FLAG (LOCKFLAG, (LineTypePtr) ptr2))
647 return (false);
648 MoveObject (type, ptr1, ptr2, ptr3,
649 -Entry->Data.Move.DX, -Entry->Data.Move.DY);
650 Entry->Data.Move.DX *= -1;
651 Entry->Data.Move.DY *= -1;
652 return (true);
654 return (false);
657 /* ----------------------------------------------------------------------
658 * recovers an object from a 'remove' operation
659 * returns true if anything has been recovered
661 static bool
662 UndoRemove (UndoListTypePtr Entry)
664 void *ptr1, *ptr2, *ptr3;
665 int type;
667 /* lookup entry by it's ID */
668 type =
669 SearchObjectByID (RemoveList, &ptr1, &ptr2, &ptr3, Entry->ID,
670 Entry->Kind);
671 if (type != NO_TYPE)
673 if (andDraw)
674 DrawRecoveredObject (type, ptr1, ptr2, ptr3);
675 MoveObjectToBuffer (PCB->Data, RemoveList, type, ptr1, ptr2, ptr3);
676 Entry->Type = UNDO_CREATE;
677 return (true);
679 return (false);
682 /* ----------------------------------------------------------------------
683 * recovers an object from a 'move to another layer' operation
684 * returns true if anything has been recovered
686 static bool
687 UndoMoveToLayer (UndoListTypePtr Entry)
689 void *ptr1, *ptr2, *ptr3;
690 int type, swap;
692 /* lookup entry by it's ID */
693 type =
694 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
695 if (type != NO_TYPE)
697 if (TEST_FLAG (LOCKFLAG, (LineTypePtr) ptr2))
698 return (false);
699 swap = GetLayerNumber (PCB->Data, (LayerTypePtr) ptr1);
700 MoveObjectToLayer (type, ptr1, ptr2, ptr3,
701 LAYER_PTR (Entry->Data.
702 MoveToLayer.OriginalLayer), true);
703 Entry->Data.MoveToLayer.OriginalLayer = swap;
704 return (true);
706 return (false);
709 /* ---------------------------------------------------------------------------
710 * recovers a removed polygon point
711 * returns true on success
713 static bool
714 UndoRemovePoint (UndoListTypePtr Entry)
716 LayerTypePtr layer;
717 PolygonTypePtr polygon;
718 void *ptr3;
719 int type;
721 /* lookup entry (polygon not point was saved) by it's ID */
722 assert (Entry->Kind == POLYGON_TYPE);
723 type =
724 SearchObjectByID (PCB->Data, (void *) &layer, (void *) &polygon, &ptr3,
725 Entry->ID, Entry->Kind);
726 switch (type)
728 case POLYGON_TYPE: /* restore the removed point */
730 if (TEST_FLAG (LOCKFLAG, polygon))
731 return (false);
732 /* recover the point */
733 if (andDraw && layer->On)
734 ErasePolygon (polygon);
735 InsertPointIntoObject (POLYGON_TYPE, layer, polygon,
736 &Entry->Data.RemovedPoint.Index,
737 Entry->Data.RemovedPoint.X,
738 Entry->Data.RemovedPoint.Y, true,
739 Entry->Data.RemovedPoint.last_in_contour);
741 polygon->Points[Entry->Data.RemovedPoint.Index].ID =
742 Entry->Data.RemovedPoint.ID;
743 if (andDraw && layer->On)
744 DrawPolygon (layer, polygon, 0);
745 Entry->Type = UNDO_INSERT_POINT;
746 Entry->ID = Entry->Data.RemovedPoint.ID;
747 Entry->Kind = POLYGONPOINT_TYPE;
748 return (true);
751 default:
752 return (false);
756 /* ---------------------------------------------------------------------------
757 * recovers an inserted polygon point
758 * returns true on success
760 static bool
761 UndoInsertPoint (UndoListTypePtr Entry)
763 LayerTypePtr layer;
764 PolygonTypePtr polygon;
765 PointTypePtr pnt;
766 int type;
767 Cardinal point_idx;
768 Cardinal hole;
769 bool last_in_contour = false;
771 assert (Entry->Kind == POLYGONPOINT_TYPE);
772 /* lookup entry by it's ID */
773 type =
774 SearchObjectByID (PCB->Data, (void *) &layer, (void *) &polygon,
775 (void *) &pnt, Entry->ID, Entry->Kind);
776 switch (type)
778 case POLYGONPOINT_TYPE: /* removes an inserted polygon point */
780 if (TEST_FLAG (LOCKFLAG, polygon))
781 return (false);
782 if (andDraw && layer->On)
783 ErasePolygon (polygon);
785 /* Check whether this point was at the end of its contour.
786 * If so, we need to flag as such when re-adding the point
787 * so it goes back in the correct place
789 point_idx = polygon_point_idx (polygon, pnt);
790 for (hole = 0; hole < polygon->HoleIndexN; hole++)
791 if (point_idx == polygon->HoleIndex[hole] - 1)
792 last_in_contour = true;
793 if (point_idx == polygon->PointN - 1)
794 last_in_contour = true;
795 Entry->Data.RemovedPoint.last_in_contour = last_in_contour;
797 Entry->Data.RemovedPoint.X = pnt->X;
798 Entry->Data.RemovedPoint.Y = pnt->Y;
799 Entry->Data.RemovedPoint.ID = pnt->ID;
800 Entry->ID = polygon->ID;
801 Entry->Kind = POLYGON_TYPE;
802 Entry->Type = UNDO_REMOVE_POINT;
803 Entry->Data.RemovedPoint.Index = point_idx;
804 DestroyObject (PCB->Data, POLYGONPOINT_TYPE, layer, polygon, pnt);
805 if (andDraw && layer->On)
806 DrawPolygon (layer, polygon, 0);
807 return (true);
810 default:
811 return (false);
815 static bool
816 UndoSwapCopiedObject (UndoListTypePtr Entry)
818 void *ptr1, *ptr2, *ptr3;
819 void *ptr1b, *ptr2b, *ptr3b;
820 AnyObjectType *obj, *obj2;
821 int type;
822 long int swap_id;
824 /* lookup entry by it's ID */
825 type =
826 SearchObjectByID (RemoveList, &ptr1, &ptr2, &ptr3, Entry->Data.CopyID,
827 Entry->Kind);
828 if (type == NO_TYPE)
829 return false;
831 type =
832 SearchObjectByID (PCB->Data, &ptr1b, &ptr2b, &ptr3b, Entry->ID,
833 Entry->Kind);
834 if (type == NO_TYPE)
835 return FALSE;
837 obj = ptr2;
838 obj2 = ptr2b;
840 swap_id = obj->ID;
841 obj->ID = obj2->ID;
842 obj2->ID = swap_id;
844 MoveObjectToBuffer (RemoveList, PCB->Data, type, ptr1b, ptr2b, ptr3b);
846 if (andDraw)
847 DrawRecoveredObject (Entry->Kind, ptr1, ptr2, ptr3);
849 obj = MoveObjectToBuffer (PCB->Data, RemoveList, type, ptr1, ptr2, ptr3);
850 if (Entry->Kind == POLYGON_TYPE)
851 InitClip (PCB->Data, ptr1b, (PolygonType *)obj);
852 return (true);
855 /* ---------------------------------------------------------------------------
856 * recovers an removed polygon point
857 * returns true on success
859 static bool
860 UndoRemoveContour (UndoListTypePtr Entry)
862 assert (Entry->Kind == POLYGON_TYPE);
863 return UndoSwapCopiedObject (Entry);
866 /* ---------------------------------------------------------------------------
867 * recovers an inserted polygon point
868 * returns true on success
870 static bool
871 UndoInsertContour (UndoListTypePtr Entry)
873 assert (Entry->Kind == POLYGON_TYPE);
874 return UndoSwapCopiedObject (Entry);
877 /* ---------------------------------------------------------------------------
878 * undo a layer change
879 * returns true on success
881 static bool
882 UndoLayerChange (UndoListTypePtr Entry)
884 LayerChangeTypePtr l = &Entry->Data.LayerChange;
885 int tmp;
887 tmp = l->new_index;
888 l->new_index = l->old_index;
889 l->old_index = tmp;
891 if (MoveLayer (l->old_index, l->new_index))
892 return false;
893 else
894 return true;
897 /* ---------------------------------------------------------------------------
898 * undo a netlist change
899 * returns true on success
901 static bool
902 UndoNetlistChange (UndoListTypePtr Entry)
904 NetlistChangeTypePtr l = & Entry->Data.NetlistChange;
905 unsigned int i, j;
906 LibraryTypePtr lib, saved;
908 lib = l->lib;
909 saved = l->old;
911 /* iterate over each net */
912 for (i = 0 ; i < lib->MenuN; i++)
914 if (lib->Menu[i].Name)
915 free (lib->Menu[i].Name);
917 if (lib->Menu[i].directory)
918 free (lib->Menu[i].directory);
920 if (lib->Menu[i].Style)
921 free (lib->Menu[i].Style);
923 /* iterate over each pin on the net */
924 for (j = 0; j < lib->Menu[i].EntryN; j++) {
926 if (lib->Menu[i].Entry[j].ListEntry)
927 free (lib->Menu[i].Entry[j].ListEntry);
929 if (lib->Menu[i].Entry[j].AllocatedMemory)
930 free (lib->Menu[i].Entry[j].AllocatedMemory);
932 if (lib->Menu[i].Entry[j].Template)
933 free (lib->Menu[i].Entry[j].Template);
935 if (lib->Menu[i].Entry[j].Package)
936 free (lib->Menu[i].Entry[j].Package);
938 if (lib->Menu[i].Entry[j].Value)
939 free (lib->Menu[i].Entry[j].Value);
941 if (lib->Menu[i].Entry[j].Description)
942 free (lib->Menu[i].Entry[j].Description);
947 if (lib->Menu)
948 free (lib->Menu);
950 *lib = *saved;
952 NetlistChanged (0);
953 return true;
956 /* ---------------------------------------------------------------------------
957 * undo of any 'hard to recover' operation
959 * returns the bitfield for the types of operations that were undone
962 Undo (bool draw)
964 UndoListTypePtr ptr;
965 int Types = 0;
966 int unique;
968 unique = TEST_FLAG (UNIQUENAMEFLAG, PCB);
969 CLEAR_FLAG (UNIQUENAMEFLAG, PCB);
971 andDraw = draw;
975 if (!UndoN)
977 if (!Serial)
978 Message (_("Nothing to undo - buffer is empty\n"));
979 else
980 Serial--;
981 return (false);
984 /* lock undo module to prevent from loops
985 * and loop over all entries with the same serial number
987 ptr = &UndoList[UndoN - 1];
988 if (ptr->Serial != Serial - 1)
990 Message (_("Undo bad serial number %d expecting %d\n"),
991 ptr->Serial, Serial - 1);
992 Serial = ptr->Serial + 1;
993 return (false);
995 LockUndo ();
996 Serial = ptr->Serial;
997 for (; UndoN && ptr->Serial == Serial; ptr--, UndoN--, RedoN++)
998 Types |= PerformUndo (ptr);
999 /* release lock */
1000 UnlockUndo ();
1002 while (Types == 0);
1003 if (Types && andDraw)
1004 Draw ();
1006 /* restore the unique flag setting */
1007 if (unique)
1008 SET_FLAG (UNIQUENAMEFLAG, PCB);
1010 return (Types);
1013 static int
1014 PerformUndo (UndoListTypePtr ptr)
1016 switch (ptr->Type)
1018 case UNDO_CHANGENAME:
1019 if (UndoChangeName (ptr))
1020 return (UNDO_CHANGENAME);
1021 break;
1023 case UNDO_CREATE:
1024 if (UndoCopyOrCreate (ptr))
1025 return (UNDO_CREATE);
1026 break;
1028 case UNDO_MOVE:
1029 if (UndoMove (ptr))
1030 return (UNDO_MOVE);
1031 break;
1033 case UNDO_REMOVE:
1034 if (UndoRemove (ptr))
1035 return (UNDO_REMOVE);
1036 break;
1038 case UNDO_REMOVE_POINT:
1039 if (UndoRemovePoint (ptr))
1040 return (UNDO_REMOVE_POINT);
1041 break;
1043 case UNDO_INSERT_POINT:
1044 if (UndoInsertPoint (ptr))
1045 return (UNDO_INSERT_POINT);
1046 break;
1048 case UNDO_REMOVE_CONTOUR:
1049 if (UndoRemoveContour (ptr))
1050 return (UNDO_REMOVE_CONTOUR);
1051 break;
1053 case UNDO_INSERT_CONTOUR:
1054 if (UndoInsertContour (ptr))
1055 return (UNDO_INSERT_CONTOUR);
1056 break;
1058 case UNDO_ROTATE:
1059 if (UndoRotate (ptr))
1060 return (UNDO_ROTATE);
1061 break;
1063 case UNDO_CLEAR:
1064 if (UndoClearPoly (ptr))
1065 return (UNDO_CLEAR);
1066 break;
1068 case UNDO_MOVETOLAYER:
1069 if (UndoMoveToLayer (ptr))
1070 return (UNDO_MOVETOLAYER);
1071 break;
1073 case UNDO_FLAG:
1074 if (UndoFlag (ptr))
1075 return (UNDO_FLAG);
1076 break;
1078 case UNDO_CHANGESIZE:
1079 if (UndoChangeSize (ptr))
1080 return (UNDO_CHANGESIZE);
1081 break;
1083 case UNDO_CHANGECLEARSIZE:
1084 if (UndoChangeClearSize (ptr))
1085 return (UNDO_CHANGECLEARSIZE);
1086 break;
1088 case UNDO_CHANGEMASKSIZE:
1089 if (UndoChangeMaskSize (ptr))
1090 return (UNDO_CHANGEMASKSIZE);
1091 break;
1093 case UNDO_CHANGE2NDSIZE:
1094 if (UndoChange2ndSize (ptr))
1095 return (UNDO_CHANGE2NDSIZE);
1096 break;
1098 case UNDO_CHANGEANGLES:
1099 if (UndoChangeAngles (ptr))
1100 return (UNDO_CHANGEANGLES);
1101 break;
1103 case UNDO_LAYERCHANGE:
1104 if (UndoLayerChange (ptr))
1105 return (UNDO_LAYERCHANGE);
1106 break;
1108 case UNDO_NETLISTCHANGE:
1109 if (UndoNetlistChange (ptr))
1110 return (UNDO_NETLISTCHANGE);
1111 break;
1113 case UNDO_MIRROR:
1114 if (UndoMirror (ptr))
1115 return (UNDO_MIRROR);
1116 break;
1118 return 0;
1121 /* ---------------------------------------------------------------------------
1122 * redo of any 'hard to recover' operation
1124 * returns the number of operations redone
1127 Redo (bool draw)
1129 UndoListTypePtr ptr;
1130 int Types = 0;
1132 andDraw = draw;
1135 if (!RedoN)
1137 Message
1139 ("Nothing to redo. Perhaps changes have been made since last undo\n"));
1140 return (false);
1143 /* lock undo module to prevent from loops
1144 * and loop over all entries with the same serial number
1146 LockUndo ();
1147 ptr = &UndoList[UndoN];
1148 Serial = ptr->Serial;
1149 for (; RedoN && ptr->Serial == Serial; ptr++, UndoN++, RedoN--)
1150 Types |= PerformUndo (ptr);
1151 /* Make next serial number current in case we take a new branch */
1152 Serial++;
1153 UnlockUndo ();
1155 while (Types == 0);
1156 if (Types && andDraw)
1157 Draw ();
1158 return (Types);
1161 /* ---------------------------------------------------------------------------
1162 * restores the serial number of the undo list
1164 void
1165 RestoreUndoSerialNumber (void)
1167 Serial = SavedSerial;
1170 /* ---------------------------------------------------------------------------
1171 * saves the serial number of the undo list
1173 void
1174 SaveUndoSerialNumber (void)
1176 Bumped = false;
1177 SavedSerial = Serial;
1180 /* ---------------------------------------------------------------------------
1181 * increments the serial number of the undo list
1182 * it's not done automatically because some operations perform more
1183 * than one request with the same serial #
1185 void
1186 IncrementUndoSerialNumber (void)
1188 if (!Locked)
1190 /* don't increment if nothing was added */
1191 if (UndoN == 0 || UndoList[UndoN - 1].Serial != Serial)
1192 return;
1193 Serial++;
1194 Bumped = true;
1195 SetChangedFlag (true);
1199 /* ---------------------------------------------------------------------------
1200 * releases memory of the undo- and remove list
1202 void
1203 ClearUndoList (bool Force)
1205 UndoListTypePtr undo;
1207 if (UndoN
1208 && (Force || gui->confirm_dialog ("OK to clear 'undo' buffer?", 0)))
1210 /* release memory allocated by objects in undo list */
1211 for (undo = UndoList; UndoN; undo++, UndoN--)
1213 if (undo->Type == UNDO_CHANGENAME)
1214 SaveFree (undo->Data.ChangeName.Name);
1216 MYFREE (UndoList);
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);