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
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
73 #ifdef HAVE_LIBDMALLOC
79 /* ---------------------------------------------------------------------------
80 * some local data types
82 typedef struct /* information about a change command */
86 ChangeNameType
, *ChangeNameTypePtr
;
88 typedef struct /* information about a move command */
90 LocationType DX
, /* movement vector */
93 MoveType
, *MoveTypePtr
;
95 typedef struct /* information about removed polygon points */
97 LocationType X
, Y
; /* data */
99 Cardinal Index
; /* index in a polygons array of points */
101 RemovedPointType
, *RemovedPointTypePtr
;
103 typedef struct /* information about rotation */
105 LocationType CenterX
, /* center of rotation */
107 BYTE Steps
; /* number of steps */
109 RotateType
, *RotateTypePtr
;
111 typedef struct /* information about moves between layers */
113 Cardinal OriginalLayer
; /* the index of the original layer */
115 MoveToLayerType
, *MoveToLayerTypePtr
;
117 typedef struct /* information about layer changes */
122 LayerChangeType
, *LayerChangeTypePtr
;
124 typedef struct /* information about poly clear/restore */
126 Boolean Clear
; /* true was clear, false was restore */
129 ClearPolyType
, *ClearPolyTypePtr
;
131 typedef struct /* information about netlist lib changes */
136 NetlistChangeType
, *NetlistChangeTypePtr
;
138 typedef struct /* holds information about an operation */
140 int Serial
, /* serial number of operation */
141 Type
, /* type of operation */
142 Kind
, /* type of object with given ID */
144 union /* some additional information */
146 ChangeNameType ChangeName
;
148 RemovedPointType RemovedPoint
;
150 MoveToLayerType MoveToLayer
;
153 LayerChangeType LayerChange
;
154 ClearPolyType ClearPoly
;
155 NetlistChangeType NetlistChange
;
159 UndoListType
, *UndoListTypePtr
;
161 /* ---------------------------------------------------------------------------
162 * some local variables
164 static DataTypePtr RemoveList
= NULL
; /* list of removed objects */
165 static UndoListTypePtr UndoList
= NULL
; /* list of operations */
166 static int Serial
= 1, /* serial number */
168 static size_t UndoN
, RedoN
, /* number of entries */
170 static Boolean Locked
= False
; /* do not add entries if */
171 static Boolean andDraw
= True
;
172 /* flag is set; prevents from */
175 /* ---------------------------------------------------------------------------
176 * some local prototypes
178 static UndoListTypePtr
GetUndoSlot (int, int, int);
179 static void DrawRecoveredObject (int, void *, void *, void *);
180 static Boolean
UndoRotate (UndoListTypePtr
);
181 static Boolean
UndoChangeName (UndoListTypePtr
);
182 static Boolean
UndoCopyOrCreate (UndoListTypePtr
);
183 static Boolean
UndoMove (UndoListTypePtr
);
184 static Boolean
UndoRemove (UndoListTypePtr
);
185 static Boolean
UndoRemovePoint (UndoListTypePtr
);
186 static Boolean
UndoInsertPoint (UndoListTypePtr
);
187 static Boolean
UndoMoveToLayer (UndoListTypePtr
);
188 static Boolean
UndoFlag (UndoListTypePtr
);
189 static Boolean
UndoMirror (UndoListTypePtr
);
190 static Boolean
UndoChangeSize (UndoListTypePtr
);
191 static Boolean
UndoChange2ndSize (UndoListTypePtr
);
192 static Boolean
UndoChangeAngles (UndoListTypePtr
);
193 static Boolean
UndoChangeClearSize (UndoListTypePtr
);
194 static Boolean
UndoChangeMaskSize (UndoListTypePtr
);
195 static Boolean
UndoClearPoly (UndoListTypePtr
);
196 static int PerformUndo (UndoListTypePtr
);
198 /* ---------------------------------------------------------------------------
199 * adds a command plus some data to the undo list
201 static UndoListTypePtr
202 GetUndoSlot (int CommandType
, int ID
, int Kind
)
205 void *ptr1
, *ptr2
, *ptr3
;
207 static size_t limit
= UNDO_WARNING_SIZE
;
210 if (SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, ID
, Kind
) == NO_TYPE
)
211 Message ("hace: ID (%d) and Type (%x) mismatch in AddObject...\n", ID
,
215 /* allocate memory */
216 if (UndoN
>= UndoMax
)
220 UndoMax
+= STEP_UNDOLIST
;
221 size
= UndoMax
* sizeof (UndoListType
);
222 UndoList
= (UndoListTypePtr
) MyRealloc (UndoList
, size
,
223 "AddCommandToUndoList()");
224 memset (&UndoList
[UndoN
], 0, STEP_REMOVELIST
* sizeof (UndoListType
));
226 /* ask user to flush the table because of it's size */
229 limit
= (size
/ UNDO_WARNING_SIZE
+ 1) * UNDO_WARNING_SIZE
;
230 Message (_("Size of 'undo-list' exceeds %li kb\n"),
231 (long) (size
>> 10));
235 /* free structures from the pruned redo list */
237 for (ptr
= &UndoList
[UndoN
]; RedoN
; ptr
++, RedoN
--)
240 case UNDO_CHANGENAME
:
241 SaveFree (ptr
->Data
.ChangeName
.Name
);
245 SearchObjectByID (RemoveList
, &ptr1
, &ptr2
, &ptr3
, ptr
->ID
,
249 DestroyObject (RemoveList
, type
, ptr1
, ptr2
, ptr3
);
256 /* copy typefield and serial number to the list */
257 ptr
= &UndoList
[UndoN
++];
258 ptr
->Type
= CommandType
;
261 ptr
->Serial
= Serial
;
265 /* ---------------------------------------------------------------------------
266 * redraws the recovered object
269 DrawRecoveredObject (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
271 if (Type
& (LINE_TYPE
| TEXT_TYPE
| POLYGON_TYPE
| ARC_TYPE
))
275 layer
= LAYER_PTR (GetLayerNumber (RemoveList
, (LayerTypePtr
) Ptr1
));
276 DrawObject (Type
, (void *) layer
, Ptr2
, 0);
279 DrawObject (Type
, Ptr1
, Ptr2
, 0);
282 /* ---------------------------------------------------------------------------
283 * recovers an object from a 'rotate' operation
284 * returns True if anything has been recovered
287 UndoRotate (UndoListTypePtr Entry
)
289 void *ptr1
, *ptr2
, *ptr3
;
292 /* lookup entry by it's ID */
294 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
297 if (TEST_FLAG (LOCKFLAG
, (ArcTypePtr
) ptr2
))
299 RotateObject (type
, ptr1
, ptr2
, ptr3
,
300 Entry
->Data
.Rotate
.CenterX
, Entry
->Data
.Rotate
.CenterY
,
301 (4 - Entry
->Data
.Rotate
.Steps
) & 0x03);
302 Entry
->Data
.Rotate
.Steps
= (4 - Entry
->Data
.Rotate
.Steps
) & 0x03;
308 /* ---------------------------------------------------------------------------
309 * recovers an object from a clear/restore poly operation
310 * returns True if anything has been recovered
313 UndoClearPoly (UndoListTypePtr Entry
)
315 void *ptr1
, *ptr2
, *ptr3
;
319 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
322 if (Entry
->Data
.ClearPoly
.Clear
)
323 RestoreToPolygon (PCB
->Data
, type
, Entry
->Data
.ClearPoly
.Layer
, ptr3
);
325 ClearFromPolygon (PCB
->Data
, type
, Entry
->Data
.ClearPoly
.Layer
, ptr3
);
326 Entry
->Data
.ClearPoly
.Clear
= !Entry
->Data
.ClearPoly
.Clear
;
332 /* ---------------------------------------------------------------------------
333 * recovers an object from a 'change name' operation
334 * returns True if anything has been recovered
337 UndoChangeName (UndoListTypePtr Entry
)
339 void *ptr1
, *ptr2
, *ptr3
;
342 /* lookup entry by it's ID */
344 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
347 if (TEST_FLAG (LOCKFLAG
, (TextTypePtr
) ptr3
))
349 Entry
->Data
.ChangeName
.Name
=
350 (ChangeObjectName (type
, ptr1
, ptr2
, ptr3
,
351 Entry
->Data
.ChangeName
.Name
));
357 /* ---------------------------------------------------------------------------
358 * recovers an object from a 2ndSize change operation
361 UndoChange2ndSize (UndoListTypePtr Entry
)
363 void *ptr1
, *ptr2
, *ptr3
;
367 /* lookup entry by ID */
369 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
372 if (TEST_FLAG (LOCKFLAG
, (PinTypePtr
) ptr2
))
374 swap
= ((PinTypePtr
) ptr2
)->DrillingHole
;
376 EraseObject (type
, ptr1
, ptr2
);
377 ((PinTypePtr
) ptr2
)->DrillingHole
= Entry
->Data
.Size
;
378 Entry
->Data
.Size
= swap
;
379 DrawObject (type
, ptr1
, ptr2
, 0);
385 /* ---------------------------------------------------------------------------
386 * recovers an object from a ChangeAngles change operation
389 UndoChangeAngles (UndoListTypePtr Entry
)
391 void *ptr1
, *ptr2
, *ptr3
;
393 long int old_sa
, old_da
;
395 /* lookup entry by ID */
397 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
398 if (type
== ARC_TYPE
)
400 LayerTypePtr Layer
= (LayerTypePtr
) ptr1
;
401 ArcTypePtr a
= (ArcTypePtr
) ptr2
;
402 if (TEST_FLAG (LOCKFLAG
, a
))
404 r_delete_entry (Layer
->arc_tree
, (BoxTypePtr
) a
);
405 old_sa
= a
->StartAngle
;
408 EraseObject (type
, Layer
, a
);
409 a
->StartAngle
= Entry
->Data
.Move
.DX
;
410 a
->Delta
= Entry
->Data
.Move
.DY
;
411 SetArcBoundingBox (a
);
412 r_insert_entry (Layer
->arc_tree
, (BoxTypePtr
) a
, 0);
413 Entry
->Data
.Move
.DX
= old_sa
;
414 Entry
->Data
.Move
.DY
= old_da
;;
415 DrawObject (type
, ptr1
, a
, 0);
421 /* ---------------------------------------------------------------------------
422 * recovers an object from a clearance size change operation
425 UndoChangeClearSize (UndoListTypePtr Entry
)
427 void *ptr1
, *ptr2
, *ptr3
;
431 /* lookup entry by ID */
433 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
436 if (TEST_FLAG (LOCKFLAG
, (LineTypePtr
) ptr2
))
438 swap
= ((PinTypePtr
) ptr2
)->Clearance
;
439 RestoreToPolygon (PCB
->Data
, type
, ptr1
, ptr2
);
441 EraseObject (type
, ptr1
, ptr2
);
442 ((PinTypePtr
) ptr2
)->Clearance
= Entry
->Data
.Size
;
443 ClearFromPolygon (PCB
->Data
, type
, ptr1
, ptr2
);
444 Entry
->Data
.Size
= swap
;
446 DrawObject (type
, ptr1
, ptr2
, 0);
452 /* ---------------------------------------------------------------------------
453 * recovers an object from a mask size change operation
456 UndoChangeMaskSize (UndoListTypePtr Entry
)
458 void *ptr1
, *ptr2
, *ptr3
;
462 /* lookup entry by ID */
464 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
465 if (type
& (VIA_TYPE
| PIN_TYPE
| PAD_TYPE
))
467 if (TEST_FLAG (LOCKFLAG
, (PinTypePtr
) ptr2
))
471 PAD_TYPE
? ((PadTypePtr
) ptr2
)->Mask
: ((PinTypePtr
) ptr2
)->Mask
);
473 EraseObject (type
, ptr1
, ptr2
);
474 if (type
== PAD_TYPE
)
475 ((PadTypePtr
) ptr2
)->Mask
= Entry
->Data
.Size
;
477 ((PinTypePtr
) ptr2
)->Mask
= Entry
->Data
.Size
;
478 Entry
->Data
.Size
= swap
;
480 DrawObject (type
, ptr1
, ptr2
, 0);
487 /* ---------------------------------------------------------------------------
488 * recovers an object from a Size change operation
491 UndoChangeSize (UndoListTypePtr Entry
)
493 void *ptr1
, *ptr2
, *ptr3
;
497 /* lookup entry by ID */
499 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
502 if (TEST_FLAG (LOCKFLAG
, (PinTypePtr
) ptr2
))
504 /* Wow! can any object be treated as a pin type for size change?? */
505 /* pins, vias, lines, and arcs can. Text can't but it has it's own mechanism */
506 swap
= ((PinTypePtr
) ptr2
)->Thickness
;
507 RestoreToPolygon (PCB
->Data
, type
, ptr1
, ptr2
);
509 EraseObject (type
, ptr1
, ptr2
);
510 ((PinTypePtr
) ptr2
)->Thickness
= Entry
->Data
.Size
;
511 Entry
->Data
.Size
= swap
;
512 ClearFromPolygon (PCB
->Data
, type
, ptr1
, ptr2
);
514 DrawObject (type
, ptr1
, ptr2
, 0);
520 /* ---------------------------------------------------------------------------
521 * recovers an object from a FLAG change operation
524 UndoFlag (UndoListTypePtr Entry
)
526 void *ptr1
, *ptr2
, *ptr3
;
531 /* lookup entry by ID */
533 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
537 PinTypePtr pin
= (PinTypePtr
) ptr2
;
539 if (TEST_FLAG (LOCKFLAG
, pin
))
545 f1
= MaskFlags (pin
->Flags
, ~DRAW_FLAGS
);
546 f2
= MaskFlags (Entry
->Data
.Flags
, ~DRAW_FLAGS
);
548 if (!FLAGS_EQUAL (f1
, f2
))
551 if (andDraw
&& must_redraw
)
552 EraseObject (type
, ptr1
, ptr2
);
554 pin
->Flags
= Entry
->Data
.Flags
;
556 Entry
->Data
.Flags
= swap
;
558 if (andDraw
&& must_redraw
)
559 DrawObject (type
, ptr1
, ptr2
, 0);
562 Message ("hace Internal error: Can't find ID %d type %08x\n", Entry
->ID
,
564 Message ("for UndoFlag Operation. Previous flags: %s\n",
565 flags_to_string (Entry
->Data
.Flags
, 0));
569 /* ---------------------------------------------------------------------------
570 * recovers an object from a mirror operation
571 * returns True if anything has been recovered
574 UndoMirror (UndoListTypePtr Entry
)
576 void *ptr1
, *ptr2
, *ptr3
;
579 /* lookup entry by ID */
581 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
582 if (type
== ELEMENT_TYPE
)
584 ElementTypePtr element
= (ElementTypePtr
) ptr3
;
585 if (TEST_FLAG (LOCKFLAG
, element
))
588 EraseElement (element
);
589 MirrorElementCoordinates (PCB
->Data
, element
, Entry
->Data
.Move
.DY
);
591 DrawElement (element
, 0);
594 Message ("hace Internal error: UndoMirror on object type %d\n", type
);
598 /* ---------------------------------------------------------------------------
599 * recovers an object from a 'copy' or 'create' operation
600 * returns True if anything has been recovered
603 UndoCopyOrCreate (UndoListTypePtr Entry
)
605 void *ptr1
, *ptr2
, *ptr3
;
608 /* lookup entry by it's ID */
610 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
613 if (TEST_FLAG (LOCKFLAG
, (PinTypePtr
) ptr2
))
616 RemoveList
= CreateNewBuffer ();
618 EraseObject (type
, ptr1
, ptr2
);
619 /* in order to make this re-doable we move it to the RemoveList */
620 MoveObjectToBuffer (RemoveList
, PCB
->Data
, type
, ptr1
, ptr2
, ptr3
);
621 Entry
->Type
= UNDO_REMOVE
;
627 /* ---------------------------------------------------------------------------
628 * recovers an object from a 'move' operation
629 * returns True if anything has been recovered
632 UndoMove (UndoListTypePtr Entry
)
634 void *ptr1
, *ptr2
, *ptr3
;
637 /* lookup entry by it's ID */
639 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
642 if (TEST_FLAG (LOCKFLAG
, (LineTypePtr
) ptr2
))
644 MoveObject (type
, ptr1
, ptr2
, ptr3
,
645 -Entry
->Data
.Move
.DX
, -Entry
->Data
.Move
.DY
);
646 Entry
->Data
.Move
.DX
*= -1;
647 Entry
->Data
.Move
.DY
*= -1;
653 /* ----------------------------------------------------------------------
654 * recovers an object from a 'remove' operation
655 * returns True if anything has been recovered
658 UndoRemove (UndoListTypePtr Entry
)
660 void *ptr1
, *ptr2
, *ptr3
;
663 /* lookup entry by it's ID */
665 SearchObjectByID (RemoveList
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
,
670 DrawRecoveredObject (type
, ptr1
, ptr2
, ptr3
);
671 MoveObjectToBuffer (PCB
->Data
, RemoveList
, type
, ptr1
, ptr2
, ptr3
);
672 Entry
->Type
= UNDO_CREATE
;
678 /* ----------------------------------------------------------------------
679 * recovers an object from a 'move to another layer' operation
680 * returns True if anything has been recovered
683 UndoMoveToLayer (UndoListTypePtr Entry
)
685 void *ptr1
, *ptr2
, *ptr3
;
688 /* lookup entry by it's ID */
690 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
693 if (TEST_FLAG (LOCKFLAG
, (LineTypePtr
) ptr2
))
695 swap
= GetLayerNumber (PCB
->Data
, (LayerTypePtr
) ptr1
);
696 MoveObjectToLayer (type
, ptr1
, ptr2
, ptr3
,
697 LAYER_PTR (Entry
->Data
.
698 MoveToLayer
.OriginalLayer
), True
);
699 Entry
->Data
.MoveToLayer
.OriginalLayer
= swap
;
705 /* ---------------------------------------------------------------------------
706 * recovers a removed polygon point
707 * returns true on success
710 UndoRemovePoint (UndoListTypePtr Entry
)
713 PolygonTypePtr polygon
;
717 /* lookup entry (polygon not point was saved) by it's ID */
718 assert (Entry
->Kind
== POLYGON_TYPE
);
720 SearchObjectByID (PCB
->Data
, (void *) &layer
, (void *) &polygon
, &ptr3
,
721 Entry
->ID
, Entry
->Kind
);
724 case POLYGON_TYPE
: /* restore the removed point */
726 if (TEST_FLAG (LOCKFLAG
, polygon
))
728 /* recover the point */
729 if (andDraw
&& layer
->On
)
730 ErasePolygon (polygon
);
731 InsertPointIntoObject (POLYGON_TYPE
, layer
, polygon
,
732 &Entry
->Data
.RemovedPoint
.Index
,
733 Entry
->Data
.RemovedPoint
.X
,
734 Entry
->Data
.RemovedPoint
.Y
, True
);
735 polygon
->Points
[Entry
->Data
.RemovedPoint
.Index
].ID
=
736 Entry
->Data
.RemovedPoint
.ID
;
737 if (andDraw
&& layer
->On
)
738 DrawPolygon (layer
, polygon
, 0);
739 Entry
->Type
= UNDO_INSERT_POINT
;
740 Entry
->ID
= Entry
->Data
.RemovedPoint
.ID
;
741 Entry
->Kind
= POLYGONPOINT_TYPE
;
750 /* ---------------------------------------------------------------------------
751 * recovers an inserted polygon point
752 * returns true on success
755 UndoInsertPoint (UndoListTypePtr Entry
)
758 PolygonTypePtr polygon
;
762 assert (Entry
->Kind
== POLYGONPOINT_TYPE
);
763 /* lookup entry by it's ID */
765 SearchObjectByID (PCB
->Data
, (void *) &layer
, (void *) &polygon
,
766 (void *) &pnt
, Entry
->ID
, Entry
->Kind
);
769 case POLYGONPOINT_TYPE
: /* removes an inserted polygon point */
771 if (TEST_FLAG (LOCKFLAG
, polygon
))
773 if (andDraw
&& layer
->On
)
774 ErasePolygon (polygon
);
775 Entry
->Data
.RemovedPoint
.X
= pnt
->X
;
776 Entry
->Data
.RemovedPoint
.Y
= pnt
->Y
;
777 Entry
->Data
.RemovedPoint
.ID
= pnt
->ID
;
778 Entry
->ID
= polygon
->ID
;
779 Entry
->Kind
= POLYGON_TYPE
;
780 Entry
->Type
= UNDO_REMOVE_POINT
;
781 POLYGONPOINT_LOOP (polygon
);
785 Entry
->Data
.RemovedPoint
.Index
= n
;
790 DestroyObject (PCB
->Data
, POLYGONPOINT_TYPE
, layer
, polygon
, pnt
);
791 if (andDraw
&& layer
->On
)
792 DrawPolygon (layer
, polygon
, 0);
801 /* ---------------------------------------------------------------------------
802 * undo a layer change
803 * returns true on success
806 UndoLayerChange (UndoListTypePtr Entry
)
808 LayerChangeTypePtr l
= &Entry
->Data
.LayerChange
;
812 l
->new_index
= l
->old_index
;
815 if (MoveLayer (l
->old_index
, l
->new_index
))
821 /* ---------------------------------------------------------------------------
822 * undo a netlist change
823 * returns true on success
826 UndoNetlistChange (UndoListTypePtr Entry
)
828 NetlistChangeTypePtr l
= & Entry
->Data
.NetlistChange
;
830 LibraryTypePtr lib
, saved
;
835 /* iterate over each net */
836 for (i
= 0 ; i
< lib
->MenuN
; i
++)
838 if (lib
->Menu
[i
].Name
)
839 free (lib
->Menu
[i
].Name
);
841 if (lib
->Menu
[i
].directory
)
842 free (lib
->Menu
[i
].directory
);
844 if (lib
->Menu
[i
].Style
)
845 free (lib
->Menu
[i
].Style
);
847 /* iterate over each pin on the net */
848 for (j
= 0; j
< lib
->Menu
[i
].EntryN
; j
++) {
850 if (lib
->Menu
[i
].Entry
[j
].ListEntry
)
851 free (lib
->Menu
[i
].Entry
[j
].ListEntry
);
853 if (lib
->Menu
[i
].Entry
[j
].AllocatedMemory
)
854 free (lib
->Menu
[i
].Entry
[j
].AllocatedMemory
);
856 if (lib
->Menu
[i
].Entry
[j
].Template
)
857 free (lib
->Menu
[i
].Entry
[j
].Template
);
859 if (lib
->Menu
[i
].Entry
[j
].Package
)
860 free (lib
->Menu
[i
].Entry
[j
].Package
);
862 if (lib
->Menu
[i
].Entry
[j
].Value
)
863 free (lib
->Menu
[i
].Entry
[j
].Value
);
865 if (lib
->Menu
[i
].Entry
[j
].Description
)
866 free (lib
->Menu
[i
].Entry
[j
].Description
);
880 /* ---------------------------------------------------------------------------
881 * undo of any 'hard to recover' operation
883 * returns the bitfield for the types of operations that were undone
892 unique
= TEST_FLAG (UNIQUENAMEFLAG
, PCB
);
893 CLEAR_FLAG (UNIQUENAMEFLAG
, PCB
);
902 Message (_("Nothing to undo - buffer is empty\n"));
908 /* lock undo module to prevent from loops
909 * and loop over all entries with the same serial number
911 ptr
= &UndoList
[UndoN
- 1];
912 if (ptr
->Serial
!= Serial
- 1)
914 Message (_("Undo bad serial number %d expecting %d\n"),
915 ptr
->Serial
, Serial
- 1);
916 Serial
= ptr
->Serial
+ 1;
920 Serial
= ptr
->Serial
;
921 for (; UndoN
&& ptr
->Serial
== Serial
; ptr
--, UndoN
--, RedoN
++)
922 Types
|= PerformUndo (ptr
);
927 if (Types
&& andDraw
)
930 /* restore the unique flag setting */
932 SET_FLAG (UNIQUENAMEFLAG
, PCB
);
938 PerformUndo (UndoListTypePtr ptr
)
942 case UNDO_CHANGENAME
:
943 if (UndoChangeName (ptr
))
944 return (UNDO_CHANGENAME
);
948 if (UndoCopyOrCreate (ptr
))
949 return (UNDO_CREATE
);
958 if (UndoRemove (ptr
))
959 return (UNDO_REMOVE
);
962 case UNDO_REMOVE_POINT
:
963 if (UndoRemovePoint (ptr
))
964 return (UNDO_REMOVE_POINT
);
967 case UNDO_INSERT_POINT
:
968 if (UndoInsertPoint (ptr
))
969 return (UNDO_INSERT_POINT
);
973 if (UndoRotate (ptr
))
974 return (UNDO_ROTATE
);
978 if (UndoClearPoly (ptr
))
982 case UNDO_MOVETOLAYER
:
983 if (UndoMoveToLayer (ptr
))
984 return (UNDO_MOVETOLAYER
);
992 case UNDO_CHANGESIZE
:
993 if (UndoChangeSize (ptr
))
994 return (UNDO_CHANGESIZE
);
997 case UNDO_CHANGECLEARSIZE
:
998 if (UndoChangeClearSize (ptr
))
999 return (UNDO_CHANGECLEARSIZE
);
1002 case UNDO_CHANGEMASKSIZE
:
1003 if (UndoChangeMaskSize (ptr
))
1004 return (UNDO_CHANGEMASKSIZE
);
1007 case UNDO_CHANGE2NDSIZE
:
1008 if (UndoChange2ndSize (ptr
))
1009 return (UNDO_CHANGE2NDSIZE
);
1012 case UNDO_CHANGEANGLES
:
1013 if (UndoChangeAngles (ptr
))
1014 return (UNDO_CHANGEANGLES
);
1017 case UNDO_LAYERCHANGE
:
1018 if (UndoLayerChange (ptr
))
1019 return (UNDO_LAYERCHANGE
);
1022 case UNDO_NETLISTCHANGE
:
1023 if (UndoNetlistChange (ptr
))
1024 return (UNDO_NETLISTCHANGE
);
1028 if (UndoMirror (ptr
))
1029 return (UNDO_MIRROR
);
1035 /* ---------------------------------------------------------------------------
1036 * redo of any 'hard to recover' operation
1038 * returns the number of operations redone
1043 UndoListTypePtr ptr
;
1053 ("Nothing to redo. Perhaps changes have been made since last undo\n"));
1057 /* lock undo module to prevent from loops
1058 * and loop over all entries with the same serial number
1061 ptr
= &UndoList
[UndoN
];
1062 Serial
= ptr
->Serial
;
1063 for (; RedoN
&& ptr
->Serial
== Serial
; ptr
++, UndoN
++, RedoN
--)
1064 Types
|= PerformUndo (ptr
);
1065 /* Make next serial number current in case we take a new branch */
1070 if (Types
&& andDraw
)
1075 /* ---------------------------------------------------------------------------
1076 * restores the serial number of the undo list
1079 RestoreUndoSerialNumber (void)
1081 Serial
= SavedSerial
;
1084 /* ---------------------------------------------------------------------------
1085 * saves the serial number of the undo list
1088 SaveUndoSerialNumber (void)
1091 SavedSerial
= Serial
;
1094 /* ---------------------------------------------------------------------------
1095 * increments the serial number of the undo list
1096 * it's not done automatically because some operations perform more
1097 * than one request with the same serial #
1100 IncrementUndoSerialNumber (void)
1104 /* don't increment if nothing was added */
1105 if (UndoN
== 0 || UndoList
[UndoN
- 1].Serial
!= Serial
)
1109 SetChangedFlag (True
);
1113 /* ---------------------------------------------------------------------------
1114 * releases memory of the undo- and remove list
1117 ClearUndoList (Boolean Force
)
1119 UndoListTypePtr undo
;
1122 && (Force
|| gui
->confirm_dialog ("OK to clear 'undo' buffer?", 0)))
1124 /* release memory allocated by objects in undo list */
1125 for (undo
= UndoList
; UndoN
; undo
++, UndoN
--)
1127 if (undo
->Type
== UNDO_CHANGENAME
)
1128 SaveFree (undo
->Data
.ChangeName
.Name
);
1133 FreeDataMemory (RemoveList
);
1138 /* reset some counters */
1139 UndoN
= UndoMax
= RedoN
= 0;
1142 /* reset counter in any case */
1146 /* ---------------------------------------------------------------------------
1147 * adds an object to the list of clearpoly objects
1150 AddObjectToClearPolyUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
,
1153 UndoListTypePtr undo
;
1157 undo
= GetUndoSlot (UNDO_CLEAR
, OBJECT_ID (Ptr3
), Type
);
1158 undo
->Data
.ClearPoly
.Clear
= clear
;
1159 undo
->Data
.ClearPoly
.Layer
= (LayerTypePtr
) Ptr1
;
1163 /* ---------------------------------------------------------------------------
1164 * adds an object to the list of mirrored objects
1167 AddObjectToMirrorUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
,
1170 UndoListTypePtr undo
;
1174 undo
= GetUndoSlot (UNDO_MIRROR
, OBJECT_ID (Ptr3
), Type
);
1175 undo
->Data
.Move
.DY
= yoff
;
1179 /* ---------------------------------------------------------------------------
1180 * adds an object to the list of rotated objects
1183 AddObjectToRotateUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
,
1184 LocationType CenterX
, LocationType CenterY
,
1187 UndoListTypePtr undo
;
1191 undo
= GetUndoSlot (UNDO_ROTATE
, OBJECT_ID (Ptr3
), Type
);
1192 undo
->Data
.Rotate
.CenterX
= CenterX
;
1193 undo
->Data
.Rotate
.CenterY
= CenterY
;
1194 undo
->Data
.Rotate
.Steps
= Steps
;
1198 /* ---------------------------------------------------------------------------
1199 * adds an object to the list of removed objects and removes it from
1203 MoveObjectToRemoveUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
1205 UndoListTypePtr undo
;
1210 RemoveList
= CreateNewBuffer ();
1212 undo
= GetUndoSlot (UNDO_REMOVE
, OBJECT_ID (Ptr3
), Type
);
1213 MoveObjectToBuffer (RemoveList
, PCB
->Data
, Type
, Ptr1
, Ptr2
, Ptr3
);
1217 /* ---------------------------------------------------------------------------
1218 * adds an object to the list of removed polygon/... points
1221 AddObjectToRemovePointUndoList (int Type
,
1222 void *Ptr1
, void *Ptr2
, Cardinal index
)
1224 UndoListTypePtr undo
;
1225 PolygonTypePtr polygon
= (PolygonTypePtr
) Ptr2
;
1231 case POLYGONPOINT_TYPE
:
1233 /* save the ID of the parent object; else it will be
1234 * impossible to recover the point
1237 GetUndoSlot (UNDO_REMOVE_POINT
, OBJECT_ID (polygon
),
1239 undo
->Data
.RemovedPoint
.X
= polygon
->Points
[index
].X
;
1240 undo
->Data
.RemovedPoint
.Y
= polygon
->Points
[index
].Y
;
1241 undo
->Data
.RemovedPoint
.ID
= polygon
->Points
[index
].ID
;
1242 undo
->Data
.RemovedPoint
.Index
= index
;
1249 /* ---------------------------------------------------------------------------
1250 * adds an object to the list of inserted polygon/... points
1253 AddObjectToInsertPointUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
1255 UndoListTypePtr undo
;
1258 undo
= GetUndoSlot (UNDO_INSERT_POINT
, OBJECT_ID (Ptr3
), Type
);
1261 /* ---------------------------------------------------------------------------
1262 * adds an object to the list of moved objects
1265 AddObjectToMoveUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
,
1266 LocationType DX
, LocationType DY
)
1268 UndoListTypePtr undo
;
1272 undo
= GetUndoSlot (UNDO_MOVE
, OBJECT_ID (Ptr3
), Type
);
1273 undo
->Data
.Move
.DX
= DX
;
1274 undo
->Data
.Move
.DY
= DY
;
1278 /* ---------------------------------------------------------------------------
1279 * adds an object to the list of objects with changed names
1282 AddObjectToChangeNameUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
,
1285 UndoListTypePtr undo
;
1289 undo
= GetUndoSlot (UNDO_CHANGENAME
, OBJECT_ID (Ptr3
), Type
);
1290 undo
->Data
.ChangeName
.Name
= OldName
;
1294 /* ---------------------------------------------------------------------------
1295 * adds an object to the list of objects moved to another layer
1298 AddObjectToMoveToLayerUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
1300 UndoListTypePtr undo
;
1304 undo
= GetUndoSlot (UNDO_MOVETOLAYER
, OBJECT_ID (Ptr3
), Type
);
1305 undo
->Data
.MoveToLayer
.OriginalLayer
=
1306 GetLayerNumber (PCB
->Data
, (LayerTypePtr
) Ptr1
);
1310 /* ---------------------------------------------------------------------------
1311 * adds an object to the list of created objects
1314 AddObjectToCreateUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
1316 UndoListTypePtr undo
;
1319 undo
= GetUndoSlot (UNDO_CREATE
, OBJECT_ID (Ptr3
), Type
);
1320 ClearFromPolygon (PCB
->Data
, Type
, Ptr1
, Ptr2
);
1323 /* ---------------------------------------------------------------------------
1324 * adds an object to the list of objects with flags changed
1327 AddObjectToFlagUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
1329 UndoListTypePtr undo
;
1333 undo
= GetUndoSlot (UNDO_FLAG
, OBJECT_ID (Ptr2
), Type
);
1334 undo
->Data
.Flags
= ((PinTypePtr
) Ptr2
)->Flags
;
1338 /* ---------------------------------------------------------------------------
1339 * adds an object to the list of objects with Size changes
1342 AddObjectToSizeUndoList (int Type
, void *ptr1
, void *ptr2
, void *ptr3
)
1344 UndoListTypePtr undo
;
1348 undo
= GetUndoSlot (UNDO_CHANGESIZE
, OBJECT_ID (ptr2
), Type
);
1353 undo
->Data
.Size
= ((PinTypePtr
) ptr2
)->Thickness
;
1356 case ELEMENTLINE_TYPE
:
1357 undo
->Data
.Size
= ((LineTypePtr
) ptr2
)->Thickness
;
1360 case ELEMENTNAME_TYPE
:
1361 undo
->Data
.Size
= ((TextTypePtr
) ptr2
)->Scale
;
1364 undo
->Data
.Size
= ((PadTypePtr
) ptr2
)->Thickness
;
1367 case ELEMENTARC_TYPE
:
1368 undo
->Data
.Size
= ((ArcTypePtr
) ptr2
)->Thickness
;
1374 /* ---------------------------------------------------------------------------
1375 * adds an object to the list of objects with Size changes
1378 AddObjectToClearSizeUndoList (int Type
, void *ptr1
, void *ptr2
, void *ptr3
)
1380 UndoListTypePtr undo
;
1384 undo
= GetUndoSlot (UNDO_CHANGECLEARSIZE
, OBJECT_ID (ptr2
), Type
);
1389 undo
->Data
.Size
= ((PinTypePtr
) ptr2
)->Clearance
;
1392 undo
->Data
.Size
= ((LineTypePtr
) ptr2
)->Clearance
;
1395 undo
->Data
.Size
= ((PadTypePtr
) ptr2
)->Clearance
;
1398 undo
->Data
.Size
= ((ArcTypePtr
) ptr2
)->Clearance
;
1404 /* ---------------------------------------------------------------------------
1405 * adds an object to the list of objects with Size changes
1408 AddObjectToMaskSizeUndoList (int Type
, void *ptr1
, void *ptr2
, void *ptr3
)
1410 UndoListTypePtr undo
;
1414 undo
= GetUndoSlot (UNDO_CHANGEMASKSIZE
, OBJECT_ID (ptr2
), Type
);
1419 undo
->Data
.Size
= ((PinTypePtr
) ptr2
)->Mask
;
1422 undo
->Data
.Size
= ((PadTypePtr
) ptr2
)->Mask
;
1428 /* ---------------------------------------------------------------------------
1429 * adds an object to the list of objects with 2ndSize changes
1432 AddObjectTo2ndSizeUndoList (int Type
, void *ptr1
, void *ptr2
, void *ptr3
)
1434 UndoListTypePtr undo
;
1438 undo
= GetUndoSlot (UNDO_CHANGE2NDSIZE
, OBJECT_ID (ptr2
), Type
);
1439 if (Type
== PIN_TYPE
|| Type
== VIA_TYPE
)
1440 undo
->Data
.Size
= ((PinTypePtr
) ptr2
)->DrillingHole
;
1444 /* ---------------------------------------------------------------------------
1445 * adds an object to the list of changed angles. Note that you must
1446 * call this before changing the angles, passing the new start/delta.
1449 AddObjectToChangeAnglesUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
1451 UndoListTypePtr undo
;
1452 ArcTypePtr a
= (ArcTypePtr
) Ptr3
;
1456 undo
= GetUndoSlot (UNDO_CHANGEANGLES
, OBJECT_ID (Ptr3
), Type
);
1457 undo
->Data
.Move
.DX
= a
->StartAngle
;
1458 undo
->Data
.Move
.DY
= a
->Delta
;
1462 /* ---------------------------------------------------------------------------
1463 * adds a layer change (new, delete, move) to the undo list.
1466 AddLayerChangeToUndoList (int old_index
, int new_index
)
1468 UndoListTypePtr undo
;
1472 undo
= GetUndoSlot (UNDO_LAYERCHANGE
, 0, 0);
1473 undo
->Data
.LayerChange
.old_index
= old_index
;
1474 undo
->Data
.LayerChange
.new_index
= new_index
;
1478 /* ---------------------------------------------------------------------------
1479 * adds a netlist change to the undo list
1482 AddNetlistLibToUndoList (LibraryTypePtr lib
)
1484 UndoListTypePtr undo
;
1490 undo
= GetUndoSlot (UNDO_NETLISTCHANGE
, 0, 0);
1491 /* keep track of where the data needs to go */
1492 undo
->Data
.NetlistChange
.lib
= lib
;
1494 /* and what the old data is that we'll need to restore */
1495 undo
->Data
.NetlistChange
.old
= malloc (sizeof (LibraryTypePtr
));
1496 old
= undo
->Data
.NetlistChange
.old
;
1497 old
->MenuN
= lib
->MenuN
;
1498 old
->MenuMax
= lib
->MenuMax
;
1499 old
->Menu
= malloc (old
->MenuMax
* sizeof (LibraryMenuType
));
1500 if (old
->Menu
== NULL
)
1502 fprintf (stderr
, "malloc() failed in %s\n", __FUNCTION__
);
1506 /* iterate over each net */
1507 for (i
= 0 ; i
< lib
->MenuN
; i
++)
1509 old
->Menu
[i
].EntryN
= lib
->Menu
[i
].EntryN
;
1510 old
->Menu
[i
].EntryMax
= lib
->Menu
[i
].EntryMax
;
1513 lib
->Menu
[i
].Name
? strdup (lib
->Menu
[i
].Name
) : NULL
;
1515 old
->Menu
[i
].directory
=
1516 lib
->Menu
[i
].directory
? strdup (lib
->Menu
[i
].directory
) : NULL
;
1518 old
->Menu
[i
].Style
=
1519 lib
->Menu
[i
].Style
? strdup (lib
->Menu
[i
].Style
) : NULL
;
1522 old
->Menu
[i
].Entry
=
1523 malloc (old
->Menu
[i
].EntryMax
* sizeof (LibraryEntryType
));
1524 if (old
->Menu
[i
].Entry
== NULL
)
1526 fprintf (stderr
, "malloc() failed in %s\n", __FUNCTION__
);
1530 /* iterate over each pin on the net */
1531 for (j
= 0; j
< lib
->Menu
[i
].EntryN
; j
++) {
1533 old
->Menu
[i
].Entry
[j
].ListEntry
=
1534 lib
->Menu
[i
].Entry
[j
].ListEntry
?
1535 strdup (lib
->Menu
[i
].Entry
[j
].ListEntry
) :
1538 old
->Menu
[i
].Entry
[j
].AllocatedMemory
=
1539 lib
->Menu
[i
].Entry
[j
].AllocatedMemory
?
1540 strdup (lib
->Menu
[i
].Entry
[j
].AllocatedMemory
) :
1543 old
->Menu
[i
].Entry
[j
].Template
=
1544 lib
->Menu
[i
].Entry
[j
].Template
?
1545 strdup (lib
->Menu
[i
].Entry
[j
].Template
) :
1548 old
->Menu
[i
].Entry
[j
].Package
=
1549 lib
->Menu
[i
].Entry
[j
].Package
?
1550 strdup (lib
->Menu
[i
].Entry
[j
].Package
) :
1553 old
->Menu
[i
].Entry
[j
].Value
=
1554 lib
->Menu
[i
].Entry
[j
].Value
?
1555 strdup (lib
->Menu
[i
].Entry
[j
].Value
) :
1558 old
->Menu
[i
].Entry
[j
].Description
=
1559 lib
->Menu
[i
].Entry
[j
].Description
?
1560 strdup (lib
->Menu
[i
].Entry
[j
].Description
) :
1570 /* ---------------------------------------------------------------------------
1579 /* ---------------------------------------------------------------------------
1588 /* ---------------------------------------------------------------------------
1589 * return undo lock state