Revert "Fix locale-dependent gerber output"
[geda-pcb/whiteaudio.git] / src / undo.c
blob17bebb9dd1ceb8d2a081f09917ba45e7f35340e2
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 static bool between_increment_and_restore = false;
80 static bool added_undo_between_increment_and_restore = false;
82 /* ---------------------------------------------------------------------------
83 * some local data types
85 typedef struct /* information about a change command */
87 char *Name;
89 ChangeNameType, *ChangeNameTypePtr;
91 typedef struct /* information about a move command */
93 Coord DX, DY; /* movement vector */
95 MoveType, *MoveTypePtr;
97 typedef struct /* information about removed polygon points */
99 Coord X, Y; /* data */
100 int ID;
101 Cardinal Index; /* index in a polygons array of points */
102 bool last_in_contour; /* Whether the point was the last in its contour */
104 RemovedPointType, *RemovedPointTypePtr;
106 typedef struct /* information about rotation */
108 Coord CenterX, CenterY; /* center of rotation */
109 Cardinal Steps; /* number of steps */
111 RotateType, *RotateTypePtr;
113 typedef struct /* information about moves between layers */
115 Cardinal OriginalLayer; /* the index of the original layer */
117 MoveToLayerType, *MoveToLayerTypePtr;
119 typedef struct /* information about layer changes */
121 int old_index;
122 int new_index;
124 LayerChangeType, *LayerChangeTypePtr;
126 typedef struct /* information about poly clear/restore */
128 bool Clear; /* true was clear, false was restore */
129 LayerTypePtr Layer;
131 ClearPolyType, *ClearPolyTypePtr;
133 typedef struct /* information about netlist lib changes */
135 LibraryTypePtr old;
136 LibraryTypePtr lib;
138 NetlistChangeType, *NetlistChangeTypePtr;
140 typedef struct /* holds information about an operation */
142 int Serial, /* serial number of operation */
143 Type, /* type of operation */
144 Kind, /* type of object with given ID */
145 ID; /* object ID */
146 union /* some additional information */
148 ChangeNameType ChangeName;
149 MoveType Move;
150 RemovedPointType RemovedPoint;
151 RotateType Rotate;
152 MoveToLayerType MoveToLayer;
153 FlagType Flags;
154 Coord Size;
155 LayerChangeType LayerChange;
156 ClearPolyType ClearPoly;
157 NetlistChangeType NetlistChange;
158 long int CopyID;
160 Data;
162 UndoListType, *UndoListTypePtr;
164 /* ---------------------------------------------------------------------------
165 * some local variables
167 static DataTypePtr RemoveList = NULL; /* list of removed objects */
168 static UndoListTypePtr UndoList = NULL; /* list of operations */
169 static int Serial = 1, /* serial number */
170 SavedSerial;
171 static size_t UndoN, RedoN, /* number of entries */
172 UndoMax;
173 static bool Locked = false; /* do not add entries if */
174 static bool andDraw = true;
175 /* flag is set; prevents from */
176 /* infinite loops */
178 /* ---------------------------------------------------------------------------
179 * some local prototypes
181 static UndoListTypePtr GetUndoSlot (int, int, int);
182 static void DrawRecoveredObject (int, void *, void *, void *);
183 static bool UndoRotate (UndoListTypePtr);
184 static bool UndoChangeName (UndoListTypePtr);
185 static bool UndoCopyOrCreate (UndoListTypePtr);
186 static bool UndoMove (UndoListTypePtr);
187 static bool UndoRemove (UndoListTypePtr);
188 static bool UndoRemovePoint (UndoListTypePtr);
189 static bool UndoInsertPoint (UndoListTypePtr);
190 static bool UndoRemoveContour (UndoListTypePtr);
191 static bool UndoInsertContour (UndoListTypePtr);
192 static bool UndoMoveToLayer (UndoListTypePtr);
193 static bool UndoFlag (UndoListTypePtr);
194 static bool UndoMirror (UndoListTypePtr);
195 static bool UndoChangeSize (UndoListTypePtr);
196 static bool UndoChange2ndSize (UndoListTypePtr);
197 static bool UndoChangeAngles (UndoListTypePtr);
198 static bool UndoChangeClearSize (UndoListTypePtr);
199 static bool UndoChangeMaskSize (UndoListTypePtr);
200 static bool UndoClearPoly (UndoListTypePtr);
201 static int PerformUndo (UndoListTypePtr);
203 /* ---------------------------------------------------------------------------
204 * adds a command plus some data to the undo list
206 static UndoListTypePtr
207 GetUndoSlot (int CommandType, int ID, int Kind)
209 UndoListTypePtr ptr;
210 void *ptr1, *ptr2, *ptr3;
211 int type;
212 static size_t limit = UNDO_WARNING_SIZE;
214 #ifdef DEBUG_ID
215 if (SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, ID, Kind) == NO_TYPE)
216 Message ("hace: ID (%d) and Type (%x) mismatch in AddObject...\n", ID,
217 Kind);
218 #endif
220 /* allocate memory */
221 if (UndoN >= UndoMax)
223 size_t size;
225 UndoMax += STEP_UNDOLIST;
226 size = UndoMax * sizeof (UndoListType);
227 UndoList = (UndoListTypePtr) realloc (UndoList, size);
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 free (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 if (between_increment_and_restore)
261 added_undo_between_increment_and_restore = true;
263 /* copy typefield and serial number to the list */
264 ptr = &UndoList[UndoN++];
265 ptr->Type = CommandType;
266 ptr->Kind = Kind;
267 ptr->ID = ID;
268 ptr->Serial = Serial;
269 return (ptr);
272 /* ---------------------------------------------------------------------------
273 * redraws the recovered object
275 static void
276 DrawRecoveredObject (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
278 if (Type & (LINE_TYPE | TEXT_TYPE | POLYGON_TYPE | ARC_TYPE))
280 LayerTypePtr layer;
282 layer = LAYER_PTR (GetLayerNumber (RemoveList, (LayerTypePtr) Ptr1));
283 DrawObject (Type, (void *) layer, Ptr2);
285 else
286 DrawObject (Type, Ptr1, Ptr2);
289 /* ---------------------------------------------------------------------------
290 * recovers an object from a 'rotate' operation
291 * returns true if anything has been recovered
293 static bool
294 UndoRotate (UndoListTypePtr Entry)
296 void *ptr1, *ptr2, *ptr3;
297 int type;
299 /* lookup entry by it's ID */
300 type =
301 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
302 if (type != NO_TYPE)
304 RotateObject (type, ptr1, ptr2, ptr3,
305 Entry->Data.Rotate.CenterX, Entry->Data.Rotate.CenterY,
306 (4 - Entry->Data.Rotate.Steps) & 0x03);
307 Entry->Data.Rotate.Steps = (4 - Entry->Data.Rotate.Steps) & 0x03;
308 return (true);
310 return (false);
313 /* ---------------------------------------------------------------------------
314 * recovers an object from a clear/restore poly operation
315 * returns true if anything has been recovered
317 static bool
318 UndoClearPoly (UndoListTypePtr Entry)
320 void *ptr1, *ptr2, *ptr3;
321 int type;
323 type =
324 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
325 if (type != NO_TYPE)
327 if (Entry->Data.ClearPoly.Clear)
328 RestoreToPolygon (PCB->Data, type, Entry->Data.ClearPoly.Layer, ptr3);
329 else
330 ClearFromPolygon (PCB->Data, type, Entry->Data.ClearPoly.Layer, ptr3);
331 Entry->Data.ClearPoly.Clear = !Entry->Data.ClearPoly.Clear;
332 return true;
334 return false;
337 /* ---------------------------------------------------------------------------
338 * recovers an object from a 'change name' operation
339 * returns true if anything has been recovered
341 static bool
342 UndoChangeName (UndoListTypePtr Entry)
344 void *ptr1, *ptr2, *ptr3;
345 int type;
347 /* lookup entry by it's ID */
348 type =
349 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
350 if (type != NO_TYPE)
352 Entry->Data.ChangeName.Name =
353 (char *)(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 Coord 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 swap = ((PinTypePtr) ptr2)->DrillingHole;
376 if (andDraw)
377 EraseObject (type, ptr1, ptr2);
378 ((PinTypePtr) ptr2)->DrillingHole = Entry->Data.Size;
379 Entry->Data.Size = swap;
380 DrawObject (type, ptr1, ptr2);
381 return (true);
383 return (false);
386 /* ---------------------------------------------------------------------------
387 * recovers an object from a ChangeAngles change operation
389 static bool
390 UndoChangeAngles (UndoListTypePtr Entry)
392 void *ptr1, *ptr2, *ptr3;
393 int type;
394 long int old_sa, old_da;
396 /* lookup entry by ID */
397 type =
398 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
399 if (type == ARC_TYPE)
401 LayerTypePtr Layer = (LayerTypePtr) ptr1;
402 ArcTypePtr a = (ArcTypePtr) ptr2;
403 r_delete_entry (Layer->arc_tree, (BoxTypePtr) a);
404 old_sa = a->StartAngle;
405 old_da = a->Delta;
406 if (andDraw)
407 EraseObject (type, Layer, a);
408 a->StartAngle = Entry->Data.Move.DX;
409 a->Delta = Entry->Data.Move.DY;
410 SetArcBoundingBox (a);
411 r_insert_entry (Layer->arc_tree, (BoxTypePtr) a, 0);
412 Entry->Data.Move.DX = old_sa;
413 Entry->Data.Move.DY = old_da;;
414 DrawObject (type, ptr1, a);
415 return (true);
417 return (false);
420 /* ---------------------------------------------------------------------------
421 * recovers an object from a clearance size change operation
423 static bool
424 UndoChangeClearSize (UndoListTypePtr Entry)
426 void *ptr1, *ptr2, *ptr3;
427 int type;
428 Coord swap;
430 /* lookup entry by ID */
431 type =
432 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
433 if (type != NO_TYPE)
435 swap = ((PinTypePtr) ptr2)->Clearance;
436 RestoreToPolygon (PCB->Data, type, ptr1, ptr2);
437 if (andDraw)
438 EraseObject (type, ptr1, ptr2);
439 ((PinTypePtr) ptr2)->Clearance = Entry->Data.Size;
440 ClearFromPolygon (PCB->Data, type, ptr1, ptr2);
441 Entry->Data.Size = swap;
442 if (andDraw)
443 DrawObject (type, ptr1, ptr2);
444 return (true);
446 return (false);
449 /* ---------------------------------------------------------------------------
450 * recovers an object from a mask size change operation
452 static bool
453 UndoChangeMaskSize (UndoListTypePtr Entry)
455 void *ptr1, *ptr2, *ptr3;
456 int type;
457 Coord swap;
459 /* lookup entry by ID */
460 type =
461 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
462 if (type & (VIA_TYPE | PIN_TYPE | PAD_TYPE))
464 swap =
465 (type ==
466 PAD_TYPE ? ((PadTypePtr) ptr2)->Mask : ((PinTypePtr) ptr2)->Mask);
467 if (andDraw)
468 EraseObject (type, ptr1, ptr2);
469 if (type == PAD_TYPE)
470 ((PadTypePtr) ptr2)->Mask = Entry->Data.Size;
471 else
472 ((PinTypePtr) ptr2)->Mask = Entry->Data.Size;
473 Entry->Data.Size = swap;
474 if (andDraw)
475 DrawObject (type, ptr1, ptr2);
476 return (true);
478 return (false);
482 /* ---------------------------------------------------------------------------
483 * recovers an object from a Size change operation
485 static bool
486 UndoChangeSize (UndoListTypePtr Entry)
488 void *ptr1, *ptr2, *ptr3;
489 int type;
490 Coord swap;
492 /* lookup entry by ID */
493 type =
494 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
495 if (type != NO_TYPE)
497 /* Wow! can any object be treated as a pin type for size change?? */
498 /* pins, vias, lines, and arcs can. Text can't but it has it's own mechanism */
499 swap = ((PinTypePtr) ptr2)->Thickness;
500 RestoreToPolygon (PCB->Data, type, ptr1, ptr2);
501 if (andDraw)
502 EraseObject (type, ptr1, ptr2);
503 ((PinTypePtr) ptr2)->Thickness = Entry->Data.Size;
504 Entry->Data.Size = swap;
505 ClearFromPolygon (PCB->Data, type, ptr1, ptr2);
506 if (andDraw)
507 DrawObject (type, ptr1, ptr2);
508 return (true);
510 return (false);
513 /* ---------------------------------------------------------------------------
514 * recovers an object from a FLAG change operation
516 static bool
517 UndoFlag (UndoListTypePtr Entry)
519 void *ptr1, *ptr2, *ptr3;
520 int type;
521 FlagType swap;
522 int must_redraw;
524 /* lookup entry by ID */
525 type =
526 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
527 if (type != NO_TYPE)
529 FlagType f1, f2;
530 PinTypePtr pin = (PinTypePtr) ptr2;
532 swap = pin->Flags;
534 must_redraw = 0;
535 f1 = MaskFlags (pin->Flags, ~DRAW_FLAGS);
536 f2 = MaskFlags (Entry->Data.Flags, ~DRAW_FLAGS);
538 if (!FLAGS_EQUAL (f1, f2))
539 must_redraw = 1;
541 if (andDraw && must_redraw)
542 EraseObject (type, ptr1, ptr2);
544 pin->Flags = Entry->Data.Flags;
546 Entry->Data.Flags = swap;
548 if (andDraw && must_redraw)
549 DrawObject (type, ptr1, ptr2);
550 return (true);
552 Message ("hace Internal error: Can't find ID %d type %08x\n", Entry->ID,
553 Entry->Kind);
554 Message ("for UndoFlag Operation. Previous flags: %s\n",
555 flags_to_string (Entry->Data.Flags, 0));
556 return (false);
559 /* ---------------------------------------------------------------------------
560 * recovers an object from a mirror operation
561 * returns true if anything has been recovered
563 static bool
564 UndoMirror (UndoListTypePtr Entry)
566 void *ptr1, *ptr2, *ptr3;
567 int type;
569 /* lookup entry by ID */
570 type =
571 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
572 if (type == ELEMENT_TYPE)
574 ElementTypePtr element = (ElementTypePtr) ptr3;
575 if (andDraw)
576 EraseElement (element);
577 MirrorElementCoordinates (PCB->Data, element, Entry->Data.Move.DY);
578 if (andDraw)
579 DrawElement (element);
580 return (true);
582 Message ("hace Internal error: UndoMirror on object type %d\n", type);
583 return (false);
586 /* ---------------------------------------------------------------------------
587 * recovers an object from a 'copy' or 'create' operation
588 * returns true if anything has been recovered
590 static bool
591 UndoCopyOrCreate (UndoListTypePtr Entry)
593 void *ptr1, *ptr2, *ptr3;
594 int type;
596 /* lookup entry by it's ID */
597 type =
598 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
599 if (type != NO_TYPE)
601 if (!RemoveList)
602 RemoveList = CreateNewBuffer ();
603 if (andDraw)
604 EraseObject (type, ptr1, ptr2);
605 /* in order to make this re-doable we move it to the RemoveList */
606 MoveObjectToBuffer (RemoveList, PCB->Data, type, ptr1, ptr2, ptr3);
607 Entry->Type = UNDO_REMOVE;
608 return (true);
610 return (false);
613 /* ---------------------------------------------------------------------------
614 * recovers an object from a 'move' operation
615 * returns true if anything has been recovered
617 static bool
618 UndoMove (UndoListTypePtr Entry)
620 void *ptr1, *ptr2, *ptr3;
621 int type;
623 /* lookup entry by it's ID */
624 type =
625 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
626 if (type != NO_TYPE)
628 MoveObject (type, ptr1, ptr2, ptr3,
629 -Entry->Data.Move.DX, -Entry->Data.Move.DY);
630 Entry->Data.Move.DX *= -1;
631 Entry->Data.Move.DY *= -1;
632 return (true);
634 return (false);
637 /* ----------------------------------------------------------------------
638 * recovers an object from a 'remove' operation
639 * returns true if anything has been recovered
641 static bool
642 UndoRemove (UndoListTypePtr Entry)
644 void *ptr1, *ptr2, *ptr3;
645 int type;
647 /* lookup entry by it's ID */
648 type =
649 SearchObjectByID (RemoveList, &ptr1, &ptr2, &ptr3, Entry->ID,
650 Entry->Kind);
651 if (type != NO_TYPE)
653 if (andDraw)
654 DrawRecoveredObject (type, ptr1, ptr2, ptr3);
655 MoveObjectToBuffer (PCB->Data, RemoveList, type, ptr1, ptr2, ptr3);
656 Entry->Type = UNDO_CREATE;
657 return (true);
659 return (false);
662 /* ----------------------------------------------------------------------
663 * recovers an object from a 'move to another layer' operation
664 * returns true if anything has been recovered
666 static bool
667 UndoMoveToLayer (UndoListTypePtr Entry)
669 void *ptr1, *ptr2, *ptr3;
670 int type, swap;
672 /* lookup entry by it's ID */
673 type =
674 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
675 if (type != NO_TYPE)
677 swap = GetLayerNumber (PCB->Data, (LayerTypePtr) ptr1);
678 MoveObjectToLayer (type, ptr1, ptr2, ptr3,
679 LAYER_PTR (Entry->Data.
680 MoveToLayer.OriginalLayer), true);
681 Entry->Data.MoveToLayer.OriginalLayer = swap;
682 return (true);
684 return (false);
687 /* ---------------------------------------------------------------------------
688 * recovers a removed polygon point
689 * returns true on success
691 static bool
692 UndoRemovePoint (UndoListTypePtr Entry)
694 LayerTypePtr layer;
695 PolygonTypePtr polygon;
696 void *ptr3;
697 int type;
699 /* lookup entry (polygon not point was saved) by it's ID */
700 assert (Entry->Kind == POLYGON_TYPE);
701 type =
702 SearchObjectByID (PCB->Data, (void **) &layer, (void **) &polygon, &ptr3,
703 Entry->ID, Entry->Kind);
704 switch (type)
706 case POLYGON_TYPE: /* restore the removed point */
708 /* recover the point */
709 if (andDraw && layer->On)
710 ErasePolygon (polygon);
711 InsertPointIntoObject (POLYGON_TYPE, layer, polygon,
712 &Entry->Data.RemovedPoint.Index,
713 Entry->Data.RemovedPoint.X,
714 Entry->Data.RemovedPoint.Y, true,
715 Entry->Data.RemovedPoint.last_in_contour);
717 polygon->Points[Entry->Data.RemovedPoint.Index].ID =
718 Entry->Data.RemovedPoint.ID;
719 if (andDraw && layer->On)
720 DrawPolygon (layer, polygon);
721 Entry->Type = UNDO_INSERT_POINT;
722 Entry->ID = Entry->Data.RemovedPoint.ID;
723 Entry->Kind = POLYGONPOINT_TYPE;
724 return (true);
727 default:
728 return (false);
732 /* ---------------------------------------------------------------------------
733 * recovers an inserted polygon point
734 * returns true on success
736 static bool
737 UndoInsertPoint (UndoListTypePtr Entry)
739 LayerTypePtr layer;
740 PolygonTypePtr polygon;
741 PointTypePtr pnt;
742 int type;
743 Cardinal point_idx;
744 Cardinal hole;
745 bool last_in_contour = false;
747 assert (Entry->Kind == POLYGONPOINT_TYPE);
748 /* lookup entry by it's ID */
749 type =
750 SearchObjectByID (PCB->Data, (void **) &layer, (void **) &polygon,
751 (void **) &pnt, Entry->ID, Entry->Kind);
752 switch (type)
754 case POLYGONPOINT_TYPE: /* removes an inserted polygon point */
756 if (andDraw && layer->On)
757 ErasePolygon (polygon);
759 /* Check whether this point was at the end of its contour.
760 * If so, we need to flag as such when re-adding the point
761 * so it goes back in the correct place
763 point_idx = polygon_point_idx (polygon, pnt);
764 for (hole = 0; hole < polygon->HoleIndexN; hole++)
765 if (point_idx == polygon->HoleIndex[hole] - 1)
766 last_in_contour = true;
767 if (point_idx == polygon->PointN - 1)
768 last_in_contour = true;
769 Entry->Data.RemovedPoint.last_in_contour = last_in_contour;
771 Entry->Data.RemovedPoint.X = pnt->X;
772 Entry->Data.RemovedPoint.Y = pnt->Y;
773 Entry->Data.RemovedPoint.ID = pnt->ID;
774 Entry->ID = polygon->ID;
775 Entry->Kind = POLYGON_TYPE;
776 Entry->Type = UNDO_REMOVE_POINT;
777 Entry->Data.RemovedPoint.Index = point_idx;
778 DestroyObject (PCB->Data, POLYGONPOINT_TYPE, layer, polygon, pnt);
779 if (andDraw && layer->On)
780 DrawPolygon (layer, polygon);
781 return (true);
784 default:
785 return (false);
789 static bool
790 UndoSwapCopiedObject (UndoListTypePtr Entry)
792 void *ptr1, *ptr2, *ptr3;
793 void *ptr1b, *ptr2b, *ptr3b;
794 AnyObjectType *obj, *obj2;
795 int type;
796 long int swap_id;
798 /* lookup entry by it's ID */
799 type =
800 SearchObjectByID (RemoveList, &ptr1, &ptr2, &ptr3, Entry->Data.CopyID,
801 Entry->Kind);
802 if (type == NO_TYPE)
803 return false;
805 type =
806 SearchObjectByID (PCB->Data, &ptr1b, &ptr2b, &ptr3b, Entry->ID,
807 Entry->Kind);
808 if (type == NO_TYPE)
809 return FALSE;
811 obj = (AnyObjectType *)ptr2;
812 obj2 = (AnyObjectType *)ptr2b;
814 swap_id = obj->ID;
815 obj->ID = obj2->ID;
816 obj2->ID = swap_id;
818 MoveObjectToBuffer (RemoveList, PCB->Data, type, ptr1b, ptr2b, ptr3b);
820 if (andDraw)
821 DrawRecoveredObject (Entry->Kind, ptr1, ptr2, ptr3);
823 obj = (AnyObjectType *)MoveObjectToBuffer (PCB->Data, RemoveList, type, ptr1, ptr2, ptr3);
824 if (Entry->Kind == POLYGON_TYPE)
825 InitClip (PCB->Data, (LayerTypePtr)ptr1b, (PolygonType *)obj);
826 return (true);
829 /* ---------------------------------------------------------------------------
830 * recovers an removed polygon point
831 * returns true on success
833 static bool
834 UndoRemoveContour (UndoListTypePtr Entry)
836 assert (Entry->Kind == POLYGON_TYPE);
837 return UndoSwapCopiedObject (Entry);
840 /* ---------------------------------------------------------------------------
841 * recovers an inserted polygon point
842 * returns true on success
844 static bool
845 UndoInsertContour (UndoListTypePtr Entry)
847 assert (Entry->Kind == POLYGON_TYPE);
848 return UndoSwapCopiedObject (Entry);
851 /* ---------------------------------------------------------------------------
852 * undo a layer change
853 * returns true on success
855 static bool
856 UndoLayerChange (UndoListTypePtr Entry)
858 LayerChangeTypePtr l = &Entry->Data.LayerChange;
859 int tmp;
861 tmp = l->new_index;
862 l->new_index = l->old_index;
863 l->old_index = tmp;
865 if (MoveLayer (l->old_index, l->new_index))
866 return false;
867 else
868 return true;
871 /* ---------------------------------------------------------------------------
872 * undo a netlist change
873 * returns true on success
875 static bool
876 UndoNetlistChange (UndoListTypePtr Entry)
878 NetlistChangeTypePtr l = & Entry->Data.NetlistChange;
879 unsigned int i, j;
880 LibraryTypePtr lib, saved;
882 lib = l->lib;
883 saved = l->old;
885 /* iterate over each net */
886 for (i = 0 ; i < lib->MenuN; i++)
888 if (lib->Menu[i].Name)
889 free (lib->Menu[i].Name);
891 if (lib->Menu[i].directory)
892 free (lib->Menu[i].directory);
894 if (lib->Menu[i].Style)
895 free (lib->Menu[i].Style);
897 /* iterate over each pin on the net */
898 for (j = 0; j < lib->Menu[i].EntryN; j++) {
900 if (lib->Menu[i].Entry[j].ListEntry)
901 free (lib->Menu[i].Entry[j].ListEntry);
903 if (lib->Menu[i].Entry[j].AllocatedMemory)
904 free (lib->Menu[i].Entry[j].AllocatedMemory);
906 if (lib->Menu[i].Entry[j].Template)
907 free (lib->Menu[i].Entry[j].Template);
909 if (lib->Menu[i].Entry[j].Package)
910 free (lib->Menu[i].Entry[j].Package);
912 if (lib->Menu[i].Entry[j].Value)
913 free (lib->Menu[i].Entry[j].Value);
915 if (lib->Menu[i].Entry[j].Description)
916 free (lib->Menu[i].Entry[j].Description);
921 if (lib->Menu)
922 free (lib->Menu);
924 *lib = *saved;
926 NetlistChanged (0);
927 return true;
930 /* ---------------------------------------------------------------------------
931 * undo of any 'hard to recover' operation
933 * returns the bitfield for the types of operations that were undone
936 Undo (bool draw)
938 UndoListTypePtr ptr;
939 int Types = 0;
940 int unique;
941 bool error_undoing = false;
943 unique = TEST_FLAG (UNIQUENAMEFLAG, PCB);
944 CLEAR_FLAG (UNIQUENAMEFLAG, PCB);
946 andDraw = draw;
948 if (Serial == 0)
950 Message (_("ERROR: Attempt to Undo() with Serial == 0\n"
951 " Please save your work and report this bug.\n"));
952 return 0;
955 if (UndoN == 0)
957 Message (_("Nothing to undo - buffer is empty\n"));
958 return 0;
961 Serial --;
963 ptr = &UndoList[UndoN - 1];
965 if (ptr->Serial > Serial)
967 Message (_("ERROR: Bad undo serial number %d in undo stack - expecting %d or lower\n"
968 " Please save your work and report this bug.\n"),
969 ptr->Serial, Serial);
971 /* It is likely that the serial number got corrupted through some bad
972 * use of the SaveUndoSerialNumber() / RestoreUndoSerialNumber() APIs.
974 * Reset the serial number to be consistent with that of the last
975 * operation on the undo stack in the hope that this might clear
976 * the problem and allow the user to hit Undo again.
978 Serial = ptr->Serial + 1;
979 return 0;
982 LockUndo (); /* lock undo module to prevent from loops */
984 /* Loop over all entries with the correct serial number */
985 for (; UndoN && ptr->Serial == Serial; ptr--, UndoN--, RedoN++)
987 int undid = PerformUndo (ptr);
988 if (undid == 0)
989 error_undoing = true;
990 Types |= undid;
993 UnlockUndo ();
995 if (error_undoing)
996 Message (_("ERROR: Failed to undo some operations\n"));
998 if (Types && andDraw)
999 Draw ();
1001 /* restore the unique flag setting */
1002 if (unique)
1003 SET_FLAG (UNIQUENAMEFLAG, PCB);
1005 return Types;
1008 static int
1009 PerformUndo (UndoListTypePtr ptr)
1011 switch (ptr->Type)
1013 case UNDO_CHANGENAME:
1014 if (UndoChangeName (ptr))
1015 return (UNDO_CHANGENAME);
1016 break;
1018 case UNDO_CREATE:
1019 if (UndoCopyOrCreate (ptr))
1020 return (UNDO_CREATE);
1021 break;
1023 case UNDO_MOVE:
1024 if (UndoMove (ptr))
1025 return (UNDO_MOVE);
1026 break;
1028 case UNDO_REMOVE:
1029 if (UndoRemove (ptr))
1030 return (UNDO_REMOVE);
1031 break;
1033 case UNDO_REMOVE_POINT:
1034 if (UndoRemovePoint (ptr))
1035 return (UNDO_REMOVE_POINT);
1036 break;
1038 case UNDO_INSERT_POINT:
1039 if (UndoInsertPoint (ptr))
1040 return (UNDO_INSERT_POINT);
1041 break;
1043 case UNDO_REMOVE_CONTOUR:
1044 if (UndoRemoveContour (ptr))
1045 return (UNDO_REMOVE_CONTOUR);
1046 break;
1048 case UNDO_INSERT_CONTOUR:
1049 if (UndoInsertContour (ptr))
1050 return (UNDO_INSERT_CONTOUR);
1051 break;
1053 case UNDO_ROTATE:
1054 if (UndoRotate (ptr))
1055 return (UNDO_ROTATE);
1056 break;
1058 case UNDO_CLEAR:
1059 if (UndoClearPoly (ptr))
1060 return (UNDO_CLEAR);
1061 break;
1063 case UNDO_MOVETOLAYER:
1064 if (UndoMoveToLayer (ptr))
1065 return (UNDO_MOVETOLAYER);
1066 break;
1068 case UNDO_FLAG:
1069 if (UndoFlag (ptr))
1070 return (UNDO_FLAG);
1071 break;
1073 case UNDO_CHANGESIZE:
1074 if (UndoChangeSize (ptr))
1075 return (UNDO_CHANGESIZE);
1076 break;
1078 case UNDO_CHANGECLEARSIZE:
1079 if (UndoChangeClearSize (ptr))
1080 return (UNDO_CHANGECLEARSIZE);
1081 break;
1083 case UNDO_CHANGEMASKSIZE:
1084 if (UndoChangeMaskSize (ptr))
1085 return (UNDO_CHANGEMASKSIZE);
1086 break;
1088 case UNDO_CHANGE2NDSIZE:
1089 if (UndoChange2ndSize (ptr))
1090 return (UNDO_CHANGE2NDSIZE);
1091 break;
1093 case UNDO_CHANGEANGLES:
1094 if (UndoChangeAngles (ptr))
1095 return (UNDO_CHANGEANGLES);
1096 break;
1098 case UNDO_LAYERCHANGE:
1099 if (UndoLayerChange (ptr))
1100 return (UNDO_LAYERCHANGE);
1101 break;
1103 case UNDO_NETLISTCHANGE:
1104 if (UndoNetlistChange (ptr))
1105 return (UNDO_NETLISTCHANGE);
1106 break;
1108 case UNDO_MIRROR:
1109 if (UndoMirror (ptr))
1110 return (UNDO_MIRROR);
1111 break;
1113 return 0;
1116 /* ---------------------------------------------------------------------------
1117 * redo of any 'hard to recover' operation
1119 * returns the number of operations redone
1122 Redo (bool draw)
1124 UndoListTypePtr ptr;
1125 int Types = 0;
1126 bool error_undoing = false;
1128 andDraw = draw;
1130 if (RedoN == 0)
1132 Message (_("Nothing to redo. Perhaps changes have been made since last undo\n"));
1133 return 0;
1136 ptr = &UndoList[UndoN];
1138 if (ptr->Serial < Serial)
1140 Message (_("ERROR: Bad undo serial number %d in redo stack - expecting %d or higher\n"
1141 " Please save your work and report this bug.\n"),
1142 ptr->Serial, Serial);
1144 /* It is likely that the serial number got corrupted through some bad
1145 * use of the SaveUndoSerialNumber() / RestoreUndoSerialNumber() APIs.
1147 * Reset the serial number to be consistent with that of the first
1148 * operation on the redo stack in the hope that this might clear
1149 * the problem and allow the user to hit Redo again.
1151 Serial = ptr->Serial;
1152 return 0;
1155 LockUndo (); /* lock undo module to prevent from loops */
1157 /* and loop over all entries with the correct serial number */
1158 for (; RedoN && ptr->Serial == Serial; ptr++, UndoN++, RedoN--)
1160 int undid = PerformUndo (ptr);
1161 if (undid == 0)
1162 error_undoing = true;
1163 Types |= undid;
1166 /* Make next serial number current */
1167 Serial++;
1169 UnlockUndo ();
1171 if (error_undoing)
1172 Message (_("ERROR: Failed to redo some operations\n"));
1174 if (Types && andDraw)
1175 Draw ();
1177 return Types;
1180 /* ---------------------------------------------------------------------------
1181 * restores the serial number of the undo list
1183 void
1184 RestoreUndoSerialNumber (void)
1186 if (added_undo_between_increment_and_restore)
1187 Message (_("ERROR: Operations were added to the Undo stack with an incorrect serial number\n"));
1188 between_increment_and_restore = false;
1189 added_undo_between_increment_and_restore = false;
1190 Serial = SavedSerial;
1193 /* ---------------------------------------------------------------------------
1194 * saves the serial number of the undo list
1196 void
1197 SaveUndoSerialNumber (void)
1199 Bumped = false;
1200 between_increment_and_restore = false;
1201 added_undo_between_increment_and_restore = false;
1202 SavedSerial = Serial;
1205 /* ---------------------------------------------------------------------------
1206 * increments the serial number of the undo list
1207 * it's not done automatically because some operations perform more
1208 * than one request with the same serial #
1210 void
1211 IncrementUndoSerialNumber (void)
1213 if (!Locked)
1215 /* Set the changed flag if anything was added prior to this bump */
1216 if (UndoN > 0 && UndoList[UndoN - 1].Serial == Serial)
1217 SetChangedFlag (true);
1218 Serial++;
1219 Bumped = true;
1220 between_increment_and_restore = true;
1224 /* ---------------------------------------------------------------------------
1225 * releases memory of the undo- and remove list
1227 void
1228 ClearUndoList (bool Force)
1230 UndoListTypePtr undo;
1232 if (UndoN
1233 && (Force || gui->confirm_dialog ("OK to clear 'undo' buffer?", 0)))
1235 /* release memory allocated by objects in undo list */
1236 for (undo = UndoList; UndoN; undo++, UndoN--)
1238 if (undo->Type == UNDO_CHANGENAME)
1239 free (undo->Data.ChangeName.Name);
1241 free (UndoList);
1242 UndoList = NULL;
1243 if (RemoveList)
1245 FreeDataMemory (RemoveList);
1246 free (RemoveList);
1247 RemoveList = NULL;
1250 /* reset some counters */
1251 UndoN = UndoMax = RedoN = 0;
1254 /* reset counter in any case */
1255 Serial = 1;
1258 /* ---------------------------------------------------------------------------
1259 * adds an object to the list of clearpoly objects
1261 void
1262 AddObjectToClearPolyUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
1263 bool clear)
1265 UndoListTypePtr undo;
1267 if (!Locked)
1269 undo = GetUndoSlot (UNDO_CLEAR, OBJECT_ID (Ptr3), Type);
1270 undo->Data.ClearPoly.Clear = clear;
1271 undo->Data.ClearPoly.Layer = (LayerTypePtr) Ptr1;
1275 /* ---------------------------------------------------------------------------
1276 * adds an object to the list of mirrored objects
1278 void
1279 AddObjectToMirrorUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
1280 Coord yoff)
1282 UndoListTypePtr undo;
1284 if (!Locked)
1286 undo = GetUndoSlot (UNDO_MIRROR, OBJECT_ID (Ptr3), Type);
1287 undo->Data.Move.DY = yoff;
1291 /* ---------------------------------------------------------------------------
1292 * adds an object to the list of rotated objects
1294 void
1295 AddObjectToRotateUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
1296 Coord CenterX, Coord CenterY,
1297 BYTE Steps)
1299 UndoListTypePtr undo;
1301 if (!Locked)
1303 undo = GetUndoSlot (UNDO_ROTATE, OBJECT_ID (Ptr3), Type);
1304 undo->Data.Rotate.CenterX = CenterX;
1305 undo->Data.Rotate.CenterY = CenterY;
1306 undo->Data.Rotate.Steps = Steps;
1310 /* ---------------------------------------------------------------------------
1311 * adds an object to the list of removed objects and removes it from
1312 * the current PCB
1314 void
1315 MoveObjectToRemoveUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1317 if (Locked)
1318 return;
1320 if (!RemoveList)
1321 RemoveList = CreateNewBuffer ();
1323 GetUndoSlot (UNDO_REMOVE, OBJECT_ID (Ptr3), Type);
1324 MoveObjectToBuffer (RemoveList, PCB->Data, Type, Ptr1, Ptr2, Ptr3);
1327 /* ---------------------------------------------------------------------------
1328 * adds an object to the list of removed polygon/... points
1330 void
1331 AddObjectToRemovePointUndoList (int Type,
1332 void *Ptr1, void *Ptr2, Cardinal index)
1334 UndoListTypePtr undo;
1335 PolygonTypePtr polygon = (PolygonTypePtr) Ptr2;
1336 Cardinal hole;
1337 bool last_in_contour = false;
1339 if (!Locked)
1341 switch (Type)
1343 case POLYGONPOINT_TYPE:
1345 /* save the ID of the parent object; else it will be
1346 * impossible to recover the point
1348 undo =
1349 GetUndoSlot (UNDO_REMOVE_POINT, OBJECT_ID (polygon),
1350 POLYGON_TYPE);
1351 undo->Data.RemovedPoint.X = polygon->Points[index].X;
1352 undo->Data.RemovedPoint.Y = polygon->Points[index].Y;
1353 undo->Data.RemovedPoint.ID = polygon->Points[index].ID;
1354 undo->Data.RemovedPoint.Index = index;
1356 /* Check whether this point was at the end of its contour.
1357 * If so, we need to flag as such when re-adding the point
1358 * so it goes back in the correct place
1360 for (hole = 0; hole < polygon->HoleIndexN; hole++)
1361 if (index == polygon->HoleIndex[hole] - 1)
1362 last_in_contour = true;
1363 if (index == polygon->PointN - 1)
1364 last_in_contour = true;
1365 undo->Data.RemovedPoint.last_in_contour = last_in_contour;
1367 break;
1372 /* ---------------------------------------------------------------------------
1373 * adds an object to the list of inserted polygon/... points
1375 void
1376 AddObjectToInsertPointUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1378 if (!Locked)
1379 GetUndoSlot (UNDO_INSERT_POINT, OBJECT_ID (Ptr3), Type);
1382 static void
1383 CopyObjectToUndoList (int undo_type, int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1385 UndoListTypePtr undo;
1386 AnyObjectType *copy;
1388 if (Locked)
1389 return;
1391 if (!RemoveList)
1392 RemoveList = CreateNewBuffer ();
1394 undo = GetUndoSlot (undo_type, OBJECT_ID (Ptr2), Type);
1395 copy = (AnyObjectType *)CopyObjectToBuffer (RemoveList, PCB->Data, Type, Ptr1, Ptr2, Ptr3);
1396 undo->Data.CopyID = copy->ID;
1399 /* ---------------------------------------------------------------------------
1400 * adds an object to the list of removed contours
1401 * (Actually just takes a copy of the whole polygon to restore)
1403 void
1404 AddObjectToRemoveContourUndoList (int Type,
1405 LayerType *Layer, PolygonType *Polygon)
1407 CopyObjectToUndoList (UNDO_REMOVE_CONTOUR, Type, Layer, Polygon, NULL);
1410 /* ---------------------------------------------------------------------------
1411 * adds an object to the list of insert contours
1412 * (Actually just takes a copy of the whole polygon to restore)
1414 void
1415 AddObjectToInsertContourUndoList (int Type,
1416 LayerType *Layer, PolygonType *Polygon)
1418 CopyObjectToUndoList (UNDO_INSERT_CONTOUR, Type, Layer, Polygon, NULL);
1421 /* ---------------------------------------------------------------------------
1422 * adds an object to the list of moved objects
1424 void
1425 AddObjectToMoveUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
1426 Coord DX, Coord DY)
1428 UndoListTypePtr undo;
1430 if (!Locked)
1432 undo = GetUndoSlot (UNDO_MOVE, OBJECT_ID (Ptr3), Type);
1433 undo->Data.Move.DX = DX;
1434 undo->Data.Move.DY = DY;
1438 /* ---------------------------------------------------------------------------
1439 * adds an object to the list of objects with changed names
1441 void
1442 AddObjectToChangeNameUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
1443 char *OldName)
1445 UndoListTypePtr undo;
1447 if (!Locked)
1449 undo = GetUndoSlot (UNDO_CHANGENAME, OBJECT_ID (Ptr3), Type);
1450 undo->Data.ChangeName.Name = OldName;
1454 /* ---------------------------------------------------------------------------
1455 * adds an object to the list of objects moved to another layer
1457 void
1458 AddObjectToMoveToLayerUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1460 UndoListTypePtr undo;
1462 if (!Locked)
1464 undo = GetUndoSlot (UNDO_MOVETOLAYER, OBJECT_ID (Ptr3), Type);
1465 undo->Data.MoveToLayer.OriginalLayer =
1466 GetLayerNumber (PCB->Data, (LayerTypePtr) Ptr1);
1470 /* ---------------------------------------------------------------------------
1471 * adds an object to the list of created objects
1473 void
1474 AddObjectToCreateUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1476 if (!Locked)
1477 GetUndoSlot (UNDO_CREATE, OBJECT_ID (Ptr3), Type);
1478 ClearFromPolygon (PCB->Data, Type, Ptr1, Ptr2);
1481 /* ---------------------------------------------------------------------------
1482 * adds an object to the list of objects with flags changed
1484 void
1485 AddObjectToFlagUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1487 UndoListTypePtr undo;
1489 if (!Locked)
1491 undo = GetUndoSlot (UNDO_FLAG, OBJECT_ID (Ptr2), Type);
1492 undo->Data.Flags = ((PinTypePtr) Ptr2)->Flags;
1496 /* ---------------------------------------------------------------------------
1497 * adds an object to the list of objects with Size changes
1499 void
1500 AddObjectToSizeUndoList (int Type, void *ptr1, void *ptr2, void *ptr3)
1502 UndoListTypePtr undo;
1504 if (!Locked)
1506 undo = GetUndoSlot (UNDO_CHANGESIZE, OBJECT_ID (ptr2), Type);
1507 switch (Type)
1509 case PIN_TYPE:
1510 case VIA_TYPE:
1511 undo->Data.Size = ((PinTypePtr) ptr2)->Thickness;
1512 break;
1513 case LINE_TYPE:
1514 case ELEMENTLINE_TYPE:
1515 undo->Data.Size = ((LineTypePtr) ptr2)->Thickness;
1516 break;
1517 case TEXT_TYPE:
1518 case ELEMENTNAME_TYPE:
1519 undo->Data.Size = ((TextTypePtr) ptr2)->Scale;
1520 break;
1521 case PAD_TYPE:
1522 undo->Data.Size = ((PadTypePtr) ptr2)->Thickness;
1523 break;
1524 case ARC_TYPE:
1525 case ELEMENTARC_TYPE:
1526 undo->Data.Size = ((ArcTypePtr) ptr2)->Thickness;
1527 break;
1532 /* ---------------------------------------------------------------------------
1533 * adds an object to the list of objects with Size changes
1535 void
1536 AddObjectToClearSizeUndoList (int Type, void *ptr1, void *ptr2, void *ptr3)
1538 UndoListTypePtr undo;
1540 if (!Locked)
1542 undo = GetUndoSlot (UNDO_CHANGECLEARSIZE, OBJECT_ID (ptr2), Type);
1543 switch (Type)
1545 case PIN_TYPE:
1546 case VIA_TYPE:
1547 undo->Data.Size = ((PinTypePtr) ptr2)->Clearance;
1548 break;
1549 case LINE_TYPE:
1550 undo->Data.Size = ((LineTypePtr) ptr2)->Clearance;
1551 break;
1552 case PAD_TYPE:
1553 undo->Data.Size = ((PadTypePtr) ptr2)->Clearance;
1554 break;
1555 case ARC_TYPE:
1556 undo->Data.Size = ((ArcTypePtr) ptr2)->Clearance;
1557 break;
1562 /* ---------------------------------------------------------------------------
1563 * adds an object to the list of objects with Size changes
1565 void
1566 AddObjectToMaskSizeUndoList (int Type, void *ptr1, void *ptr2, void *ptr3)
1568 UndoListTypePtr undo;
1570 if (!Locked)
1572 undo = GetUndoSlot (UNDO_CHANGEMASKSIZE, OBJECT_ID (ptr2), Type);
1573 switch (Type)
1575 case PIN_TYPE:
1576 case VIA_TYPE:
1577 undo->Data.Size = ((PinTypePtr) ptr2)->Mask;
1578 break;
1579 case PAD_TYPE:
1580 undo->Data.Size = ((PadTypePtr) ptr2)->Mask;
1581 break;
1586 /* ---------------------------------------------------------------------------
1587 * adds an object to the list of objects with 2ndSize changes
1589 void
1590 AddObjectTo2ndSizeUndoList (int Type, void *ptr1, void *ptr2, void *ptr3)
1592 UndoListTypePtr undo;
1594 if (!Locked)
1596 undo = GetUndoSlot (UNDO_CHANGE2NDSIZE, OBJECT_ID (ptr2), Type);
1597 if (Type == PIN_TYPE || Type == VIA_TYPE)
1598 undo->Data.Size = ((PinTypePtr) ptr2)->DrillingHole;
1602 /* ---------------------------------------------------------------------------
1603 * adds an object to the list of changed angles. Note that you must
1604 * call this before changing the angles, passing the new start/delta.
1606 void
1607 AddObjectToChangeAnglesUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1609 UndoListTypePtr undo;
1610 ArcTypePtr a = (ArcTypePtr) Ptr3;
1612 if (!Locked)
1614 undo = GetUndoSlot (UNDO_CHANGEANGLES, OBJECT_ID (Ptr3), Type);
1615 undo->Data.Move.DX = a->StartAngle;
1616 undo->Data.Move.DY = a->Delta;
1620 /* ---------------------------------------------------------------------------
1621 * adds a layer change (new, delete, move) to the undo list.
1623 void
1624 AddLayerChangeToUndoList (int old_index, int new_index)
1626 UndoListTypePtr undo;
1628 if (!Locked)
1630 undo = GetUndoSlot (UNDO_LAYERCHANGE, 0, 0);
1631 undo->Data.LayerChange.old_index = old_index;
1632 undo->Data.LayerChange.new_index = new_index;
1636 /* ---------------------------------------------------------------------------
1637 * adds a netlist change to the undo list
1639 void
1640 AddNetlistLibToUndoList (LibraryTypePtr lib)
1642 UndoListTypePtr undo;
1643 unsigned int i, j;
1644 LibraryTypePtr old;
1646 if (!Locked)
1648 undo = GetUndoSlot (UNDO_NETLISTCHANGE, 0, 0);
1649 /* keep track of where the data needs to go */
1650 undo->Data.NetlistChange.lib = lib;
1652 /* and what the old data is that we'll need to restore */
1653 undo->Data.NetlistChange.old = (LibraryTypePtr)malloc (sizeof (LibraryTypePtr));
1654 old = undo->Data.NetlistChange.old;
1655 old->MenuN = lib->MenuN;
1656 old->MenuMax = lib->MenuMax;
1657 old->Menu = (LibraryMenuTypePtr)malloc (old->MenuMax * sizeof (LibraryMenuType));
1658 if (old->Menu == NULL)
1660 fprintf (stderr, "malloc() failed in %s\n", __FUNCTION__);
1661 exit (1);
1664 /* iterate over each net */
1665 for (i = 0 ; i < lib->MenuN; i++)
1667 old->Menu[i].EntryN = lib->Menu[i].EntryN;
1668 old->Menu[i].EntryMax = lib->Menu[i].EntryMax;
1670 old->Menu[i].Name =
1671 lib->Menu[i].Name ? strdup (lib->Menu[i].Name) : NULL;
1673 old->Menu[i].directory =
1674 lib->Menu[i].directory ? strdup (lib->Menu[i].directory) : NULL;
1676 old->Menu[i].Style =
1677 lib->Menu[i].Style ? strdup (lib->Menu[i].Style) : NULL;
1680 old->Menu[i].Entry =
1681 (LibraryEntryTypePtr)malloc (old->Menu[i].EntryMax * sizeof (LibraryEntryType));
1682 if (old->Menu[i].Entry == NULL)
1684 fprintf (stderr, "malloc() failed in %s\n", __FUNCTION__);
1685 exit (1);
1688 /* iterate over each pin on the net */
1689 for (j = 0; j < lib->Menu[i].EntryN; j++) {
1691 old->Menu[i].Entry[j].ListEntry =
1692 lib->Menu[i].Entry[j].ListEntry ?
1693 strdup (lib->Menu[i].Entry[j].ListEntry) :
1694 NULL;
1696 old->Menu[i].Entry[j].AllocatedMemory =
1697 lib->Menu[i].Entry[j].AllocatedMemory ?
1698 strdup (lib->Menu[i].Entry[j].AllocatedMemory) :
1699 NULL;
1701 old->Menu[i].Entry[j].Template =
1702 lib->Menu[i].Entry[j].Template ?
1703 strdup (lib->Menu[i].Entry[j].Template) :
1704 NULL;
1706 old->Menu[i].Entry[j].Package =
1707 lib->Menu[i].Entry[j].Package ?
1708 strdup (lib->Menu[i].Entry[j].Package) :
1709 NULL;
1711 old->Menu[i].Entry[j].Value =
1712 lib->Menu[i].Entry[j].Value ?
1713 strdup (lib->Menu[i].Entry[j].Value) :
1714 NULL;
1716 old->Menu[i].Entry[j].Description =
1717 lib->Menu[i].Entry[j].Description ?
1718 strdup (lib->Menu[i].Entry[j].Description) :
1719 NULL;
1728 /* ---------------------------------------------------------------------------
1729 * set lock flag
1731 void
1732 LockUndo (void)
1734 Locked = true;
1737 /* ---------------------------------------------------------------------------
1738 * reset lock flag
1740 void
1741 UnlockUndo (void)
1743 Locked = false;
1746 /* ---------------------------------------------------------------------------
1747 * return undo lock state
1749 bool
1750 Undoing (void)
1752 return (Locked);