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
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
71 #ifdef HAVE_LIBDMALLOC
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 */
86 typedef struct /* information about a move command */
88 Coord DX
, DY
; /* movement vector */
91 typedef struct /* information about removed polygon points */
93 Coord X
, Y
; /* data */
95 Cardinal Index
; /* index in a polygons array of points */
96 bool last_in_contour
; /* Whether the point was the last in its contour */
99 typedef struct /* information about rotation */
101 Coord CenterX
, CenterY
; /* center of rotation */
102 Cardinal Steps
; /* number of steps */
105 typedef struct /* information about moves between layers */
107 Cardinal OriginalLayer
; /* the index of the original layer */
110 typedef struct /* information about layer changes */
116 typedef struct /* information about poly clear/restore */
118 bool Clear
; /* true was clear, false was restore */
122 typedef struct /* information about netlist lib changes */
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 */
134 union /* some additional information */
136 ChangeNameType ChangeName
;
138 RemovedPointType RemovedPoint
;
140 MoveToLayerType MoveToLayer
;
143 LayerChangeType LayerChange
;
144 ClearPolyType ClearPoly
;
145 NetlistChangeType NetlistChange
;
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 */
158 static size_t UndoN
, RedoN
, /* number of entries */
160 static bool Locked
= false; /* do not add entries if */
161 static bool andDraw
= true;
162 /* flag is set; prevents from */
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
)
197 void *ptr1
, *ptr2
, *ptr3
;
199 static size_t limit
= UNDO_WARNING_SIZE
;
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
,
207 /* allocate memory */
208 if (UndoN
>= UndoMax
)
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 */
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
--)
231 case UNDO_CHANGENAME
:
232 free (ptr
->Data
.ChangeName
.Name
);
236 SearchObjectByID (RemoveList
, &ptr1
, &ptr2
, &ptr3
, ptr
->ID
,
240 DestroyObject (RemoveList
, type
, ptr1
, ptr2
, ptr3
);
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
;
255 ptr
->Serial
= Serial
;
259 /* ---------------------------------------------------------------------------
260 * redraws the recovered object
263 DrawRecoveredObject (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
265 if (Type
& (LINE_TYPE
| TEXT_TYPE
| POLYGON_TYPE
| ARC_TYPE
))
269 layer
= LAYER_PTR (GetLayerNumber (RemoveList
, (LayerType
*) Ptr1
));
270 DrawObject (Type
, (void *) layer
, Ptr2
);
273 DrawObject (Type
, Ptr1
, Ptr2
);
276 /* ---------------------------------------------------------------------------
277 * recovers an object from a 'rotate' operation
278 * returns true if anything has been recovered
281 UndoRotate (UndoListType
*Entry
)
283 void *ptr1
, *ptr2
, *ptr3
;
286 /* lookup entry by it's ID */
288 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
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;
300 /* ---------------------------------------------------------------------------
301 * recovers an object from a clear/restore poly operation
302 * returns true if anything has been recovered
305 UndoClearPoly (UndoListType
*Entry
)
307 void *ptr1
, *ptr2
, *ptr3
;
311 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
314 if (Entry
->Data
.ClearPoly
.Clear
)
315 RestoreToPolygon (PCB
->Data
, type
, Entry
->Data
.ClearPoly
.Layer
, ptr3
);
317 ClearFromPolygon (PCB
->Data
, type
, Entry
->Data
.ClearPoly
.Layer
, ptr3
);
318 Entry
->Data
.ClearPoly
.Clear
= !Entry
->Data
.ClearPoly
.Clear
;
324 /* ---------------------------------------------------------------------------
325 * recovers an object from a 'change name' operation
326 * returns true if anything has been recovered
329 UndoChangeName (UndoListType
*Entry
)
331 void *ptr1
, *ptr2
, *ptr3
;
334 /* lookup entry by it's ID */
336 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
339 Entry
->Data
.ChangeName
.Name
=
340 (char *)(ChangeObjectName (type
, ptr1
, ptr2
, ptr3
,
341 Entry
->Data
.ChangeName
.Name
));
347 /* ---------------------------------------------------------------------------
348 * recovers an object from a 2ndSize change operation
351 UndoChange2ndSize (UndoListType
*Entry
)
353 void *ptr1
, *ptr2
, *ptr3
;
357 /* lookup entry by ID */
359 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
362 swap
= ((PinType
*) ptr2
)->DrillingHole
;
364 EraseObject (type
, ptr1
, ptr2
);
365 ((PinType
*) ptr2
)->DrillingHole
= Entry
->Data
.Size
;
366 Entry
->Data
.Size
= swap
;
367 DrawObject (type
, ptr1
, ptr2
);
373 /* ---------------------------------------------------------------------------
374 * recovers an object from a ChangeAngles change operation
377 UndoChangeAngles (UndoListType
*Entry
)
379 void *ptr1
, *ptr2
, *ptr3
;
381 long int old_sa
, old_da
;
383 /* lookup entry by ID */
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
;
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
);
407 /* ---------------------------------------------------------------------------
408 * recovers an object from a clearance size change operation
411 UndoChangeClearSize (UndoListType
*Entry
)
413 void *ptr1
, *ptr2
, *ptr3
;
417 /* lookup entry by ID */
419 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
422 swap
= ((PinType
*) ptr2
)->Clearance
;
423 RestoreToPolygon (PCB
->Data
, type
, ptr1
, ptr2
);
425 EraseObject (type
, ptr1
, ptr2
);
426 ((PinType
*) ptr2
)->Clearance
= Entry
->Data
.Size
;
427 ClearFromPolygon (PCB
->Data
, type
, ptr1
, ptr2
);
428 Entry
->Data
.Size
= swap
;
430 DrawObject (type
, ptr1
, ptr2
);
436 /* ---------------------------------------------------------------------------
437 * recovers an object from a mask size change operation
440 UndoChangeMaskSize (UndoListType
*Entry
)
442 void *ptr1
, *ptr2
, *ptr3
;
446 /* lookup entry by ID */
448 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
449 if (type
& (VIA_TYPE
| PIN_TYPE
| PAD_TYPE
))
453 PAD_TYPE
? ((PadType
*) ptr2
)->Mask
: ((PinType
*) ptr2
)->Mask
);
455 EraseObject (type
, ptr1
, ptr2
);
456 if (type
== PAD_TYPE
)
457 ((PadType
*) ptr2
)->Mask
= Entry
->Data
.Size
;
459 ((PinType
*) ptr2
)->Mask
= Entry
->Data
.Size
;
460 Entry
->Data
.Size
= swap
;
462 DrawObject (type
, ptr1
, ptr2
);
469 /* ---------------------------------------------------------------------------
470 * recovers an object from a Size change operation
473 UndoChangeSize (UndoListType
*Entry
)
475 void *ptr1
, *ptr2
, *ptr3
;
479 /* lookup entry by ID */
481 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
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
);
489 EraseObject (type
, ptr1
, ptr2
);
490 ((PinType
*) ptr2
)->Thickness
= Entry
->Data
.Size
;
491 Entry
->Data
.Size
= swap
;
492 ClearFromPolygon (PCB
->Data
, type
, ptr1
, ptr2
);
494 DrawObject (type
, ptr1
, ptr2
);
500 /* ---------------------------------------------------------------------------
501 * recovers an object from a FLAG change operation
504 UndoFlag (UndoListType
*Entry
)
506 void *ptr1
, *ptr2
, *ptr3
;
511 /* lookup entry by ID */
513 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
517 PinType
*pin
= (PinType
*) ptr2
;
522 f1
= MaskFlags (pin
->Flags
, ~DRAW_FLAGS
);
523 f2
= MaskFlags (Entry
->Data
.Flags
, ~DRAW_FLAGS
);
525 if (!FLAGS_EQUAL (f1
, f2
))
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
);
539 Message ("hace Internal error: Can't find ID %d type %08x\n", Entry
->ID
,
541 Message ("for UndoFlag Operation. Previous flags: %s\n",
542 flags_to_string (Entry
->Data
.Flags
, 0));
546 /* ---------------------------------------------------------------------------
547 * recovers an object from a mirror operation
548 * returns true if anything has been recovered
551 UndoMirror (UndoListType
*Entry
)
553 void *ptr1
, *ptr2
, *ptr3
;
556 /* lookup entry by ID */
558 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
559 if (type
== ELEMENT_TYPE
)
561 ElementType
*element
= (ElementType
*) ptr3
;
563 EraseElement (element
);
564 MirrorElementCoordinates (PCB
->Data
, element
, Entry
->Data
.Move
.DY
);
566 DrawElement (element
);
569 Message ("hace Internal error: UndoMirror on object type %d\n", type
);
573 /* ---------------------------------------------------------------------------
574 * recovers an object from a 'copy' or 'create' operation
575 * returns true if anything has been recovered
578 UndoCopyOrCreate (UndoListType
*Entry
)
580 void *ptr1
, *ptr2
, *ptr3
;
583 /* lookup entry by it's ID */
585 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
589 RemoveList
= CreateNewBuffer ();
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
;
600 /* ---------------------------------------------------------------------------
601 * recovers an object from a 'move' operation
602 * returns true if anything has been recovered
605 UndoMove (UndoListType
*Entry
)
607 void *ptr1
, *ptr2
, *ptr3
;
610 /* lookup entry by it's ID */
612 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
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;
624 /* ----------------------------------------------------------------------
625 * recovers an object from a 'remove' operation
626 * returns true if anything has been recovered
629 UndoRemove (UndoListType
*Entry
)
631 void *ptr1
, *ptr2
, *ptr3
;
634 /* lookup entry by it's ID */
636 SearchObjectByID (RemoveList
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
,
641 DrawRecoveredObject (type
, ptr1
, ptr2
, ptr3
);
642 MoveObjectToBuffer (PCB
->Data
, RemoveList
, type
, ptr1
, ptr2
, ptr3
);
643 Entry
->Type
= UNDO_CREATE
;
649 /* ----------------------------------------------------------------------
650 * recovers an object from a 'move to another layer' operation
651 * returns true if anything has been recovered
654 UndoMoveToLayer (UndoListType
*Entry
)
656 void *ptr1
, *ptr2
, *ptr3
;
659 /* lookup entry by it's ID */
661 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
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
;
674 /* ---------------------------------------------------------------------------
675 * recovers a removed polygon point
676 * returns true on success
679 UndoRemovePoint (UndoListType
*Entry
)
682 PolygonType
*polygon
;
686 /* lookup entry (polygon not point was saved) by it's ID */
687 assert (Entry
->Kind
== POLYGON_TYPE
);
689 SearchObjectByID (PCB
->Data
, (void **) &layer
, (void **) &polygon
, &ptr3
,
690 Entry
->ID
, Entry
->Kind
);
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
;
719 /* ---------------------------------------------------------------------------
720 * recovers an inserted polygon point
721 * returns true on success
724 UndoInsertPoint (UndoListType
*Entry
)
727 PolygonType
*polygon
;
732 bool last_in_contour
= false;
734 assert (Entry
->Kind
== POLYGONPOINT_TYPE
);
735 /* lookup entry by it's ID */
737 SearchObjectByID (PCB
->Data
, (void **) &layer
, (void **) &polygon
,
738 (void **) &pnt
, Entry
->ID
, Entry
->Kind
);
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
);
777 UndoSwapCopiedObject (UndoListType
*Entry
)
779 void *ptr1
, *ptr2
, *ptr3
;
780 void *ptr1b
, *ptr2b
, *ptr3b
;
781 AnyObjectType
*obj
, *obj2
;
785 /* lookup entry by it's ID */
787 SearchObjectByID (RemoveList
, &ptr1
, &ptr2
, &ptr3
, Entry
->Data
.CopyID
,
793 SearchObjectByID (PCB
->Data
, &ptr1b
, &ptr2b
, &ptr3b
, Entry
->ID
,
798 obj
= (AnyObjectType
*)ptr2
;
799 obj2
= (AnyObjectType
*)ptr2b
;
805 MoveObjectToBuffer (RemoveList
, PCB
->Data
, type
, ptr1b
, ptr2b
, ptr3b
);
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
);
816 /* ---------------------------------------------------------------------------
817 * recovers an removed polygon point
818 * returns true on success
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
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
843 UndoLayerChange (UndoListType
*Entry
)
845 LayerChangeType
*l
= &Entry
->Data
.LayerChange
;
849 l
->new_index
= l
->old_index
;
852 if (MoveLayer (l
->old_index
, l
->new_index
))
858 /* ---------------------------------------------------------------------------
859 * undo a netlist change
860 * returns true on success
863 UndoNetlistChange (UndoListType
*Entry
)
865 NetlistChangeType
*l
= & Entry
->Data
.NetlistChange
;
867 LibraryType
*lib
, *saved
;
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
);
917 /* ---------------------------------------------------------------------------
918 * undo of any 'hard to recover' operation
920 * returns the bitfield for the types of operations that were undone
928 bool error_undoing
= false;
930 unique
= TEST_FLAG (UNIQUENAMEFLAG
, PCB
);
931 CLEAR_FLAG (UNIQUENAMEFLAG
, PCB
);
937 Message (_("ERROR: Attempt to Undo() with Serial == 0\n"
938 " Please save your work and report this bug.\n"));
944 Message (_("Nothing to undo - buffer is empty\n"));
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;
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
);
976 error_undoing
= true;
983 Message (_("ERROR: Failed to undo some operations\n"));
985 if (Types
&& andDraw
)
988 /* restore the unique flag setting */
990 SET_FLAG (UNIQUENAMEFLAG
, PCB
);
996 PerformUndo (UndoListType
*ptr
)
1000 case UNDO_CHANGENAME
:
1001 if (UndoChangeName (ptr
))
1002 return (UNDO_CHANGENAME
);
1006 if (UndoCopyOrCreate (ptr
))
1007 return (UNDO_CREATE
);
1016 if (UndoRemove (ptr
))
1017 return (UNDO_REMOVE
);
1020 case UNDO_REMOVE_POINT
:
1021 if (UndoRemovePoint (ptr
))
1022 return (UNDO_REMOVE_POINT
);
1025 case UNDO_INSERT_POINT
:
1026 if (UndoInsertPoint (ptr
))
1027 return (UNDO_INSERT_POINT
);
1030 case UNDO_REMOVE_CONTOUR
:
1031 if (UndoRemoveContour (ptr
))
1032 return (UNDO_REMOVE_CONTOUR
);
1035 case UNDO_INSERT_CONTOUR
:
1036 if (UndoInsertContour (ptr
))
1037 return (UNDO_INSERT_CONTOUR
);
1041 if (UndoRotate (ptr
))
1042 return (UNDO_ROTATE
);
1046 if (UndoClearPoly (ptr
))
1047 return (UNDO_CLEAR
);
1050 case UNDO_MOVETOLAYER
:
1051 if (UndoMoveToLayer (ptr
))
1052 return (UNDO_MOVETOLAYER
);
1060 case UNDO_CHANGESIZE
:
1061 if (UndoChangeSize (ptr
))
1062 return (UNDO_CHANGESIZE
);
1065 case UNDO_CHANGECLEARSIZE
:
1066 if (UndoChangeClearSize (ptr
))
1067 return (UNDO_CHANGECLEARSIZE
);
1070 case UNDO_CHANGEMASKSIZE
:
1071 if (UndoChangeMaskSize (ptr
))
1072 return (UNDO_CHANGEMASKSIZE
);
1075 case UNDO_CHANGE2NDSIZE
:
1076 if (UndoChange2ndSize (ptr
))
1077 return (UNDO_CHANGE2NDSIZE
);
1080 case UNDO_CHANGEANGLES
:
1081 if (UndoChangeAngles (ptr
))
1082 return (UNDO_CHANGEANGLES
);
1085 case UNDO_LAYERCHANGE
:
1086 if (UndoLayerChange (ptr
))
1087 return (UNDO_LAYERCHANGE
);
1090 case UNDO_NETLISTCHANGE
:
1091 if (UndoNetlistChange (ptr
))
1092 return (UNDO_NETLISTCHANGE
);
1096 if (UndoMirror (ptr
))
1097 return (UNDO_MIRROR
);
1103 /* ---------------------------------------------------------------------------
1104 * redo of any 'hard to recover' operation
1106 * returns the number of operations redone
1113 bool error_undoing
= false;
1119 Message (_("Nothing to redo. Perhaps changes have been made since last undo\n"));
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
;
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
);
1149 error_undoing
= true;
1153 /* Make next serial number current */
1159 Message (_("ERROR: Failed to redo some operations\n"));
1161 if (Types
&& andDraw
)
1167 /* ---------------------------------------------------------------------------
1168 * restores the serial number of the undo list
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
1184 SaveUndoSerialNumber (void)
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 #
1198 IncrementUndoSerialNumber (void)
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);
1207 between_increment_and_restore
= true;
1211 /* ---------------------------------------------------------------------------
1212 * releases memory of the undo- and remove list
1215 ClearUndoList (bool Force
)
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
);
1232 FreeDataMemory (RemoveList
);
1237 /* reset some counters */
1238 UndoN
= UndoMax
= RedoN
= 0;
1241 /* reset counter in any case */
1245 /* ---------------------------------------------------------------------------
1246 * adds an object to the list of clearpoly objects
1249 AddObjectToClearPolyUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
,
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
1266 AddObjectToMirrorUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
,
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
1282 AddObjectToRotateUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
,
1283 Coord CenterX
, Coord CenterY
,
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
1302 MoveObjectToRemoveUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
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
1318 AddObjectToRemovePointUndoList (int Type
,
1319 void *Ptr1
, void *Ptr2
, Cardinal index
)
1322 PolygonType
*polygon
= (PolygonType
*) Ptr2
;
1324 bool last_in_contour
= false;
1330 case POLYGONPOINT_TYPE
:
1332 /* save the ID of the parent object; else it will be
1333 * impossible to recover the point
1336 GetUndoSlot (UNDO_REMOVE_POINT
, OBJECT_ID (polygon
),
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
;
1359 /* ---------------------------------------------------------------------------
1360 * adds an object to the list of inserted polygon/... points
1363 AddObjectToInsertPointUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
1366 GetUndoSlot (UNDO_INSERT_POINT
, OBJECT_ID (Ptr3
), Type
);
1370 CopyObjectToUndoList (int undo_type
, int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
1373 AnyObjectType
*copy
;
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)
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)
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
1412 AddObjectToMoveUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
,
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
1429 AddObjectToChangeNameUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
,
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
1445 AddObjectToMoveToLayerUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
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
1461 AddObjectToCreateUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
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
1472 AddObjectToFlagUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
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
1487 AddObjectToSizeUndoList (int Type
, void *ptr1
, void *ptr2
, void *ptr3
)
1493 undo
= GetUndoSlot (UNDO_CHANGESIZE
, OBJECT_ID (ptr2
), Type
);
1498 undo
->Data
.Size
= ((PinType
*) ptr2
)->Thickness
;
1501 case ELEMENTLINE_TYPE
:
1502 undo
->Data
.Size
= ((LineType
*) ptr2
)->Thickness
;
1505 case ELEMENTNAME_TYPE
:
1506 undo
->Data
.Size
= ((TextType
*) ptr2
)->Scale
;
1509 undo
->Data
.Size
= ((PadType
*) ptr2
)->Thickness
;
1512 case ELEMENTARC_TYPE
:
1513 undo
->Data
.Size
= ((ArcType
*) ptr2
)->Thickness
;
1519 /* ---------------------------------------------------------------------------
1520 * adds an object to the list of objects with Size changes
1523 AddObjectToClearSizeUndoList (int Type
, void *ptr1
, void *ptr2
, void *ptr3
)
1529 undo
= GetUndoSlot (UNDO_CHANGECLEARSIZE
, OBJECT_ID (ptr2
), Type
);
1534 undo
->Data
.Size
= ((PinType
*) ptr2
)->Clearance
;
1537 undo
->Data
.Size
= ((LineType
*) ptr2
)->Clearance
;
1540 undo
->Data
.Size
= ((PadType
*) ptr2
)->Clearance
;
1543 undo
->Data
.Size
= ((ArcType
*) ptr2
)->Clearance
;
1549 /* ---------------------------------------------------------------------------
1550 * adds an object to the list of objects with Size changes
1553 AddObjectToMaskSizeUndoList (int Type
, void *ptr1
, void *ptr2
, void *ptr3
)
1559 undo
= GetUndoSlot (UNDO_CHANGEMASKSIZE
, OBJECT_ID (ptr2
), Type
);
1564 undo
->Data
.Size
= ((PinType
*) ptr2
)->Mask
;
1567 undo
->Data
.Size
= ((PadType
*) ptr2
)->Mask
;
1573 /* ---------------------------------------------------------------------------
1574 * adds an object to the list of objects with 2ndSize changes
1577 AddObjectTo2ndSizeUndoList (int Type
, void *ptr1
, void *ptr2
, void *ptr3
)
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.
1594 AddObjectToChangeAnglesUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
1597 ArcType
*a
= (ArcType
*) Ptr3
;
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.
1611 AddLayerChangeToUndoList (int old_index
, int new_index
)
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
1627 AddNetlistLibToUndoList (LibraryType
*lib
)
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__
);
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
;
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__
);
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
) :
1683 old
->Menu
[i
].Entry
[j
].AllocatedMemory
=
1684 lib
->Menu
[i
].Entry
[j
].AllocatedMemory
?
1685 strdup (lib
->Menu
[i
].Entry
[j
].AllocatedMemory
) :
1688 old
->Menu
[i
].Entry
[j
].Template
=
1689 lib
->Menu
[i
].Entry
[j
].Template
?
1690 strdup (lib
->Menu
[i
].Entry
[j
].Template
) :
1693 old
->Menu
[i
].Entry
[j
].Package
=
1694 lib
->Menu
[i
].Entry
[j
].Package
?
1695 strdup (lib
->Menu
[i
].Entry
[j
].Package
) :
1698 old
->Menu
[i
].Entry
[j
].Value
=
1699 lib
->Menu
[i
].Entry
[j
].Value
?
1700 strdup (lib
->Menu
[i
].Entry
[j
].Value
) :
1703 old
->Menu
[i
].Entry
[j
].Description
=
1704 lib
->Menu
[i
].Entry
[j
].Description
?
1705 strdup (lib
->Menu
[i
].Entry
[j
].Description
) :
1715 /* ---------------------------------------------------------------------------
1724 /* ---------------------------------------------------------------------------
1733 /* ---------------------------------------------------------------------------
1734 * return undo lock state