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 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 */
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 */
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 */
124 LayerChangeType
, *LayerChangeTypePtr
;
126 typedef struct /* information about poly clear/restore */
128 bool Clear
; /* true was clear, false was restore */
131 ClearPolyType
, *ClearPolyTypePtr
;
133 typedef struct /* information about netlist lib changes */
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 */
146 union /* some additional information */
148 ChangeNameType ChangeName
;
150 RemovedPointType RemovedPoint
;
152 MoveToLayerType MoveToLayer
;
155 LayerChangeType LayerChange
;
156 ClearPolyType ClearPoly
;
157 NetlistChangeType NetlistChange
;
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 */
171 static size_t UndoN
, RedoN
, /* number of entries */
173 static bool Locked
= false; /* do not add entries if */
174 static bool andDraw
= true;
175 /* flag is set; prevents from */
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
)
210 void *ptr1
, *ptr2
, *ptr3
;
212 static size_t limit
= UNDO_WARNING_SIZE
;
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
,
220 /* allocate memory */
221 if (UndoN
>= UndoMax
)
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 */
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
--)
244 case UNDO_CHANGENAME
:
245 free (ptr
->Data
.ChangeName
.Name
);
249 SearchObjectByID (RemoveList
, &ptr1
, &ptr2
, &ptr3
, ptr
->ID
,
253 DestroyObject (RemoveList
, type
, ptr1
, ptr2
, ptr3
);
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
;
268 ptr
->Serial
= Serial
;
272 /* ---------------------------------------------------------------------------
273 * redraws the recovered object
276 DrawRecoveredObject (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
278 if (Type
& (LINE_TYPE
| TEXT_TYPE
| POLYGON_TYPE
| ARC_TYPE
))
282 layer
= LAYER_PTR (GetLayerNumber (RemoveList
, (LayerTypePtr
) Ptr1
));
283 DrawObject (Type
, (void *) layer
, Ptr2
);
286 DrawObject (Type
, Ptr1
, Ptr2
);
289 /* ---------------------------------------------------------------------------
290 * recovers an object from a 'rotate' operation
291 * returns true if anything has been recovered
294 UndoRotate (UndoListTypePtr Entry
)
296 void *ptr1
, *ptr2
, *ptr3
;
299 /* lookup entry by it's ID */
301 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
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;
313 /* ---------------------------------------------------------------------------
314 * recovers an object from a clear/restore poly operation
315 * returns true if anything has been recovered
318 UndoClearPoly (UndoListTypePtr Entry
)
320 void *ptr1
, *ptr2
, *ptr3
;
324 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
327 if (Entry
->Data
.ClearPoly
.Clear
)
328 RestoreToPolygon (PCB
->Data
, type
, Entry
->Data
.ClearPoly
.Layer
, ptr3
);
330 ClearFromPolygon (PCB
->Data
, type
, Entry
->Data
.ClearPoly
.Layer
, ptr3
);
331 Entry
->Data
.ClearPoly
.Clear
= !Entry
->Data
.ClearPoly
.Clear
;
337 /* ---------------------------------------------------------------------------
338 * recovers an object from a 'change name' operation
339 * returns true if anything has been recovered
342 UndoChangeName (UndoListTypePtr Entry
)
344 void *ptr1
, *ptr2
, *ptr3
;
347 /* lookup entry by it's ID */
349 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
352 Entry
->Data
.ChangeName
.Name
=
353 (char *)(ChangeObjectName (type
, ptr1
, ptr2
, ptr3
,
354 Entry
->Data
.ChangeName
.Name
));
360 /* ---------------------------------------------------------------------------
361 * recovers an object from a 2ndSize change operation
364 UndoChange2ndSize (UndoListTypePtr Entry
)
366 void *ptr1
, *ptr2
, *ptr3
;
370 /* lookup entry by ID */
372 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
375 swap
= ((PinTypePtr
) ptr2
)->DrillingHole
;
377 EraseObject (type
, ptr1
, ptr2
);
378 ((PinTypePtr
) ptr2
)->DrillingHole
= Entry
->Data
.Size
;
379 Entry
->Data
.Size
= swap
;
380 DrawObject (type
, ptr1
, ptr2
);
386 /* ---------------------------------------------------------------------------
387 * recovers an object from a ChangeAngles change operation
390 UndoChangeAngles (UndoListTypePtr Entry
)
392 void *ptr1
, *ptr2
, *ptr3
;
394 long int old_sa
, old_da
;
396 /* lookup entry by ID */
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
;
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
);
420 /* ---------------------------------------------------------------------------
421 * recovers an object from a clearance size change operation
424 UndoChangeClearSize (UndoListTypePtr Entry
)
426 void *ptr1
, *ptr2
, *ptr3
;
430 /* lookup entry by ID */
432 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
435 swap
= ((PinTypePtr
) ptr2
)->Clearance
;
436 RestoreToPolygon (PCB
->Data
, type
, ptr1
, ptr2
);
438 EraseObject (type
, ptr1
, ptr2
);
439 ((PinTypePtr
) ptr2
)->Clearance
= Entry
->Data
.Size
;
440 ClearFromPolygon (PCB
->Data
, type
, ptr1
, ptr2
);
441 Entry
->Data
.Size
= swap
;
443 DrawObject (type
, ptr1
, ptr2
);
449 /* ---------------------------------------------------------------------------
450 * recovers an object from a mask size change operation
453 UndoChangeMaskSize (UndoListTypePtr Entry
)
455 void *ptr1
, *ptr2
, *ptr3
;
459 /* lookup entry by ID */
461 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
462 if (type
& (VIA_TYPE
| PIN_TYPE
| PAD_TYPE
))
466 PAD_TYPE
? ((PadTypePtr
) ptr2
)->Mask
: ((PinTypePtr
) ptr2
)->Mask
);
468 EraseObject (type
, ptr1
, ptr2
);
469 if (type
== PAD_TYPE
)
470 ((PadTypePtr
) ptr2
)->Mask
= Entry
->Data
.Size
;
472 ((PinTypePtr
) ptr2
)->Mask
= Entry
->Data
.Size
;
473 Entry
->Data
.Size
= swap
;
475 DrawObject (type
, ptr1
, ptr2
);
482 /* ---------------------------------------------------------------------------
483 * recovers an object from a Size change operation
486 UndoChangeSize (UndoListTypePtr Entry
)
488 void *ptr1
, *ptr2
, *ptr3
;
492 /* lookup entry by ID */
494 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
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
);
502 EraseObject (type
, ptr1
, ptr2
);
503 ((PinTypePtr
) ptr2
)->Thickness
= Entry
->Data
.Size
;
504 Entry
->Data
.Size
= swap
;
505 ClearFromPolygon (PCB
->Data
, type
, ptr1
, ptr2
);
507 DrawObject (type
, ptr1
, ptr2
);
513 /* ---------------------------------------------------------------------------
514 * recovers an object from a FLAG change operation
517 UndoFlag (UndoListTypePtr Entry
)
519 void *ptr1
, *ptr2
, *ptr3
;
524 /* lookup entry by ID */
526 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
530 PinTypePtr pin
= (PinTypePtr
) ptr2
;
535 f1
= MaskFlags (pin
->Flags
, ~DRAW_FLAGS
);
536 f2
= MaskFlags (Entry
->Data
.Flags
, ~DRAW_FLAGS
);
538 if (!FLAGS_EQUAL (f1
, f2
))
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
);
552 Message ("hace Internal error: Can't find ID %d type %08x\n", Entry
->ID
,
554 Message ("for UndoFlag Operation. Previous flags: %s\n",
555 flags_to_string (Entry
->Data
.Flags
, 0));
559 /* ---------------------------------------------------------------------------
560 * recovers an object from a mirror operation
561 * returns true if anything has been recovered
564 UndoMirror (UndoListTypePtr Entry
)
566 void *ptr1
, *ptr2
, *ptr3
;
569 /* lookup entry by ID */
571 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
572 if (type
== ELEMENT_TYPE
)
574 ElementTypePtr element
= (ElementTypePtr
) ptr3
;
576 EraseElement (element
);
577 MirrorElementCoordinates (PCB
->Data
, element
, Entry
->Data
.Move
.DY
);
579 DrawElement (element
);
582 Message ("hace Internal error: UndoMirror on object type %d\n", type
);
586 /* ---------------------------------------------------------------------------
587 * recovers an object from a 'copy' or 'create' operation
588 * returns true if anything has been recovered
591 UndoCopyOrCreate (UndoListTypePtr Entry
)
593 void *ptr1
, *ptr2
, *ptr3
;
596 /* lookup entry by it's ID */
598 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
602 RemoveList
= CreateNewBuffer ();
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
;
613 /* ---------------------------------------------------------------------------
614 * recovers an object from a 'move' operation
615 * returns true if anything has been recovered
618 UndoMove (UndoListTypePtr Entry
)
620 void *ptr1
, *ptr2
, *ptr3
;
623 /* lookup entry by it's ID */
625 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
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;
637 /* ----------------------------------------------------------------------
638 * recovers an object from a 'remove' operation
639 * returns true if anything has been recovered
642 UndoRemove (UndoListTypePtr Entry
)
644 void *ptr1
, *ptr2
, *ptr3
;
647 /* lookup entry by it's ID */
649 SearchObjectByID (RemoveList
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
,
654 DrawRecoveredObject (type
, ptr1
, ptr2
, ptr3
);
655 MoveObjectToBuffer (PCB
->Data
, RemoveList
, type
, ptr1
, ptr2
, ptr3
);
656 Entry
->Type
= UNDO_CREATE
;
662 /* ----------------------------------------------------------------------
663 * recovers an object from a 'move to another layer' operation
664 * returns true if anything has been recovered
667 UndoMoveToLayer (UndoListTypePtr Entry
)
669 void *ptr1
, *ptr2
, *ptr3
;
672 /* lookup entry by it's ID */
674 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
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
;
687 /* ---------------------------------------------------------------------------
688 * recovers a removed polygon point
689 * returns true on success
692 UndoRemovePoint (UndoListTypePtr Entry
)
695 PolygonTypePtr polygon
;
699 /* lookup entry (polygon not point was saved) by it's ID */
700 assert (Entry
->Kind
== POLYGON_TYPE
);
702 SearchObjectByID (PCB
->Data
, (void **) &layer
, (void **) &polygon
, &ptr3
,
703 Entry
->ID
, Entry
->Kind
);
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
;
732 /* ---------------------------------------------------------------------------
733 * recovers an inserted polygon point
734 * returns true on success
737 UndoInsertPoint (UndoListTypePtr Entry
)
740 PolygonTypePtr polygon
;
745 bool last_in_contour
= false;
747 assert (Entry
->Kind
== POLYGONPOINT_TYPE
);
748 /* lookup entry by it's ID */
750 SearchObjectByID (PCB
->Data
, (void **) &layer
, (void **) &polygon
,
751 (void **) &pnt
, Entry
->ID
, Entry
->Kind
);
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
);
790 UndoSwapCopiedObject (UndoListTypePtr Entry
)
792 void *ptr1
, *ptr2
, *ptr3
;
793 void *ptr1b
, *ptr2b
, *ptr3b
;
794 AnyObjectType
*obj
, *obj2
;
798 /* lookup entry by it's ID */
800 SearchObjectByID (RemoveList
, &ptr1
, &ptr2
, &ptr3
, Entry
->Data
.CopyID
,
806 SearchObjectByID (PCB
->Data
, &ptr1b
, &ptr2b
, &ptr3b
, Entry
->ID
,
811 obj
= (AnyObjectType
*)ptr2
;
812 obj2
= (AnyObjectType
*)ptr2b
;
818 MoveObjectToBuffer (RemoveList
, PCB
->Data
, type
, ptr1b
, ptr2b
, ptr3b
);
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
);
829 /* ---------------------------------------------------------------------------
830 * recovers an removed polygon point
831 * returns true on success
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
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
856 UndoLayerChange (UndoListTypePtr Entry
)
858 LayerChangeTypePtr l
= &Entry
->Data
.LayerChange
;
862 l
->new_index
= l
->old_index
;
865 if (MoveLayer (l
->old_index
, l
->new_index
))
871 /* ---------------------------------------------------------------------------
872 * undo a netlist change
873 * returns true on success
876 UndoNetlistChange (UndoListTypePtr Entry
)
878 NetlistChangeTypePtr l
= & Entry
->Data
.NetlistChange
;
880 LibraryTypePtr lib
, saved
;
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
);
930 /* ---------------------------------------------------------------------------
931 * undo of any 'hard to recover' operation
933 * returns the bitfield for the types of operations that were undone
941 bool error_undoing
= false;
943 unique
= TEST_FLAG (UNIQUENAMEFLAG
, PCB
);
944 CLEAR_FLAG (UNIQUENAMEFLAG
, PCB
);
950 Message (_("ERROR: Attempt to Undo() with Serial == 0\n"
951 " Please save your work and report this bug.\n"));
957 Message (_("Nothing to undo - buffer is empty\n"));
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;
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
);
989 error_undoing
= true;
996 Message (_("ERROR: Failed to undo some operations\n"));
998 if (Types
&& andDraw
)
1001 /* restore the unique flag setting */
1003 SET_FLAG (UNIQUENAMEFLAG
, PCB
);
1009 PerformUndo (UndoListTypePtr ptr
)
1013 case UNDO_CHANGENAME
:
1014 if (UndoChangeName (ptr
))
1015 return (UNDO_CHANGENAME
);
1019 if (UndoCopyOrCreate (ptr
))
1020 return (UNDO_CREATE
);
1029 if (UndoRemove (ptr
))
1030 return (UNDO_REMOVE
);
1033 case UNDO_REMOVE_POINT
:
1034 if (UndoRemovePoint (ptr
))
1035 return (UNDO_REMOVE_POINT
);
1038 case UNDO_INSERT_POINT
:
1039 if (UndoInsertPoint (ptr
))
1040 return (UNDO_INSERT_POINT
);
1043 case UNDO_REMOVE_CONTOUR
:
1044 if (UndoRemoveContour (ptr
))
1045 return (UNDO_REMOVE_CONTOUR
);
1048 case UNDO_INSERT_CONTOUR
:
1049 if (UndoInsertContour (ptr
))
1050 return (UNDO_INSERT_CONTOUR
);
1054 if (UndoRotate (ptr
))
1055 return (UNDO_ROTATE
);
1059 if (UndoClearPoly (ptr
))
1060 return (UNDO_CLEAR
);
1063 case UNDO_MOVETOLAYER
:
1064 if (UndoMoveToLayer (ptr
))
1065 return (UNDO_MOVETOLAYER
);
1073 case UNDO_CHANGESIZE
:
1074 if (UndoChangeSize (ptr
))
1075 return (UNDO_CHANGESIZE
);
1078 case UNDO_CHANGECLEARSIZE
:
1079 if (UndoChangeClearSize (ptr
))
1080 return (UNDO_CHANGECLEARSIZE
);
1083 case UNDO_CHANGEMASKSIZE
:
1084 if (UndoChangeMaskSize (ptr
))
1085 return (UNDO_CHANGEMASKSIZE
);
1088 case UNDO_CHANGE2NDSIZE
:
1089 if (UndoChange2ndSize (ptr
))
1090 return (UNDO_CHANGE2NDSIZE
);
1093 case UNDO_CHANGEANGLES
:
1094 if (UndoChangeAngles (ptr
))
1095 return (UNDO_CHANGEANGLES
);
1098 case UNDO_LAYERCHANGE
:
1099 if (UndoLayerChange (ptr
))
1100 return (UNDO_LAYERCHANGE
);
1103 case UNDO_NETLISTCHANGE
:
1104 if (UndoNetlistChange (ptr
))
1105 return (UNDO_NETLISTCHANGE
);
1109 if (UndoMirror (ptr
))
1110 return (UNDO_MIRROR
);
1116 /* ---------------------------------------------------------------------------
1117 * redo of any 'hard to recover' operation
1119 * returns the number of operations redone
1124 UndoListTypePtr ptr
;
1126 bool error_undoing
= false;
1132 Message (_("Nothing to redo. Perhaps changes have been made since last undo\n"));
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
;
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
);
1162 error_undoing
= true;
1166 /* Make next serial number current */
1172 Message (_("ERROR: Failed to redo some operations\n"));
1174 if (Types
&& andDraw
)
1180 /* ---------------------------------------------------------------------------
1181 * restores the serial number of the undo list
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
1197 SaveUndoSerialNumber (void)
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 #
1211 IncrementUndoSerialNumber (void)
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);
1220 between_increment_and_restore
= true;
1224 /* ---------------------------------------------------------------------------
1225 * releases memory of the undo- and remove list
1228 ClearUndoList (bool Force
)
1230 UndoListTypePtr undo
;
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
);
1245 FreeDataMemory (RemoveList
);
1250 /* reset some counters */
1251 UndoN
= UndoMax
= RedoN
= 0;
1254 /* reset counter in any case */
1258 /* ---------------------------------------------------------------------------
1259 * adds an object to the list of clearpoly objects
1262 AddObjectToClearPolyUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
,
1265 UndoListTypePtr undo
;
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
1279 AddObjectToMirrorUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
,
1282 UndoListTypePtr undo
;
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
1295 AddObjectToRotateUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
,
1296 Coord CenterX
, Coord CenterY
,
1299 UndoListTypePtr undo
;
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
1315 MoveObjectToRemoveUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
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
1331 AddObjectToRemovePointUndoList (int Type
,
1332 void *Ptr1
, void *Ptr2
, Cardinal index
)
1334 UndoListTypePtr undo
;
1335 PolygonTypePtr polygon
= (PolygonTypePtr
) Ptr2
;
1337 bool last_in_contour
= false;
1343 case POLYGONPOINT_TYPE
:
1345 /* save the ID of the parent object; else it will be
1346 * impossible to recover the point
1349 GetUndoSlot (UNDO_REMOVE_POINT
, OBJECT_ID (polygon
),
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
;
1372 /* ---------------------------------------------------------------------------
1373 * adds an object to the list of inserted polygon/... points
1376 AddObjectToInsertPointUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
1379 GetUndoSlot (UNDO_INSERT_POINT
, OBJECT_ID (Ptr3
), Type
);
1383 CopyObjectToUndoList (int undo_type
, int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
1385 UndoListTypePtr undo
;
1386 AnyObjectType
*copy
;
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)
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)
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
1425 AddObjectToMoveUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
,
1428 UndoListTypePtr undo
;
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
1442 AddObjectToChangeNameUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
,
1445 UndoListTypePtr undo
;
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
1458 AddObjectToMoveToLayerUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
1460 UndoListTypePtr undo
;
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
1474 AddObjectToCreateUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
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
1485 AddObjectToFlagUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
1487 UndoListTypePtr undo
;
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
1500 AddObjectToSizeUndoList (int Type
, void *ptr1
, void *ptr2
, void *ptr3
)
1502 UndoListTypePtr undo
;
1506 undo
= GetUndoSlot (UNDO_CHANGESIZE
, OBJECT_ID (ptr2
), Type
);
1511 undo
->Data
.Size
= ((PinTypePtr
) ptr2
)->Thickness
;
1514 case ELEMENTLINE_TYPE
:
1515 undo
->Data
.Size
= ((LineTypePtr
) ptr2
)->Thickness
;
1518 case ELEMENTNAME_TYPE
:
1519 undo
->Data
.Size
= ((TextTypePtr
) ptr2
)->Scale
;
1522 undo
->Data
.Size
= ((PadTypePtr
) ptr2
)->Thickness
;
1525 case ELEMENTARC_TYPE
:
1526 undo
->Data
.Size
= ((ArcTypePtr
) ptr2
)->Thickness
;
1532 /* ---------------------------------------------------------------------------
1533 * adds an object to the list of objects with Size changes
1536 AddObjectToClearSizeUndoList (int Type
, void *ptr1
, void *ptr2
, void *ptr3
)
1538 UndoListTypePtr undo
;
1542 undo
= GetUndoSlot (UNDO_CHANGECLEARSIZE
, OBJECT_ID (ptr2
), Type
);
1547 undo
->Data
.Size
= ((PinTypePtr
) ptr2
)->Clearance
;
1550 undo
->Data
.Size
= ((LineTypePtr
) ptr2
)->Clearance
;
1553 undo
->Data
.Size
= ((PadTypePtr
) ptr2
)->Clearance
;
1556 undo
->Data
.Size
= ((ArcTypePtr
) ptr2
)->Clearance
;
1562 /* ---------------------------------------------------------------------------
1563 * adds an object to the list of objects with Size changes
1566 AddObjectToMaskSizeUndoList (int Type
, void *ptr1
, void *ptr2
, void *ptr3
)
1568 UndoListTypePtr undo
;
1572 undo
= GetUndoSlot (UNDO_CHANGEMASKSIZE
, OBJECT_ID (ptr2
), Type
);
1577 undo
->Data
.Size
= ((PinTypePtr
) ptr2
)->Mask
;
1580 undo
->Data
.Size
= ((PadTypePtr
) ptr2
)->Mask
;
1586 /* ---------------------------------------------------------------------------
1587 * adds an object to the list of objects with 2ndSize changes
1590 AddObjectTo2ndSizeUndoList (int Type
, void *ptr1
, void *ptr2
, void *ptr3
)
1592 UndoListTypePtr undo
;
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.
1607 AddObjectToChangeAnglesUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
1609 UndoListTypePtr undo
;
1610 ArcTypePtr a
= (ArcTypePtr
) Ptr3
;
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.
1624 AddLayerChangeToUndoList (int old_index
, int new_index
)
1626 UndoListTypePtr undo
;
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
1640 AddNetlistLibToUndoList (LibraryTypePtr lib
)
1642 UndoListTypePtr undo
;
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__
);
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
;
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__
);
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
) :
1696 old
->Menu
[i
].Entry
[j
].AllocatedMemory
=
1697 lib
->Menu
[i
].Entry
[j
].AllocatedMemory
?
1698 strdup (lib
->Menu
[i
].Entry
[j
].AllocatedMemory
) :
1701 old
->Menu
[i
].Entry
[j
].Template
=
1702 lib
->Menu
[i
].Entry
[j
].Template
?
1703 strdup (lib
->Menu
[i
].Entry
[j
].Template
) :
1706 old
->Menu
[i
].Entry
[j
].Package
=
1707 lib
->Menu
[i
].Entry
[j
].Package
?
1708 strdup (lib
->Menu
[i
].Entry
[j
].Package
) :
1711 old
->Menu
[i
].Entry
[j
].Value
=
1712 lib
->Menu
[i
].Entry
[j
].Value
?
1713 strdup (lib
->Menu
[i
].Entry
[j
].Value
) :
1716 old
->Menu
[i
].Entry
[j
].Description
=
1717 lib
->Menu
[i
].Entry
[j
].Description
?
1718 strdup (lib
->Menu
[i
].Entry
[j
].Description
) :
1728 /* ---------------------------------------------------------------------------
1737 /* ---------------------------------------------------------------------------
1746 /* ---------------------------------------------------------------------------
1747 * return undo lock state