Fix node_label() function to work with self-intersection
[geda-pcb/gde.git] / src / undo.c
blobcb8d180de8d310f7852fb70ff9183b615eab2b90
1 /* $Id$ */
3 /*
4 * COPYRIGHT
6 * PCB, interactive printed circuit board design
7 * Copyright (C) 1994,1995,1996 Thomas Nau
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 * Contact addresses for paper mail and Email:
24 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
25 * Thomas.Nau@rz.uni-ulm.de
29 /* functions used to undo operations
31 * Description:
32 * There are two lists which hold
33 * - information about a command
34 * - data of removed objects
35 * Both lists are organized as first-in-last-out which means that the undo
36 * list can always use the last entry of the remove list.
37 * A serial number is incremented whenever an operation is completed.
38 * An operation itself may consist of several basic instructions.
39 * E.g.: removing all selected objects is one operation with exactly one
40 * serial number even if the remove function is called several times.
42 * a lock flag ensures that no infinite loops occur
45 #ifdef HAVE_CONFIG_H
46 #include "config.h"
47 #endif
49 #include <assert.h>
50 #include <memory.h>
51 #include "global.h"
53 #include "buffer.h"
54 #include "change.h"
55 #include "create.h"
56 #include "data.h"
57 #include "draw.h"
58 #include "error.h"
59 #include "insert.h"
60 #include "misc.h"
61 #include "mirror.h"
62 #include "move.h"
63 #include "mymem.h"
64 #include "polygon.h"
65 #include "remove.h"
66 #include "rotate.h"
67 #include "rtree.h"
68 #include "search.h"
69 #include "set.h"
70 #include "undo.h"
71 #include "strflags.h"
73 #ifdef HAVE_LIBDMALLOC
74 #include <dmalloc.h>
75 #endif
77 RCSID ("$Id$");
79 /* ---------------------------------------------------------------------------
80 * some local data types
82 typedef struct /* information about a change command */
84 char *Name;
86 ChangeNameType, *ChangeNameTypePtr;
88 typedef struct /* information about a move command */
90 LocationType DX, /* movement vector */
91 DY;
93 MoveType, *MoveTypePtr;
95 typedef struct /* information about removed polygon points */
97 LocationType X, Y; /* data */
98 int ID;
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 */
106 CenterY;
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 */
119 int old_index;
120 int new_index;
122 LayerChangeType, *LayerChangeTypePtr;
124 typedef struct /* information about poly clear/restore */
126 Boolean Clear; /* true was clear, false was restore */
127 LayerTypePtr Layer;
129 ClearPolyType, *ClearPolyTypePtr;
131 typedef struct /* information about netlist lib changes */
133 LibraryTypePtr old;
134 LibraryTypePtr lib;
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 */
143 ID; /* object ID */
144 union /* some additional information */
146 ChangeNameType ChangeName;
147 MoveType Move;
148 RemovedPointType RemovedPoint;
149 RotateType Rotate;
150 MoveToLayerType MoveToLayer;
151 FlagType Flags;
152 BDimension Size;
153 LayerChangeType LayerChange;
154 ClearPolyType ClearPoly;
155 NetlistChangeType NetlistChange;
157 Data;
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 */
167 SavedSerial;
168 static size_t UndoN, RedoN, /* number of entries */
169 UndoMax;
170 static Boolean Locked = False; /* do not add entries if */
171 static Boolean andDraw = True;
172 /* flag is set; prevents from */
173 /* infinite loops */
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)
204 UndoListTypePtr ptr;
205 void *ptr1, *ptr2, *ptr3;
206 int type;
207 static size_t limit = UNDO_WARNING_SIZE;
209 #ifdef DEBUG_ID
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,
212 Kind);
213 #endif
215 /* allocate memory */
216 if (UndoN >= UndoMax)
218 size_t size;
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 */
227 if (size > limit)
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--)
238 switch (ptr->Type)
240 case UNDO_CHANGENAME:
241 SaveFree (ptr->Data.ChangeName.Name);
242 break;
243 case UNDO_REMOVE:
244 type =
245 SearchObjectByID (RemoveList, &ptr1, &ptr2, &ptr3, ptr->ID,
246 ptr->Kind);
247 if (type != NO_TYPE)
249 DestroyObject (RemoveList, type, ptr1, ptr2, ptr3);
251 break;
252 default:
253 break;
256 /* copy typefield and serial number to the list */
257 ptr = &UndoList[UndoN++];
258 ptr->Type = CommandType;
259 ptr->Kind = Kind;
260 ptr->ID = ID;
261 ptr->Serial = Serial;
262 return (ptr);
265 /* ---------------------------------------------------------------------------
266 * redraws the recovered object
268 static void
269 DrawRecoveredObject (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
271 if (Type & (LINE_TYPE | TEXT_TYPE | POLYGON_TYPE | ARC_TYPE))
273 LayerTypePtr layer;
275 layer = LAYER_PTR (GetLayerNumber (RemoveList, (LayerTypePtr) Ptr1));
276 DrawObject (Type, (void *) layer, Ptr2, 0);
278 else
279 DrawObject (Type, Ptr1, Ptr2, 0);
282 /* ---------------------------------------------------------------------------
283 * recovers an object from a 'rotate' operation
284 * returns True if anything has been recovered
286 static Boolean
287 UndoRotate (UndoListTypePtr Entry)
289 void *ptr1, *ptr2, *ptr3;
290 int type;
292 /* lookup entry by it's ID */
293 type =
294 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
295 if (type != NO_TYPE)
297 if (TEST_FLAG (LOCKFLAG, (ArcTypePtr) ptr2))
298 return (False);
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;
303 return (True);
305 return (False);
308 /* ---------------------------------------------------------------------------
309 * recovers an object from a clear/restore poly operation
310 * returns True if anything has been recovered
312 static Boolean
313 UndoClearPoly (UndoListTypePtr Entry)
315 void *ptr1, *ptr2, *ptr3;
316 int type;
318 type =
319 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
320 if (type != NO_TYPE)
322 if (Entry->Data.ClearPoly.Clear)
323 RestoreToPolygon (PCB->Data, type, Entry->Data.ClearPoly.Layer, ptr3);
324 else
325 ClearFromPolygon (PCB->Data, type, Entry->Data.ClearPoly.Layer, ptr3);
326 Entry->Data.ClearPoly.Clear = !Entry->Data.ClearPoly.Clear;
327 return True;
329 return False;
332 /* ---------------------------------------------------------------------------
333 * recovers an object from a 'change name' operation
334 * returns True if anything has been recovered
336 static Boolean
337 UndoChangeName (UndoListTypePtr Entry)
339 void *ptr1, *ptr2, *ptr3;
340 int type;
342 /* lookup entry by it's ID */
343 type =
344 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
345 if (type != NO_TYPE)
347 if (TEST_FLAG (LOCKFLAG, (TextTypePtr) ptr3))
348 return (False);
349 Entry->Data.ChangeName.Name =
350 (ChangeObjectName (type, ptr1, ptr2, ptr3,
351 Entry->Data.ChangeName.Name));
352 return (True);
354 return (False);
357 /* ---------------------------------------------------------------------------
358 * recovers an object from a 2ndSize change operation
360 static Boolean
361 UndoChange2ndSize (UndoListTypePtr Entry)
363 void *ptr1, *ptr2, *ptr3;
364 int type;
365 BDimension swap;
367 /* lookup entry by ID */
368 type =
369 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
370 if (type != NO_TYPE)
372 if (TEST_FLAG (LOCKFLAG, (PinTypePtr) ptr2))
373 return (False);
374 swap = ((PinTypePtr) ptr2)->DrillingHole;
375 if (andDraw)
376 EraseObject (type, ptr1, ptr2);
377 ((PinTypePtr) ptr2)->DrillingHole = Entry->Data.Size;
378 Entry->Data.Size = swap;
379 DrawObject (type, ptr1, ptr2, 0);
380 return (True);
382 return (False);
385 /* ---------------------------------------------------------------------------
386 * recovers an object from a ChangeAngles change operation
388 static Boolean
389 UndoChangeAngles (UndoListTypePtr Entry)
391 void *ptr1, *ptr2, *ptr3;
392 int type;
393 long int old_sa, old_da;
395 /* lookup entry by ID */
396 type =
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))
403 return (False);
404 r_delete_entry (Layer->arc_tree, (BoxTypePtr) a);
405 old_sa = a->StartAngle;
406 old_da = a->Delta;
407 if (andDraw)
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);
416 return (True);
418 return (False);
421 /* ---------------------------------------------------------------------------
422 * recovers an object from a clearance size change operation
424 static Boolean
425 UndoChangeClearSize (UndoListTypePtr Entry)
427 void *ptr1, *ptr2, *ptr3;
428 int type;
429 BDimension swap;
431 /* lookup entry by ID */
432 type =
433 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
434 if (type != NO_TYPE)
436 if (TEST_FLAG (LOCKFLAG, (LineTypePtr) ptr2))
437 return (False);
438 swap = ((PinTypePtr) ptr2)->Clearance;
439 RestoreToPolygon (PCB->Data, type, ptr1, ptr2);
440 if (andDraw)
441 EraseObject (type, ptr1, ptr2);
442 ((PinTypePtr) ptr2)->Clearance = Entry->Data.Size;
443 ClearFromPolygon (PCB->Data, type, ptr1, ptr2);
444 Entry->Data.Size = swap;
445 if (andDraw)
446 DrawObject (type, ptr1, ptr2, 0);
447 return (True);
449 return (False);
452 /* ---------------------------------------------------------------------------
453 * recovers an object from a mask size change operation
455 static Boolean
456 UndoChangeMaskSize (UndoListTypePtr Entry)
458 void *ptr1, *ptr2, *ptr3;
459 int type;
460 BDimension swap;
462 /* lookup entry by ID */
463 type =
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))
468 return (False);
469 swap =
470 (type ==
471 PAD_TYPE ? ((PadTypePtr) ptr2)->Mask : ((PinTypePtr) ptr2)->Mask);
472 if (andDraw)
473 EraseObject (type, ptr1, ptr2);
474 if (type == PAD_TYPE)
475 ((PadTypePtr) ptr2)->Mask = Entry->Data.Size;
476 else
477 ((PinTypePtr) ptr2)->Mask = Entry->Data.Size;
478 Entry->Data.Size = swap;
479 if (andDraw)
480 DrawObject (type, ptr1, ptr2, 0);
481 return (True);
483 return (False);
487 /* ---------------------------------------------------------------------------
488 * recovers an object from a Size change operation
490 static Boolean
491 UndoChangeSize (UndoListTypePtr Entry)
493 void *ptr1, *ptr2, *ptr3;
494 int type;
495 BDimension swap;
497 /* lookup entry by ID */
498 type =
499 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
500 if (type != NO_TYPE)
502 if (TEST_FLAG (LOCKFLAG, (PinTypePtr) ptr2))
503 return (False);
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);
508 if (andDraw)
509 EraseObject (type, ptr1, ptr2);
510 ((PinTypePtr) ptr2)->Thickness = Entry->Data.Size;
511 Entry->Data.Size = swap;
512 ClearFromPolygon (PCB->Data, type, ptr1, ptr2);
513 if (andDraw)
514 DrawObject (type, ptr1, ptr2, 0);
515 return (True);
517 return (False);
520 /* ---------------------------------------------------------------------------
521 * recovers an object from a FLAG change operation
523 static Boolean
524 UndoFlag (UndoListTypePtr Entry)
526 void *ptr1, *ptr2, *ptr3;
527 int type;
528 FlagType swap;
529 int must_redraw;
531 /* lookup entry by ID */
532 type =
533 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
534 if (type != NO_TYPE)
536 FlagType f1, f2;
537 PinTypePtr pin = (PinTypePtr) ptr2;
539 if (TEST_FLAG (LOCKFLAG, pin))
540 return (False);
542 swap = pin->Flags;
544 must_redraw = 0;
545 f1 = MaskFlags (pin->Flags, ~DRAW_FLAGS);
546 f2 = MaskFlags (Entry->Data.Flags, ~DRAW_FLAGS);
548 if (!FLAGS_EQUAL (f1, f2))
549 must_redraw = 1;
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);
560 return (True);
562 Message ("hace Internal error: Can't find ID %d type %08x\n", Entry->ID,
563 Entry->Kind);
564 Message ("for UndoFlag Operation. Previous flags: %s\n",
565 flags_to_string (Entry->Data.Flags, 0));
566 return (False);
569 /* ---------------------------------------------------------------------------
570 * recovers an object from a mirror operation
571 * returns True if anything has been recovered
573 static Boolean
574 UndoMirror (UndoListTypePtr Entry)
576 void *ptr1, *ptr2, *ptr3;
577 int type;
579 /* lookup entry by ID */
580 type =
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))
586 return (False);
587 if (andDraw)
588 EraseElement (element);
589 MirrorElementCoordinates (PCB->Data, element, Entry->Data.Move.DY);
590 if (andDraw)
591 DrawElement (element, 0);
592 return (True);
594 Message ("hace Internal error: UndoMirror on object type %d\n", type);
595 return (False);
598 /* ---------------------------------------------------------------------------
599 * recovers an object from a 'copy' or 'create' operation
600 * returns True if anything has been recovered
602 static Boolean
603 UndoCopyOrCreate (UndoListTypePtr Entry)
605 void *ptr1, *ptr2, *ptr3;
606 int type;
608 /* lookup entry by it's ID */
609 type =
610 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
611 if (type != NO_TYPE)
613 if (TEST_FLAG (LOCKFLAG, (PinTypePtr) ptr2))
614 return (False);
615 if (!RemoveList)
616 RemoveList = CreateNewBuffer ();
617 if (andDraw)
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;
622 return (True);
624 return (False);
627 /* ---------------------------------------------------------------------------
628 * recovers an object from a 'move' operation
629 * returns True if anything has been recovered
631 static Boolean
632 UndoMove (UndoListTypePtr Entry)
634 void *ptr1, *ptr2, *ptr3;
635 int type;
637 /* lookup entry by it's ID */
638 type =
639 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
640 if (type != NO_TYPE)
642 if (TEST_FLAG (LOCKFLAG, (LineTypePtr) ptr2))
643 return (False);
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;
648 return (True);
650 return (False);
653 /* ----------------------------------------------------------------------
654 * recovers an object from a 'remove' operation
655 * returns True if anything has been recovered
657 static Boolean
658 UndoRemove (UndoListTypePtr Entry)
660 void *ptr1, *ptr2, *ptr3;
661 int type;
663 /* lookup entry by it's ID */
664 type =
665 SearchObjectByID (RemoveList, &ptr1, &ptr2, &ptr3, Entry->ID,
666 Entry->Kind);
667 if (type != NO_TYPE)
669 if (andDraw)
670 DrawRecoveredObject (type, ptr1, ptr2, ptr3);
671 MoveObjectToBuffer (PCB->Data, RemoveList, type, ptr1, ptr2, ptr3);
672 Entry->Type = UNDO_CREATE;
673 return (True);
675 return (False);
678 /* ----------------------------------------------------------------------
679 * recovers an object from a 'move to another layer' operation
680 * returns True if anything has been recovered
682 static Boolean
683 UndoMoveToLayer (UndoListTypePtr Entry)
685 void *ptr1, *ptr2, *ptr3;
686 int type, swap;
688 /* lookup entry by it's ID */
689 type =
690 SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
691 if (type != NO_TYPE)
693 if (TEST_FLAG (LOCKFLAG, (LineTypePtr) ptr2))
694 return (False);
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;
700 return (True);
702 return (False);
705 /* ---------------------------------------------------------------------------
706 * recovers a removed polygon point
707 * returns true on success
709 static Boolean
710 UndoRemovePoint (UndoListTypePtr Entry)
712 LayerTypePtr layer;
713 PolygonTypePtr polygon;
714 void *ptr3;
715 int type;
717 /* lookup entry (polygon not point was saved) by it's ID */
718 assert (Entry->Kind == POLYGON_TYPE);
719 type =
720 SearchObjectByID (PCB->Data, (void *) &layer, (void *) &polygon, &ptr3,
721 Entry->ID, Entry->Kind);
722 switch (type)
724 case POLYGON_TYPE: /* restore the removed point */
726 if (TEST_FLAG (LOCKFLAG, polygon))
727 return (False);
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;
742 return (True);
745 default:
746 return (False);
750 /* ---------------------------------------------------------------------------
751 * recovers an inserted polygon point
752 * returns true on success
754 static Boolean
755 UndoInsertPoint (UndoListTypePtr Entry)
757 LayerTypePtr layer;
758 PolygonTypePtr polygon;
759 PointTypePtr pnt;
760 int type;
762 assert (Entry->Kind == POLYGONPOINT_TYPE);
763 /* lookup entry by it's ID */
764 type =
765 SearchObjectByID (PCB->Data, (void *) &layer, (void *) &polygon,
766 (void *) &pnt, Entry->ID, Entry->Kind);
767 switch (type)
769 case POLYGONPOINT_TYPE: /* removes an inserted polygon point */
771 if (TEST_FLAG (LOCKFLAG, polygon))
772 return (False);
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);
783 if (pnt == point)
785 Entry->Data.RemovedPoint.Index = n;
786 break;
789 END_LOOP;
790 DestroyObject (PCB->Data, POLYGONPOINT_TYPE, layer, polygon, pnt);
791 if (andDraw && layer->On)
792 DrawPolygon (layer, polygon, 0);
793 return (True);
796 default:
797 return (False);
801 /* ---------------------------------------------------------------------------
802 * undo a layer change
803 * returns true on success
805 static Boolean
806 UndoLayerChange (UndoListTypePtr Entry)
808 LayerChangeTypePtr l = &Entry->Data.LayerChange;
809 int tmp;
811 tmp = l->new_index;
812 l->new_index = l->old_index;
813 l->old_index = tmp;
815 if (MoveLayer (l->old_index, l->new_index))
816 return False;
817 else
818 return True;
821 /* ---------------------------------------------------------------------------
822 * undo a netlist change
823 * returns true on success
825 static Boolean
826 UndoNetlistChange (UndoListTypePtr Entry)
828 NetlistChangeTypePtr l = & Entry->Data.NetlistChange;
829 unsigned int i, j;
830 LibraryTypePtr lib, saved;
832 lib = l->lib;
833 saved = l->old;
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);
871 if (lib->Menu)
872 free (lib->Menu);
874 *lib = *saved;
876 NetlistChanged (0);
877 return True;
880 /* ---------------------------------------------------------------------------
881 * undo of any 'hard to recover' operation
883 * returns the bitfield for the types of operations that were undone
886 Undo (Boolean draw)
888 UndoListTypePtr ptr;
889 int Types = 0;
890 int unique;
892 unique = TEST_FLAG (UNIQUENAMEFLAG, PCB);
893 CLEAR_FLAG (UNIQUENAMEFLAG, PCB);
895 andDraw = draw;
899 if (!UndoN)
901 if (!Serial)
902 Message (_("Nothing to undo - buffer is empty\n"));
903 else
904 Serial--;
905 return (False);
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;
917 return (False);
919 LockUndo ();
920 Serial = ptr->Serial;
921 for (; UndoN && ptr->Serial == Serial; ptr--, UndoN--, RedoN++)
922 Types |= PerformUndo (ptr);
923 /* release lock */
924 UnlockUndo ();
926 while (Types == 0);
927 if (Types && andDraw)
928 Draw ();
930 /* restore the unique flag setting */
931 if (unique)
932 SET_FLAG (UNIQUENAMEFLAG, PCB);
934 return (Types);
937 static int
938 PerformUndo (UndoListTypePtr ptr)
940 switch (ptr->Type)
942 case UNDO_CHANGENAME:
943 if (UndoChangeName (ptr))
944 return (UNDO_CHANGENAME);
945 break;
947 case UNDO_CREATE:
948 if (UndoCopyOrCreate (ptr))
949 return (UNDO_CREATE);
950 break;
952 case UNDO_MOVE:
953 if (UndoMove (ptr))
954 return (UNDO_MOVE);
955 break;
957 case UNDO_REMOVE:
958 if (UndoRemove (ptr))
959 return (UNDO_REMOVE);
960 break;
962 case UNDO_REMOVE_POINT:
963 if (UndoRemovePoint (ptr))
964 return (UNDO_REMOVE_POINT);
965 break;
967 case UNDO_INSERT_POINT:
968 if (UndoInsertPoint (ptr))
969 return (UNDO_INSERT_POINT);
970 break;
972 case UNDO_ROTATE:
973 if (UndoRotate (ptr))
974 return (UNDO_ROTATE);
975 break;
977 case UNDO_CLEAR:
978 if (UndoClearPoly (ptr))
979 return (UNDO_CLEAR);
980 break;
982 case UNDO_MOVETOLAYER:
983 if (UndoMoveToLayer (ptr))
984 return (UNDO_MOVETOLAYER);
985 break;
987 case UNDO_FLAG:
988 if (UndoFlag (ptr))
989 return (UNDO_FLAG);
990 break;
992 case UNDO_CHANGESIZE:
993 if (UndoChangeSize (ptr))
994 return (UNDO_CHANGESIZE);
995 break;
997 case UNDO_CHANGECLEARSIZE:
998 if (UndoChangeClearSize (ptr))
999 return (UNDO_CHANGECLEARSIZE);
1000 break;
1002 case UNDO_CHANGEMASKSIZE:
1003 if (UndoChangeMaskSize (ptr))
1004 return (UNDO_CHANGEMASKSIZE);
1005 break;
1007 case UNDO_CHANGE2NDSIZE:
1008 if (UndoChange2ndSize (ptr))
1009 return (UNDO_CHANGE2NDSIZE);
1010 break;
1012 case UNDO_CHANGEANGLES:
1013 if (UndoChangeAngles (ptr))
1014 return (UNDO_CHANGEANGLES);
1015 break;
1017 case UNDO_LAYERCHANGE:
1018 if (UndoLayerChange (ptr))
1019 return (UNDO_LAYERCHANGE);
1020 break;
1022 case UNDO_NETLISTCHANGE:
1023 if (UndoNetlistChange (ptr))
1024 return (UNDO_NETLISTCHANGE);
1025 break;
1027 case UNDO_MIRROR:
1028 if (UndoMirror (ptr))
1029 return (UNDO_MIRROR);
1030 break;
1032 return 0;
1035 /* ---------------------------------------------------------------------------
1036 * redo of any 'hard to recover' operation
1038 * returns the number of operations redone
1041 Redo (Boolean draw)
1043 UndoListTypePtr ptr;
1044 int Types = 0;
1046 andDraw = draw;
1049 if (!RedoN)
1051 Message
1053 ("Nothing to redo. Perhaps changes have been made since last undo\n"));
1054 return (False);
1057 /* lock undo module to prevent from loops
1058 * and loop over all entries with the same serial number
1060 LockUndo ();
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 */
1066 Serial++;
1067 UnlockUndo ();
1069 while (Types == 0);
1070 if (Types && andDraw)
1071 Draw ();
1072 return (Types);
1075 /* ---------------------------------------------------------------------------
1076 * restores the serial number of the undo list
1078 void
1079 RestoreUndoSerialNumber (void)
1081 Serial = SavedSerial;
1084 /* ---------------------------------------------------------------------------
1085 * saves the serial number of the undo list
1087 void
1088 SaveUndoSerialNumber (void)
1090 Bumped = False;
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 #
1099 void
1100 IncrementUndoSerialNumber (void)
1102 if (!Locked)
1104 /* don't increment if nothing was added */
1105 if (UndoN == 0 || UndoList[UndoN - 1].Serial != Serial)
1106 return;
1107 Serial++;
1108 Bumped = True;
1109 SetChangedFlag (True);
1113 /* ---------------------------------------------------------------------------
1114 * releases memory of the undo- and remove list
1116 void
1117 ClearUndoList (Boolean Force)
1119 UndoListTypePtr undo;
1121 if (UndoN
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);
1130 MYFREE (UndoList);
1131 if (RemoveList)
1133 FreeDataMemory (RemoveList);
1134 free (RemoveList);
1135 RemoveList = NULL;
1138 /* reset some counters */
1139 UndoN = UndoMax = RedoN = 0;
1142 /* reset counter in any case */
1143 Serial = 1;
1146 /* ---------------------------------------------------------------------------
1147 * adds an object to the list of clearpoly objects
1149 void
1150 AddObjectToClearPolyUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
1151 Boolean clear)
1153 UndoListTypePtr undo;
1155 if (!Locked)
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
1166 void
1167 AddObjectToMirrorUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
1168 LocationType yoff)
1170 UndoListTypePtr undo;
1172 if (!Locked)
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
1182 void
1183 AddObjectToRotateUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
1184 LocationType CenterX, LocationType CenterY,
1185 BYTE Steps)
1187 UndoListTypePtr undo;
1189 if (!Locked)
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
1200 * the current PCB
1202 void
1203 MoveObjectToRemoveUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1205 UndoListTypePtr undo;
1207 if (!Locked)
1209 if (!RemoveList)
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
1220 void
1221 AddObjectToRemovePointUndoList (int Type,
1222 void *Ptr1, void *Ptr2, Cardinal index)
1224 UndoListTypePtr undo;
1225 PolygonTypePtr polygon = (PolygonTypePtr) Ptr2;
1227 if (!Locked)
1229 switch (Type)
1231 case POLYGONPOINT_TYPE:
1233 /* save the ID of the parent object; else it will be
1234 * impossible to recover the point
1236 undo =
1237 GetUndoSlot (UNDO_REMOVE_POINT, OBJECT_ID (polygon),
1238 POLYGON_TYPE);
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;
1244 break;
1249 /* ---------------------------------------------------------------------------
1250 * adds an object to the list of inserted polygon/... points
1252 void
1253 AddObjectToInsertPointUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1255 UndoListTypePtr undo;
1257 if (!Locked)
1258 undo = GetUndoSlot (UNDO_INSERT_POINT, OBJECT_ID (Ptr3), Type);
1261 /* ---------------------------------------------------------------------------
1262 * adds an object to the list of moved objects
1264 void
1265 AddObjectToMoveUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
1266 LocationType DX, LocationType DY)
1268 UndoListTypePtr undo;
1270 if (!Locked)
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
1281 void
1282 AddObjectToChangeNameUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
1283 char *OldName)
1285 UndoListTypePtr undo;
1287 if (!Locked)
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
1297 void
1298 AddObjectToMoveToLayerUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1300 UndoListTypePtr undo;
1302 if (!Locked)
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
1313 void
1314 AddObjectToCreateUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1316 UndoListTypePtr undo;
1318 if (!Locked)
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
1326 void
1327 AddObjectToFlagUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1329 UndoListTypePtr undo;
1331 if (!Locked)
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
1341 void
1342 AddObjectToSizeUndoList (int Type, void *ptr1, void *ptr2, void *ptr3)
1344 UndoListTypePtr undo;
1346 if (!Locked)
1348 undo = GetUndoSlot (UNDO_CHANGESIZE, OBJECT_ID (ptr2), Type);
1349 switch (Type)
1351 case PIN_TYPE:
1352 case VIA_TYPE:
1353 undo->Data.Size = ((PinTypePtr) ptr2)->Thickness;
1354 break;
1355 case LINE_TYPE:
1356 case ELEMENTLINE_TYPE:
1357 undo->Data.Size = ((LineTypePtr) ptr2)->Thickness;
1358 break;
1359 case TEXT_TYPE:
1360 case ELEMENTNAME_TYPE:
1361 undo->Data.Size = ((TextTypePtr) ptr2)->Scale;
1362 break;
1363 case PAD_TYPE:
1364 undo->Data.Size = ((PadTypePtr) ptr2)->Thickness;
1365 break;
1366 case ARC_TYPE:
1367 case ELEMENTARC_TYPE:
1368 undo->Data.Size = ((ArcTypePtr) ptr2)->Thickness;
1369 break;
1374 /* ---------------------------------------------------------------------------
1375 * adds an object to the list of objects with Size changes
1377 void
1378 AddObjectToClearSizeUndoList (int Type, void *ptr1, void *ptr2, void *ptr3)
1380 UndoListTypePtr undo;
1382 if (!Locked)
1384 undo = GetUndoSlot (UNDO_CHANGECLEARSIZE, OBJECT_ID (ptr2), Type);
1385 switch (Type)
1387 case PIN_TYPE:
1388 case VIA_TYPE:
1389 undo->Data.Size = ((PinTypePtr) ptr2)->Clearance;
1390 break;
1391 case LINE_TYPE:
1392 undo->Data.Size = ((LineTypePtr) ptr2)->Clearance;
1393 break;
1394 case PAD_TYPE:
1395 undo->Data.Size = ((PadTypePtr) ptr2)->Clearance;
1396 break;
1397 case ARC_TYPE:
1398 undo->Data.Size = ((ArcTypePtr) ptr2)->Clearance;
1399 break;
1404 /* ---------------------------------------------------------------------------
1405 * adds an object to the list of objects with Size changes
1407 void
1408 AddObjectToMaskSizeUndoList (int Type, void *ptr1, void *ptr2, void *ptr3)
1410 UndoListTypePtr undo;
1412 if (!Locked)
1414 undo = GetUndoSlot (UNDO_CHANGEMASKSIZE, OBJECT_ID (ptr2), Type);
1415 switch (Type)
1417 case PIN_TYPE:
1418 case VIA_TYPE:
1419 undo->Data.Size = ((PinTypePtr) ptr2)->Mask;
1420 break;
1421 case PAD_TYPE:
1422 undo->Data.Size = ((PadTypePtr) ptr2)->Mask;
1423 break;
1428 /* ---------------------------------------------------------------------------
1429 * adds an object to the list of objects with 2ndSize changes
1431 void
1432 AddObjectTo2ndSizeUndoList (int Type, void *ptr1, void *ptr2, void *ptr3)
1434 UndoListTypePtr undo;
1436 if (!Locked)
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.
1448 void
1449 AddObjectToChangeAnglesUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1451 UndoListTypePtr undo;
1452 ArcTypePtr a = (ArcTypePtr) Ptr3;
1454 if (!Locked)
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.
1465 void
1466 AddLayerChangeToUndoList (int old_index, int new_index)
1468 UndoListTypePtr undo;
1470 if (!Locked)
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
1481 void
1482 AddNetlistLibToUndoList (LibraryTypePtr lib)
1484 UndoListTypePtr undo;
1485 unsigned int i, j;
1486 LibraryTypePtr old;
1488 if (!Locked)
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__);
1503 exit (1);
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;
1512 old->Menu[i].Name =
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__);
1527 exit (1);
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) :
1536 NULL;
1538 old->Menu[i].Entry[j].AllocatedMemory =
1539 lib->Menu[i].Entry[j].AllocatedMemory ?
1540 strdup (lib->Menu[i].Entry[j].AllocatedMemory) :
1541 NULL;
1543 old->Menu[i].Entry[j].Template =
1544 lib->Menu[i].Entry[j].Template ?
1545 strdup (lib->Menu[i].Entry[j].Template) :
1546 NULL;
1548 old->Menu[i].Entry[j].Package =
1549 lib->Menu[i].Entry[j].Package ?
1550 strdup (lib->Menu[i].Entry[j].Package) :
1551 NULL;
1553 old->Menu[i].Entry[j].Value =
1554 lib->Menu[i].Entry[j].Value ?
1555 strdup (lib->Menu[i].Entry[j].Value) :
1556 NULL;
1558 old->Menu[i].Entry[j].Description =
1559 lib->Menu[i].Entry[j].Description ?
1560 strdup (lib->Menu[i].Entry[j].Description) :
1561 NULL;
1570 /* ---------------------------------------------------------------------------
1571 * set lock flag
1573 void
1574 LockUndo (void)
1576 Locked = True;
1579 /* ---------------------------------------------------------------------------
1580 * reset lock flag
1582 void
1583 UnlockUndo (void)
1585 Locked = False;
1588 /* ---------------------------------------------------------------------------
1589 * return undo lock state
1591 Boolean
1592 Undoing (void)
1594 return (Locked);