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 */
100 bool last_in_contour
; /* Whether the point was the last in its contour */
102 RemovedPointType
, *RemovedPointTypePtr
;
104 typedef struct /* information about rotation */
106 LocationType CenterX
, /* center of rotation */
108 BYTE Steps
; /* number of steps */
110 RotateType
, *RotateTypePtr
;
112 typedef struct /* information about moves between layers */
114 Cardinal OriginalLayer
; /* the index of the original layer */
116 MoveToLayerType
, *MoveToLayerTypePtr
;
118 typedef struct /* information about layer changes */
123 LayerChangeType
, *LayerChangeTypePtr
;
125 typedef struct /* information about poly clear/restore */
127 bool Clear
; /* true was clear, false was restore */
130 ClearPolyType
, *ClearPolyTypePtr
;
132 typedef struct /* information about netlist lib changes */
137 NetlistChangeType
, *NetlistChangeTypePtr
;
139 typedef struct /* holds information about an operation */
141 int Serial
, /* serial number of operation */
142 Type
, /* type of operation */
143 Kind
, /* type of object with given ID */
145 union /* some additional information */
147 ChangeNameType ChangeName
;
149 RemovedPointType RemovedPoint
;
151 MoveToLayerType MoveToLayer
;
154 LayerChangeType LayerChange
;
155 ClearPolyType ClearPoly
;
156 NetlistChangeType NetlistChange
;
161 UndoListType
, *UndoListTypePtr
;
163 /* ---------------------------------------------------------------------------
164 * some local variables
166 static DataTypePtr RemoveList
= NULL
; /* list of removed objects */
167 static UndoListTypePtr UndoList
= NULL
; /* list of operations */
168 static int Serial
= 1, /* serial number */
170 static size_t UndoN
, RedoN
, /* number of entries */
172 static bool Locked
= false; /* do not add entries if */
173 static bool andDraw
= true;
174 /* flag is set; prevents from */
177 /* ---------------------------------------------------------------------------
178 * some local prototypes
180 static UndoListTypePtr
GetUndoSlot (int, int, int);
181 static void DrawRecoveredObject (int, void *, void *, void *);
182 static bool UndoRotate (UndoListTypePtr
);
183 static bool UndoChangeName (UndoListTypePtr
);
184 static bool UndoCopyOrCreate (UndoListTypePtr
);
185 static bool UndoMove (UndoListTypePtr
);
186 static bool UndoRemove (UndoListTypePtr
);
187 static bool UndoRemovePoint (UndoListTypePtr
);
188 static bool UndoInsertPoint (UndoListTypePtr
);
189 static bool UndoRemoveContour (UndoListTypePtr
);
190 static bool UndoInsertContour (UndoListTypePtr
);
191 static bool UndoMoveToLayer (UndoListTypePtr
);
192 static bool UndoFlag (UndoListTypePtr
);
193 static bool UndoMirror (UndoListTypePtr
);
194 static bool UndoChangeSize (UndoListTypePtr
);
195 static bool UndoChange2ndSize (UndoListTypePtr
);
196 static bool UndoChangeAngles (UndoListTypePtr
);
197 static bool UndoChangeClearSize (UndoListTypePtr
);
198 static bool UndoChangeMaskSize (UndoListTypePtr
);
199 static bool UndoClearPoly (UndoListTypePtr
);
200 static int PerformUndo (UndoListTypePtr
);
202 /* ---------------------------------------------------------------------------
203 * adds a command plus some data to the undo list
205 static UndoListTypePtr
206 GetUndoSlot (int CommandType
, int ID
, int Kind
)
209 void *ptr1
, *ptr2
, *ptr3
;
211 static size_t limit
= UNDO_WARNING_SIZE
;
214 if (SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, ID
, Kind
) == NO_TYPE
)
215 Message ("hace: ID (%d) and Type (%x) mismatch in AddObject...\n", ID
,
219 /* allocate memory */
220 if (UndoN
>= UndoMax
)
224 UndoMax
+= STEP_UNDOLIST
;
225 size
= UndoMax
* sizeof (UndoListType
);
226 UndoList
= (UndoListTypePtr
) MyRealloc (UndoList
, size
,
227 "AddCommandToUndoList()");
228 memset (&UndoList
[UndoN
], 0, STEP_REMOVELIST
* sizeof (UndoListType
));
230 /* ask user to flush the table because of it's size */
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 SaveFree (ptr
->Data
.ChangeName
.Name
);
249 SearchObjectByID (RemoveList
, &ptr1
, &ptr2
, &ptr3
, ptr
->ID
,
253 DestroyObject (RemoveList
, type
, ptr1
, ptr2
, ptr3
);
260 /* copy typefield and serial number to the list */
261 ptr
= &UndoList
[UndoN
++];
262 ptr
->Type
= CommandType
;
265 ptr
->Serial
= Serial
;
269 /* ---------------------------------------------------------------------------
270 * redraws the recovered object
273 DrawRecoveredObject (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
275 if (Type
& (LINE_TYPE
| TEXT_TYPE
| POLYGON_TYPE
| ARC_TYPE
))
279 layer
= LAYER_PTR (GetLayerNumber (RemoveList
, (LayerTypePtr
) Ptr1
));
280 DrawObject (Type
, (void *) layer
, Ptr2
, 0);
283 DrawObject (Type
, Ptr1
, Ptr2
, 0);
286 /* ---------------------------------------------------------------------------
287 * recovers an object from a 'rotate' operation
288 * returns true if anything has been recovered
291 UndoRotate (UndoListTypePtr Entry
)
293 void *ptr1
, *ptr2
, *ptr3
;
296 /* lookup entry by it's ID */
298 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
301 if (TEST_FLAG (LOCKFLAG
, (ArcTypePtr
) ptr2
))
303 RotateObject (type
, ptr1
, ptr2
, ptr3
,
304 Entry
->Data
.Rotate
.CenterX
, Entry
->Data
.Rotate
.CenterY
,
305 (4 - Entry
->Data
.Rotate
.Steps
) & 0x03);
306 Entry
->Data
.Rotate
.Steps
= (4 - Entry
->Data
.Rotate
.Steps
) & 0x03;
312 /* ---------------------------------------------------------------------------
313 * recovers an object from a clear/restore poly operation
314 * returns true if anything has been recovered
317 UndoClearPoly (UndoListTypePtr Entry
)
319 void *ptr1
, *ptr2
, *ptr3
;
323 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
326 if (Entry
->Data
.ClearPoly
.Clear
)
327 RestoreToPolygon (PCB
->Data
, type
, Entry
->Data
.ClearPoly
.Layer
, ptr3
);
329 ClearFromPolygon (PCB
->Data
, type
, Entry
->Data
.ClearPoly
.Layer
, ptr3
);
330 Entry
->Data
.ClearPoly
.Clear
= !Entry
->Data
.ClearPoly
.Clear
;
336 /* ---------------------------------------------------------------------------
337 * recovers an object from a 'change name' operation
338 * returns true if anything has been recovered
341 UndoChangeName (UndoListTypePtr Entry
)
343 void *ptr1
, *ptr2
, *ptr3
;
346 /* lookup entry by it's ID */
348 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
351 if (TEST_FLAG (LOCKFLAG
, (TextTypePtr
) ptr3
))
353 Entry
->Data
.ChangeName
.Name
=
354 (ChangeObjectName (type
, ptr1
, ptr2
, ptr3
,
355 Entry
->Data
.ChangeName
.Name
));
361 /* ---------------------------------------------------------------------------
362 * recovers an object from a 2ndSize change operation
365 UndoChange2ndSize (UndoListTypePtr Entry
)
367 void *ptr1
, *ptr2
, *ptr3
;
371 /* lookup entry by ID */
373 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
376 if (TEST_FLAG (LOCKFLAG
, (PinTypePtr
) ptr2
))
378 swap
= ((PinTypePtr
) ptr2
)->DrillingHole
;
380 EraseObject (type
, ptr1
, ptr2
);
381 ((PinTypePtr
) ptr2
)->DrillingHole
= Entry
->Data
.Size
;
382 Entry
->Data
.Size
= swap
;
383 DrawObject (type
, ptr1
, ptr2
, 0);
389 /* ---------------------------------------------------------------------------
390 * recovers an object from a ChangeAngles change operation
393 UndoChangeAngles (UndoListTypePtr Entry
)
395 void *ptr1
, *ptr2
, *ptr3
;
397 long int old_sa
, old_da
;
399 /* lookup entry by ID */
401 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
402 if (type
== ARC_TYPE
)
404 LayerTypePtr Layer
= (LayerTypePtr
) ptr1
;
405 ArcTypePtr a
= (ArcTypePtr
) ptr2
;
406 if (TEST_FLAG (LOCKFLAG
, a
))
408 r_delete_entry (Layer
->arc_tree
, (BoxTypePtr
) a
);
409 old_sa
= a
->StartAngle
;
412 EraseObject (type
, Layer
, a
);
413 a
->StartAngle
= Entry
->Data
.Move
.DX
;
414 a
->Delta
= Entry
->Data
.Move
.DY
;
415 SetArcBoundingBox (a
);
416 r_insert_entry (Layer
->arc_tree
, (BoxTypePtr
) a
, 0);
417 Entry
->Data
.Move
.DX
= old_sa
;
418 Entry
->Data
.Move
.DY
= old_da
;;
419 DrawObject (type
, ptr1
, a
, 0);
425 /* ---------------------------------------------------------------------------
426 * recovers an object from a clearance size change operation
429 UndoChangeClearSize (UndoListTypePtr Entry
)
431 void *ptr1
, *ptr2
, *ptr3
;
435 /* lookup entry by ID */
437 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
440 if (TEST_FLAG (LOCKFLAG
, (LineTypePtr
) ptr2
))
442 swap
= ((PinTypePtr
) ptr2
)->Clearance
;
443 RestoreToPolygon (PCB
->Data
, type
, ptr1
, ptr2
);
445 EraseObject (type
, ptr1
, ptr2
);
446 ((PinTypePtr
) ptr2
)->Clearance
= Entry
->Data
.Size
;
447 ClearFromPolygon (PCB
->Data
, type
, ptr1
, ptr2
);
448 Entry
->Data
.Size
= swap
;
450 DrawObject (type
, ptr1
, ptr2
, 0);
456 /* ---------------------------------------------------------------------------
457 * recovers an object from a mask size change operation
460 UndoChangeMaskSize (UndoListTypePtr Entry
)
462 void *ptr1
, *ptr2
, *ptr3
;
466 /* lookup entry by ID */
468 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
469 if (type
& (VIA_TYPE
| PIN_TYPE
| PAD_TYPE
))
471 if (TEST_FLAG (LOCKFLAG
, (PinTypePtr
) ptr2
))
475 PAD_TYPE
? ((PadTypePtr
) ptr2
)->Mask
: ((PinTypePtr
) ptr2
)->Mask
);
477 EraseObject (type
, ptr1
, ptr2
);
478 if (type
== PAD_TYPE
)
479 ((PadTypePtr
) ptr2
)->Mask
= Entry
->Data
.Size
;
481 ((PinTypePtr
) ptr2
)->Mask
= Entry
->Data
.Size
;
482 Entry
->Data
.Size
= swap
;
484 DrawObject (type
, ptr1
, ptr2
, 0);
491 /* ---------------------------------------------------------------------------
492 * recovers an object from a Size change operation
495 UndoChangeSize (UndoListTypePtr Entry
)
497 void *ptr1
, *ptr2
, *ptr3
;
501 /* lookup entry by ID */
503 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
506 if (TEST_FLAG (LOCKFLAG
, (PinTypePtr
) ptr2
))
508 /* Wow! can any object be treated as a pin type for size change?? */
509 /* pins, vias, lines, and arcs can. Text can't but it has it's own mechanism */
510 swap
= ((PinTypePtr
) ptr2
)->Thickness
;
511 RestoreToPolygon (PCB
->Data
, type
, ptr1
, ptr2
);
513 EraseObject (type
, ptr1
, ptr2
);
514 ((PinTypePtr
) ptr2
)->Thickness
= Entry
->Data
.Size
;
515 Entry
->Data
.Size
= swap
;
516 ClearFromPolygon (PCB
->Data
, type
, ptr1
, ptr2
);
518 DrawObject (type
, ptr1
, ptr2
, 0);
524 /* ---------------------------------------------------------------------------
525 * recovers an object from a FLAG change operation
528 UndoFlag (UndoListTypePtr Entry
)
530 void *ptr1
, *ptr2
, *ptr3
;
535 /* lookup entry by ID */
537 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
541 PinTypePtr pin
= (PinTypePtr
) ptr2
;
543 if (TEST_FLAG (LOCKFLAG
, pin
))
549 f1
= MaskFlags (pin
->Flags
, ~DRAW_FLAGS
);
550 f2
= MaskFlags (Entry
->Data
.Flags
, ~DRAW_FLAGS
);
552 if (!FLAGS_EQUAL (f1
, f2
))
555 if (andDraw
&& must_redraw
)
556 EraseObject (type
, ptr1
, ptr2
);
558 pin
->Flags
= Entry
->Data
.Flags
;
560 Entry
->Data
.Flags
= swap
;
562 if (andDraw
&& must_redraw
)
563 DrawObject (type
, ptr1
, ptr2
, 0);
566 Message ("hace Internal error: Can't find ID %d type %08x\n", Entry
->ID
,
568 Message ("for UndoFlag Operation. Previous flags: %s\n",
569 flags_to_string (Entry
->Data
.Flags
, 0));
573 /* ---------------------------------------------------------------------------
574 * recovers an object from a mirror operation
575 * returns true if anything has been recovered
578 UndoMirror (UndoListTypePtr Entry
)
580 void *ptr1
, *ptr2
, *ptr3
;
583 /* lookup entry by ID */
585 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
586 if (type
== ELEMENT_TYPE
)
588 ElementTypePtr element
= (ElementTypePtr
) ptr3
;
589 if (TEST_FLAG (LOCKFLAG
, element
))
592 EraseElement (element
);
593 MirrorElementCoordinates (PCB
->Data
, element
, Entry
->Data
.Move
.DY
);
595 DrawElement (element
, 0);
598 Message ("hace Internal error: UndoMirror on object type %d\n", type
);
602 /* ---------------------------------------------------------------------------
603 * recovers an object from a 'copy' or 'create' operation
604 * returns true if anything has been recovered
607 UndoCopyOrCreate (UndoListTypePtr Entry
)
609 void *ptr1
, *ptr2
, *ptr3
;
612 /* lookup entry by it's ID */
614 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
617 if (TEST_FLAG (LOCKFLAG
, (PinTypePtr
) ptr2
))
620 RemoveList
= CreateNewBuffer ();
622 EraseObject (type
, ptr1
, ptr2
);
623 /* in order to make this re-doable we move it to the RemoveList */
624 MoveObjectToBuffer (RemoveList
, PCB
->Data
, type
, ptr1
, ptr2
, ptr3
);
625 Entry
->Type
= UNDO_REMOVE
;
631 /* ---------------------------------------------------------------------------
632 * recovers an object from a 'move' operation
633 * returns true if anything has been recovered
636 UndoMove (UndoListTypePtr Entry
)
638 void *ptr1
, *ptr2
, *ptr3
;
641 /* lookup entry by it's ID */
643 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
646 if (TEST_FLAG (LOCKFLAG
, (LineTypePtr
) ptr2
))
648 MoveObject (type
, ptr1
, ptr2
, ptr3
,
649 -Entry
->Data
.Move
.DX
, -Entry
->Data
.Move
.DY
);
650 Entry
->Data
.Move
.DX
*= -1;
651 Entry
->Data
.Move
.DY
*= -1;
657 /* ----------------------------------------------------------------------
658 * recovers an object from a 'remove' operation
659 * returns true if anything has been recovered
662 UndoRemove (UndoListTypePtr Entry
)
664 void *ptr1
, *ptr2
, *ptr3
;
667 /* lookup entry by it's ID */
669 SearchObjectByID (RemoveList
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
,
674 DrawRecoveredObject (type
, ptr1
, ptr2
, ptr3
);
675 MoveObjectToBuffer (PCB
->Data
, RemoveList
, type
, ptr1
, ptr2
, ptr3
);
676 Entry
->Type
= UNDO_CREATE
;
682 /* ----------------------------------------------------------------------
683 * recovers an object from a 'move to another layer' operation
684 * returns true if anything has been recovered
687 UndoMoveToLayer (UndoListTypePtr Entry
)
689 void *ptr1
, *ptr2
, *ptr3
;
692 /* lookup entry by it's ID */
694 SearchObjectByID (PCB
->Data
, &ptr1
, &ptr2
, &ptr3
, Entry
->ID
, Entry
->Kind
);
697 if (TEST_FLAG (LOCKFLAG
, (LineTypePtr
) ptr2
))
699 swap
= GetLayerNumber (PCB
->Data
, (LayerTypePtr
) ptr1
);
700 MoveObjectToLayer (type
, ptr1
, ptr2
, ptr3
,
701 LAYER_PTR (Entry
->Data
.
702 MoveToLayer
.OriginalLayer
), true);
703 Entry
->Data
.MoveToLayer
.OriginalLayer
= swap
;
709 /* ---------------------------------------------------------------------------
710 * recovers a removed polygon point
711 * returns true on success
714 UndoRemovePoint (UndoListTypePtr Entry
)
717 PolygonTypePtr polygon
;
721 /* lookup entry (polygon not point was saved) by it's ID */
722 assert (Entry
->Kind
== POLYGON_TYPE
);
724 SearchObjectByID (PCB
->Data
, (void *) &layer
, (void *) &polygon
, &ptr3
,
725 Entry
->ID
, Entry
->Kind
);
728 case POLYGON_TYPE
: /* restore the removed point */
730 if (TEST_FLAG (LOCKFLAG
, polygon
))
732 /* recover the point */
733 if (andDraw
&& layer
->On
)
734 ErasePolygon (polygon
);
735 InsertPointIntoObject (POLYGON_TYPE
, layer
, polygon
,
736 &Entry
->Data
.RemovedPoint
.Index
,
737 Entry
->Data
.RemovedPoint
.X
,
738 Entry
->Data
.RemovedPoint
.Y
, true,
739 Entry
->Data
.RemovedPoint
.last_in_contour
);
741 polygon
->Points
[Entry
->Data
.RemovedPoint
.Index
].ID
=
742 Entry
->Data
.RemovedPoint
.ID
;
743 if (andDraw
&& layer
->On
)
744 DrawPolygon (layer
, polygon
, 0);
745 Entry
->Type
= UNDO_INSERT_POINT
;
746 Entry
->ID
= Entry
->Data
.RemovedPoint
.ID
;
747 Entry
->Kind
= POLYGONPOINT_TYPE
;
756 /* ---------------------------------------------------------------------------
757 * recovers an inserted polygon point
758 * returns true on success
761 UndoInsertPoint (UndoListTypePtr Entry
)
764 PolygonTypePtr polygon
;
769 bool last_in_contour
= false;
771 assert (Entry
->Kind
== POLYGONPOINT_TYPE
);
772 /* lookup entry by it's ID */
774 SearchObjectByID (PCB
->Data
, (void *) &layer
, (void *) &polygon
,
775 (void *) &pnt
, Entry
->ID
, Entry
->Kind
);
778 case POLYGONPOINT_TYPE
: /* removes an inserted polygon point */
780 if (TEST_FLAG (LOCKFLAG
, polygon
))
782 if (andDraw
&& layer
->On
)
783 ErasePolygon (polygon
);
785 /* Check whether this point was at the end of its contour.
786 * If so, we need to flag as such when re-adding the point
787 * so it goes back in the correct place
789 point_idx
= polygon_point_idx (polygon
, pnt
);
790 for (hole
= 0; hole
< polygon
->HoleIndexN
; hole
++)
791 if (point_idx
== polygon
->HoleIndex
[hole
] - 1)
792 last_in_contour
= true;
793 if (point_idx
== polygon
->PointN
- 1)
794 last_in_contour
= true;
795 Entry
->Data
.RemovedPoint
.last_in_contour
= last_in_contour
;
797 Entry
->Data
.RemovedPoint
.X
= pnt
->X
;
798 Entry
->Data
.RemovedPoint
.Y
= pnt
->Y
;
799 Entry
->Data
.RemovedPoint
.ID
= pnt
->ID
;
800 Entry
->ID
= polygon
->ID
;
801 Entry
->Kind
= POLYGON_TYPE
;
802 Entry
->Type
= UNDO_REMOVE_POINT
;
803 Entry
->Data
.RemovedPoint
.Index
= point_idx
;
804 DestroyObject (PCB
->Data
, POLYGONPOINT_TYPE
, layer
, polygon
, pnt
);
805 if (andDraw
&& layer
->On
)
806 DrawPolygon (layer
, polygon
, 0);
816 UndoSwapCopiedObject (UndoListTypePtr Entry
)
818 void *ptr1
, *ptr2
, *ptr3
;
819 void *ptr1b
, *ptr2b
, *ptr3b
;
820 AnyObjectType
*obj
, *obj2
;
824 /* lookup entry by it's ID */
826 SearchObjectByID (RemoveList
, &ptr1
, &ptr2
, &ptr3
, Entry
->Data
.CopyID
,
832 SearchObjectByID (PCB
->Data
, &ptr1b
, &ptr2b
, &ptr3b
, Entry
->ID
,
844 MoveObjectToBuffer (RemoveList
, PCB
->Data
, type
, ptr1b
, ptr2b
, ptr3b
);
847 DrawRecoveredObject (Entry
->Kind
, ptr1
, ptr2
, ptr3
);
849 obj
= MoveObjectToBuffer (PCB
->Data
, RemoveList
, type
, ptr1
, ptr2
, ptr3
);
850 if (Entry
->Kind
== POLYGON_TYPE
)
851 InitClip (PCB
->Data
, ptr1b
, (PolygonType
*)obj
);
855 /* ---------------------------------------------------------------------------
856 * recovers an removed polygon point
857 * returns true on success
860 UndoRemoveContour (UndoListTypePtr Entry
)
862 assert (Entry
->Kind
== POLYGON_TYPE
);
863 return UndoSwapCopiedObject (Entry
);
866 /* ---------------------------------------------------------------------------
867 * recovers an inserted polygon point
868 * returns true on success
871 UndoInsertContour (UndoListTypePtr Entry
)
873 assert (Entry
->Kind
== POLYGON_TYPE
);
874 return UndoSwapCopiedObject (Entry
);
877 /* ---------------------------------------------------------------------------
878 * undo a layer change
879 * returns true on success
882 UndoLayerChange (UndoListTypePtr Entry
)
884 LayerChangeTypePtr l
= &Entry
->Data
.LayerChange
;
888 l
->new_index
= l
->old_index
;
891 if (MoveLayer (l
->old_index
, l
->new_index
))
897 /* ---------------------------------------------------------------------------
898 * undo a netlist change
899 * returns true on success
902 UndoNetlistChange (UndoListTypePtr Entry
)
904 NetlistChangeTypePtr l
= & Entry
->Data
.NetlistChange
;
906 LibraryTypePtr lib
, saved
;
911 /* iterate over each net */
912 for (i
= 0 ; i
< lib
->MenuN
; i
++)
914 if (lib
->Menu
[i
].Name
)
915 free (lib
->Menu
[i
].Name
);
917 if (lib
->Menu
[i
].directory
)
918 free (lib
->Menu
[i
].directory
);
920 if (lib
->Menu
[i
].Style
)
921 free (lib
->Menu
[i
].Style
);
923 /* iterate over each pin on the net */
924 for (j
= 0; j
< lib
->Menu
[i
].EntryN
; j
++) {
926 if (lib
->Menu
[i
].Entry
[j
].ListEntry
)
927 free (lib
->Menu
[i
].Entry
[j
].ListEntry
);
929 if (lib
->Menu
[i
].Entry
[j
].AllocatedMemory
)
930 free (lib
->Menu
[i
].Entry
[j
].AllocatedMemory
);
932 if (lib
->Menu
[i
].Entry
[j
].Template
)
933 free (lib
->Menu
[i
].Entry
[j
].Template
);
935 if (lib
->Menu
[i
].Entry
[j
].Package
)
936 free (lib
->Menu
[i
].Entry
[j
].Package
);
938 if (lib
->Menu
[i
].Entry
[j
].Value
)
939 free (lib
->Menu
[i
].Entry
[j
].Value
);
941 if (lib
->Menu
[i
].Entry
[j
].Description
)
942 free (lib
->Menu
[i
].Entry
[j
].Description
);
956 /* ---------------------------------------------------------------------------
957 * undo of any 'hard to recover' operation
959 * returns the bitfield for the types of operations that were undone
968 unique
= TEST_FLAG (UNIQUENAMEFLAG
, PCB
);
969 CLEAR_FLAG (UNIQUENAMEFLAG
, PCB
);
978 Message (_("Nothing to undo - buffer is empty\n"));
984 /* lock undo module to prevent from loops
985 * and loop over all entries with the same serial number
987 ptr
= &UndoList
[UndoN
- 1];
988 if (ptr
->Serial
!= Serial
- 1)
990 Message (_("Undo bad serial number %d expecting %d\n"),
991 ptr
->Serial
, Serial
- 1);
992 Serial
= ptr
->Serial
+ 1;
996 Serial
= ptr
->Serial
;
997 for (; UndoN
&& ptr
->Serial
== Serial
; ptr
--, UndoN
--, RedoN
++)
998 Types
|= PerformUndo (ptr
);
1003 if (Types
&& andDraw
)
1006 /* restore the unique flag setting */
1008 SET_FLAG (UNIQUENAMEFLAG
, PCB
);
1014 PerformUndo (UndoListTypePtr ptr
)
1018 case UNDO_CHANGENAME
:
1019 if (UndoChangeName (ptr
))
1020 return (UNDO_CHANGENAME
);
1024 if (UndoCopyOrCreate (ptr
))
1025 return (UNDO_CREATE
);
1034 if (UndoRemove (ptr
))
1035 return (UNDO_REMOVE
);
1038 case UNDO_REMOVE_POINT
:
1039 if (UndoRemovePoint (ptr
))
1040 return (UNDO_REMOVE_POINT
);
1043 case UNDO_INSERT_POINT
:
1044 if (UndoInsertPoint (ptr
))
1045 return (UNDO_INSERT_POINT
);
1048 case UNDO_REMOVE_CONTOUR
:
1049 if (UndoRemoveContour (ptr
))
1050 return (UNDO_REMOVE_CONTOUR
);
1053 case UNDO_INSERT_CONTOUR
:
1054 if (UndoInsertContour (ptr
))
1055 return (UNDO_INSERT_CONTOUR
);
1059 if (UndoRotate (ptr
))
1060 return (UNDO_ROTATE
);
1064 if (UndoClearPoly (ptr
))
1065 return (UNDO_CLEAR
);
1068 case UNDO_MOVETOLAYER
:
1069 if (UndoMoveToLayer (ptr
))
1070 return (UNDO_MOVETOLAYER
);
1078 case UNDO_CHANGESIZE
:
1079 if (UndoChangeSize (ptr
))
1080 return (UNDO_CHANGESIZE
);
1083 case UNDO_CHANGECLEARSIZE
:
1084 if (UndoChangeClearSize (ptr
))
1085 return (UNDO_CHANGECLEARSIZE
);
1088 case UNDO_CHANGEMASKSIZE
:
1089 if (UndoChangeMaskSize (ptr
))
1090 return (UNDO_CHANGEMASKSIZE
);
1093 case UNDO_CHANGE2NDSIZE
:
1094 if (UndoChange2ndSize (ptr
))
1095 return (UNDO_CHANGE2NDSIZE
);
1098 case UNDO_CHANGEANGLES
:
1099 if (UndoChangeAngles (ptr
))
1100 return (UNDO_CHANGEANGLES
);
1103 case UNDO_LAYERCHANGE
:
1104 if (UndoLayerChange (ptr
))
1105 return (UNDO_LAYERCHANGE
);
1108 case UNDO_NETLISTCHANGE
:
1109 if (UndoNetlistChange (ptr
))
1110 return (UNDO_NETLISTCHANGE
);
1114 if (UndoMirror (ptr
))
1115 return (UNDO_MIRROR
);
1121 /* ---------------------------------------------------------------------------
1122 * redo of any 'hard to recover' operation
1124 * returns the number of operations redone
1129 UndoListTypePtr ptr
;
1139 ("Nothing to redo. Perhaps changes have been made since last undo\n"));
1143 /* lock undo module to prevent from loops
1144 * and loop over all entries with the same serial number
1147 ptr
= &UndoList
[UndoN
];
1148 Serial
= ptr
->Serial
;
1149 for (; RedoN
&& ptr
->Serial
== Serial
; ptr
++, UndoN
++, RedoN
--)
1150 Types
|= PerformUndo (ptr
);
1151 /* Make next serial number current in case we take a new branch */
1156 if (Types
&& andDraw
)
1161 /* ---------------------------------------------------------------------------
1162 * restores the serial number of the undo list
1165 RestoreUndoSerialNumber (void)
1167 Serial
= SavedSerial
;
1170 /* ---------------------------------------------------------------------------
1171 * saves the serial number of the undo list
1174 SaveUndoSerialNumber (void)
1177 SavedSerial
= Serial
;
1180 /* ---------------------------------------------------------------------------
1181 * increments the serial number of the undo list
1182 * it's not done automatically because some operations perform more
1183 * than one request with the same serial #
1186 IncrementUndoSerialNumber (void)
1190 /* don't increment if nothing was added */
1191 if (UndoN
== 0 || UndoList
[UndoN
- 1].Serial
!= Serial
)
1195 SetChangedFlag (true);
1199 /* ---------------------------------------------------------------------------
1200 * releases memory of the undo- and remove list
1203 ClearUndoList (bool Force
)
1205 UndoListTypePtr undo
;
1208 && (Force
|| gui
->confirm_dialog ("OK to clear 'undo' buffer?", 0)))
1210 /* release memory allocated by objects in undo list */
1211 for (undo
= UndoList
; UndoN
; undo
++, UndoN
--)
1213 if (undo
->Type
== UNDO_CHANGENAME
)
1214 SaveFree (undo
->Data
.ChangeName
.Name
);
1219 FreeDataMemory (RemoveList
);
1224 /* reset some counters */
1225 UndoN
= UndoMax
= RedoN
= 0;
1228 /* reset counter in any case */
1232 /* ---------------------------------------------------------------------------
1233 * adds an object to the list of clearpoly objects
1236 AddObjectToClearPolyUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
,
1239 UndoListTypePtr undo
;
1243 undo
= GetUndoSlot (UNDO_CLEAR
, OBJECT_ID (Ptr3
), Type
);
1244 undo
->Data
.ClearPoly
.Clear
= clear
;
1245 undo
->Data
.ClearPoly
.Layer
= (LayerTypePtr
) Ptr1
;
1249 /* ---------------------------------------------------------------------------
1250 * adds an object to the list of mirrored objects
1253 AddObjectToMirrorUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
,
1256 UndoListTypePtr undo
;
1260 undo
= GetUndoSlot (UNDO_MIRROR
, OBJECT_ID (Ptr3
), Type
);
1261 undo
->Data
.Move
.DY
= yoff
;
1265 /* ---------------------------------------------------------------------------
1266 * adds an object to the list of rotated objects
1269 AddObjectToRotateUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
,
1270 LocationType CenterX
, LocationType CenterY
,
1273 UndoListTypePtr undo
;
1277 undo
= GetUndoSlot (UNDO_ROTATE
, OBJECT_ID (Ptr3
), Type
);
1278 undo
->Data
.Rotate
.CenterX
= CenterX
;
1279 undo
->Data
.Rotate
.CenterY
= CenterY
;
1280 undo
->Data
.Rotate
.Steps
= Steps
;
1284 /* ---------------------------------------------------------------------------
1285 * adds an object to the list of removed objects and removes it from
1289 MoveObjectToRemoveUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
1291 UndoListTypePtr undo
;
1296 RemoveList
= CreateNewBuffer ();
1298 undo
= GetUndoSlot (UNDO_REMOVE
, OBJECT_ID (Ptr3
), Type
);
1299 MoveObjectToBuffer (RemoveList
, PCB
->Data
, Type
, Ptr1
, Ptr2
, Ptr3
);
1303 /* ---------------------------------------------------------------------------
1304 * adds an object to the list of removed polygon/... points
1307 AddObjectToRemovePointUndoList (int Type
,
1308 void *Ptr1
, void *Ptr2
, Cardinal index
)
1310 UndoListTypePtr undo
;
1311 PolygonTypePtr polygon
= (PolygonTypePtr
) Ptr2
;
1313 bool last_in_contour
= false;
1319 case POLYGONPOINT_TYPE
:
1321 /* save the ID of the parent object; else it will be
1322 * impossible to recover the point
1325 GetUndoSlot (UNDO_REMOVE_POINT
, OBJECT_ID (polygon
),
1327 undo
->Data
.RemovedPoint
.X
= polygon
->Points
[index
].X
;
1328 undo
->Data
.RemovedPoint
.Y
= polygon
->Points
[index
].Y
;
1329 undo
->Data
.RemovedPoint
.ID
= polygon
->Points
[index
].ID
;
1330 undo
->Data
.RemovedPoint
.Index
= index
;
1332 /* Check whether this point was at the end of its contour.
1333 * If so, we need to flag as such when re-adding the point
1334 * so it goes back in the correct place
1336 for (hole
= 0; hole
< polygon
->HoleIndexN
; hole
++)
1337 if (index
== polygon
->HoleIndex
[hole
] - 1)
1338 last_in_contour
= true;
1339 if (index
== polygon
->PointN
- 1)
1340 last_in_contour
= true;
1341 undo
->Data
.RemovedPoint
.last_in_contour
= last_in_contour
;
1348 /* ---------------------------------------------------------------------------
1349 * adds an object to the list of inserted polygon/... points
1352 AddObjectToInsertPointUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
1354 UndoListTypePtr undo
;
1357 undo
= GetUndoSlot (UNDO_INSERT_POINT
, OBJECT_ID (Ptr3
), Type
);
1361 CopyObjectToUndoList (int undo_type
, int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
1363 UndoListTypePtr undo
;
1364 AnyObjectType
*copy
;
1370 RemoveList
= CreateNewBuffer ();
1372 undo
= GetUndoSlot (undo_type
, OBJECT_ID (Ptr2
), Type
);
1373 copy
= CopyObjectToBuffer (RemoveList
, PCB
->Data
, Type
, Ptr1
, Ptr2
, Ptr3
);
1374 undo
->Data
.CopyID
= copy
->ID
;
1377 /* ---------------------------------------------------------------------------
1378 * adds an object to the list of removed contours
1379 * (Actually just takes a copy of the whole polygon to restore)
1382 AddObjectToRemoveContourUndoList (int Type
,
1383 LayerType
*Layer
, PolygonType
*Polygon
)
1385 CopyObjectToUndoList (UNDO_REMOVE_CONTOUR
, Type
, Layer
, Polygon
, NULL
);
1388 /* ---------------------------------------------------------------------------
1389 * adds an object to the list of insert contours
1390 * (Actually just takes a copy of the whole polygon to restore)
1393 AddObjectToInsertContourUndoList (int Type
,
1394 LayerType
*Layer
, PolygonType
*Polygon
)
1396 CopyObjectToUndoList (UNDO_INSERT_CONTOUR
, Type
, Layer
, Polygon
, NULL
);
1399 /* ---------------------------------------------------------------------------
1400 * adds an object to the list of moved objects
1403 AddObjectToMoveUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
,
1404 LocationType DX
, LocationType DY
)
1406 UndoListTypePtr undo
;
1410 undo
= GetUndoSlot (UNDO_MOVE
, OBJECT_ID (Ptr3
), Type
);
1411 undo
->Data
.Move
.DX
= DX
;
1412 undo
->Data
.Move
.DY
= DY
;
1416 /* ---------------------------------------------------------------------------
1417 * adds an object to the list of objects with changed names
1420 AddObjectToChangeNameUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
,
1423 UndoListTypePtr undo
;
1427 undo
= GetUndoSlot (UNDO_CHANGENAME
, OBJECT_ID (Ptr3
), Type
);
1428 undo
->Data
.ChangeName
.Name
= OldName
;
1432 /* ---------------------------------------------------------------------------
1433 * adds an object to the list of objects moved to another layer
1436 AddObjectToMoveToLayerUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
1438 UndoListTypePtr undo
;
1442 undo
= GetUndoSlot (UNDO_MOVETOLAYER
, OBJECT_ID (Ptr3
), Type
);
1443 undo
->Data
.MoveToLayer
.OriginalLayer
=
1444 GetLayerNumber (PCB
->Data
, (LayerTypePtr
) Ptr1
);
1448 /* ---------------------------------------------------------------------------
1449 * adds an object to the list of created objects
1452 AddObjectToCreateUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
1454 UndoListTypePtr undo
;
1457 undo
= GetUndoSlot (UNDO_CREATE
, OBJECT_ID (Ptr3
), Type
);
1458 ClearFromPolygon (PCB
->Data
, Type
, Ptr1
, Ptr2
);
1461 /* ---------------------------------------------------------------------------
1462 * adds an object to the list of objects with flags changed
1465 AddObjectToFlagUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
1467 UndoListTypePtr undo
;
1471 undo
= GetUndoSlot (UNDO_FLAG
, OBJECT_ID (Ptr2
), Type
);
1472 undo
->Data
.Flags
= ((PinTypePtr
) Ptr2
)->Flags
;
1476 /* ---------------------------------------------------------------------------
1477 * adds an object to the list of objects with Size changes
1480 AddObjectToSizeUndoList (int Type
, void *ptr1
, void *ptr2
, void *ptr3
)
1482 UndoListTypePtr undo
;
1486 undo
= GetUndoSlot (UNDO_CHANGESIZE
, OBJECT_ID (ptr2
), Type
);
1491 undo
->Data
.Size
= ((PinTypePtr
) ptr2
)->Thickness
;
1494 case ELEMENTLINE_TYPE
:
1495 undo
->Data
.Size
= ((LineTypePtr
) ptr2
)->Thickness
;
1498 case ELEMENTNAME_TYPE
:
1499 undo
->Data
.Size
= ((TextTypePtr
) ptr2
)->Scale
;
1502 undo
->Data
.Size
= ((PadTypePtr
) ptr2
)->Thickness
;
1505 case ELEMENTARC_TYPE
:
1506 undo
->Data
.Size
= ((ArcTypePtr
) ptr2
)->Thickness
;
1512 /* ---------------------------------------------------------------------------
1513 * adds an object to the list of objects with Size changes
1516 AddObjectToClearSizeUndoList (int Type
, void *ptr1
, void *ptr2
, void *ptr3
)
1518 UndoListTypePtr undo
;
1522 undo
= GetUndoSlot (UNDO_CHANGECLEARSIZE
, OBJECT_ID (ptr2
), Type
);
1527 undo
->Data
.Size
= ((PinTypePtr
) ptr2
)->Clearance
;
1530 undo
->Data
.Size
= ((LineTypePtr
) ptr2
)->Clearance
;
1533 undo
->Data
.Size
= ((PadTypePtr
) ptr2
)->Clearance
;
1536 undo
->Data
.Size
= ((ArcTypePtr
) ptr2
)->Clearance
;
1542 /* ---------------------------------------------------------------------------
1543 * adds an object to the list of objects with Size changes
1546 AddObjectToMaskSizeUndoList (int Type
, void *ptr1
, void *ptr2
, void *ptr3
)
1548 UndoListTypePtr undo
;
1552 undo
= GetUndoSlot (UNDO_CHANGEMASKSIZE
, OBJECT_ID (ptr2
), Type
);
1557 undo
->Data
.Size
= ((PinTypePtr
) ptr2
)->Mask
;
1560 undo
->Data
.Size
= ((PadTypePtr
) ptr2
)->Mask
;
1566 /* ---------------------------------------------------------------------------
1567 * adds an object to the list of objects with 2ndSize changes
1570 AddObjectTo2ndSizeUndoList (int Type
, void *ptr1
, void *ptr2
, void *ptr3
)
1572 UndoListTypePtr undo
;
1576 undo
= GetUndoSlot (UNDO_CHANGE2NDSIZE
, OBJECT_ID (ptr2
), Type
);
1577 if (Type
== PIN_TYPE
|| Type
== VIA_TYPE
)
1578 undo
->Data
.Size
= ((PinTypePtr
) ptr2
)->DrillingHole
;
1582 /* ---------------------------------------------------------------------------
1583 * adds an object to the list of changed angles. Note that you must
1584 * call this before changing the angles, passing the new start/delta.
1587 AddObjectToChangeAnglesUndoList (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
1589 UndoListTypePtr undo
;
1590 ArcTypePtr a
= (ArcTypePtr
) Ptr3
;
1594 undo
= GetUndoSlot (UNDO_CHANGEANGLES
, OBJECT_ID (Ptr3
), Type
);
1595 undo
->Data
.Move
.DX
= a
->StartAngle
;
1596 undo
->Data
.Move
.DY
= a
->Delta
;
1600 /* ---------------------------------------------------------------------------
1601 * adds a layer change (new, delete, move) to the undo list.
1604 AddLayerChangeToUndoList (int old_index
, int new_index
)
1606 UndoListTypePtr undo
;
1610 undo
= GetUndoSlot (UNDO_LAYERCHANGE
, 0, 0);
1611 undo
->Data
.LayerChange
.old_index
= old_index
;
1612 undo
->Data
.LayerChange
.new_index
= new_index
;
1616 /* ---------------------------------------------------------------------------
1617 * adds a netlist change to the undo list
1620 AddNetlistLibToUndoList (LibraryTypePtr lib
)
1622 UndoListTypePtr undo
;
1628 undo
= GetUndoSlot (UNDO_NETLISTCHANGE
, 0, 0);
1629 /* keep track of where the data needs to go */
1630 undo
->Data
.NetlistChange
.lib
= lib
;
1632 /* and what the old data is that we'll need to restore */
1633 undo
->Data
.NetlistChange
.old
= malloc (sizeof (LibraryTypePtr
));
1634 old
= undo
->Data
.NetlistChange
.old
;
1635 old
->MenuN
= lib
->MenuN
;
1636 old
->MenuMax
= lib
->MenuMax
;
1637 old
->Menu
= malloc (old
->MenuMax
* sizeof (LibraryMenuType
));
1638 if (old
->Menu
== NULL
)
1640 fprintf (stderr
, "malloc() failed in %s\n", __FUNCTION__
);
1644 /* iterate over each net */
1645 for (i
= 0 ; i
< lib
->MenuN
; i
++)
1647 old
->Menu
[i
].EntryN
= lib
->Menu
[i
].EntryN
;
1648 old
->Menu
[i
].EntryMax
= lib
->Menu
[i
].EntryMax
;
1651 lib
->Menu
[i
].Name
? strdup (lib
->Menu
[i
].Name
) : NULL
;
1653 old
->Menu
[i
].directory
=
1654 lib
->Menu
[i
].directory
? strdup (lib
->Menu
[i
].directory
) : NULL
;
1656 old
->Menu
[i
].Style
=
1657 lib
->Menu
[i
].Style
? strdup (lib
->Menu
[i
].Style
) : NULL
;
1660 old
->Menu
[i
].Entry
=
1661 malloc (old
->Menu
[i
].EntryMax
* sizeof (LibraryEntryType
));
1662 if (old
->Menu
[i
].Entry
== NULL
)
1664 fprintf (stderr
, "malloc() failed in %s\n", __FUNCTION__
);
1668 /* iterate over each pin on the net */
1669 for (j
= 0; j
< lib
->Menu
[i
].EntryN
; j
++) {
1671 old
->Menu
[i
].Entry
[j
].ListEntry
=
1672 lib
->Menu
[i
].Entry
[j
].ListEntry
?
1673 strdup (lib
->Menu
[i
].Entry
[j
].ListEntry
) :
1676 old
->Menu
[i
].Entry
[j
].AllocatedMemory
=
1677 lib
->Menu
[i
].Entry
[j
].AllocatedMemory
?
1678 strdup (lib
->Menu
[i
].Entry
[j
].AllocatedMemory
) :
1681 old
->Menu
[i
].Entry
[j
].Template
=
1682 lib
->Menu
[i
].Entry
[j
].Template
?
1683 strdup (lib
->Menu
[i
].Entry
[j
].Template
) :
1686 old
->Menu
[i
].Entry
[j
].Package
=
1687 lib
->Menu
[i
].Entry
[j
].Package
?
1688 strdup (lib
->Menu
[i
].Entry
[j
].Package
) :
1691 old
->Menu
[i
].Entry
[j
].Value
=
1692 lib
->Menu
[i
].Entry
[j
].Value
?
1693 strdup (lib
->Menu
[i
].Entry
[j
].Value
) :
1696 old
->Menu
[i
].Entry
[j
].Description
=
1697 lib
->Menu
[i
].Entry
[j
].Description
?
1698 strdup (lib
->Menu
[i
].Entry
[j
].Description
) :
1708 /* ---------------------------------------------------------------------------
1717 /* ---------------------------------------------------------------------------
1726 /* ---------------------------------------------------------------------------
1727 * return undo lock state