pcb 4.1.1
An interactive printed circuit board layout editor.

undo.c

Go to the documentation of this file.
00001 
00054 #ifdef HAVE_CONFIG_H
00055 #include "config.h"
00056 #endif
00057 
00058 #include <assert.h>
00059 #include <memory.h>
00060 #include "global.h"
00061 
00062 #include "buffer.h"
00063 #include "change.h"
00064 #include "create.h"
00065 #include "data.h"
00066 #include "draw.h"
00067 #include "error.h"
00068 #include "insert.h"
00069 #include "misc.h"
00070 #include "mirror.h"
00071 #include "move.h"
00072 #include "mymem.h"
00073 #include "polygon.h"
00074 #include "remove.h"
00075 #include "rotate.h"
00076 #include "rtree.h"
00077 #include "search.h"
00078 #include "set.h"
00079 #include "undo.h"
00080 #include "strflags.h"
00081 
00082 #ifdef HAVE_LIBDMALLOC
00083 #include <dmalloc.h>
00084 #endif
00085 
00086 static bool between_increment_and_restore = false;
00087 static bool added_undo_between_increment_and_restore = false;
00088 
00089 /* ---------------------------------------------------------------------------
00090  * some local data types
00091  */
00092 
00096 typedef struct
00097 {
00098   char *Name;
00099 } ChangeNameType;
00100 
00104 typedef struct
00105 {
00106   Coord DX; 
00107   Coord DY; 
00108 } MoveType;
00109 
00113 typedef struct
00114 {
00115   Coord X; 
00116   Coord Y; 
00117   int ID;
00118   Cardinal Index; 
00119   bool last_in_contour; 
00120 } RemovedPointType;
00121 
00125 typedef struct
00126 {
00127   Coord CenterX; 
00128   Coord CenterY; 
00129   Cardinal Steps; 
00130 } RotateType;
00131 
00135 typedef struct
00136 {
00137   Cardinal OriginalLayer; 
00138 } MoveToLayerType;
00139 
00143 typedef struct
00144 {
00145   int old_index;
00146   int new_index;
00147 } LayerChangeType;
00148 
00152 typedef struct
00153 {
00154   int from;
00155   int to;
00156 } SetViaLayersChangeType;
00157 
00161 typedef struct
00162 {
00163   bool Clear; 
00164   LayerType *Layer;
00165 } ClearPolyType;
00166 
00170 typedef struct
00171 {
00172   LibraryType *old;
00173   LibraryType *lib;
00174 } NetlistChangeType;
00175 
00179 typedef struct
00180 {
00181   int Serial, 
00182     Type, 
00183     Kind, 
00184     ID; 
00185   union /* Some additional information. */
00186   {
00187     ChangeNameType ChangeName;
00188     MoveType Move;
00189     RemovedPointType RemovedPoint;
00190     RotateType Rotate;
00191     MoveToLayerType MoveToLayer;
00192     FlagType Flags;
00193     Coord Size;
00194     int Scale;
00195     LayerChangeType LayerChange;
00196     ClearPolyType ClearPoly;
00197     NetlistChangeType NetlistChange;
00198     SetViaLayersChangeType SetViaLayersChange;
00199     long int CopyID;
00200   }
00201   Data;
00202 } UndoListType;
00203 
00204 /* ---------------------------------------------------------------------------
00205  * some local variables
00206  */
00207 static DataType *RemoveList = NULL; 
00208 static UndoListType *UndoList = NULL; 
00209 static int Serial = 1; 
00210 static int SavedSerial;
00211 static size_t UndoN; 
00212 static size_t RedoN; 
00213 static size_t UndoMax; 
00214 static bool Locked = false; 
00215 static bool andDraw = true;
00216                                                                                 /* flag is set; prevents from */
00217                                                                                 /* infinite loops */
00218 
00219 /* ---------------------------------------------------------------------------
00220  * some local prototypes
00221  */
00222 static UndoListType *GetUndoSlot (int, int, int);
00223 static void DrawRecoveredObject (int, void *, void *, void *);
00224 static bool UndoRotate (UndoListType *);
00225 static bool UndoChangeName (UndoListType *);
00226 static bool UndoCopyOrCreate (UndoListType *);
00227 static bool UndoMove (UndoListType *);
00228 static bool UndoRemove (UndoListType *);
00229 static bool UndoRemovePoint (UndoListType *);
00230 static bool UndoInsertPoint (UndoListType *);
00231 static bool UndoRemoveContour (UndoListType *);
00232 static bool UndoInsertContour (UndoListType *);
00233 static bool UndoMoveToLayer (UndoListType *);
00234 static bool UndoFlag (UndoListType *);
00235 static bool UndoMirror (UndoListType *);
00236 static bool UndoChangeSize (UndoListType *);
00237 static bool UndoChange2ndSize (UndoListType *);
00238 static bool UndoChangeAngles (UndoListType *);
00239 static bool UndoChangeClearSize (UndoListType *);
00240 static bool UndoChangeMaskSize (UndoListType *);
00241 static bool UndoClearPoly (UndoListType *);
00242 static bool UndoSetViaLayers (UndoListType *);
00243 static int PerformUndo (UndoListType *);
00244 
00248 static UndoListType *
00249 GetUndoSlot (int CommandType, int ID, int Kind)
00250 {
00251   UndoListType *ptr;
00252   void *ptr1, *ptr2, *ptr3;
00253   int type;
00254   static size_t limit = UNDO_WARNING_SIZE;
00255 
00256 #ifdef DEBUG_ID
00257   if (SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, ID, Kind) == NO_TYPE)
00258     Message ("hace: ID (%d) and Type (%x) mismatch in AddObject...\n", ID,
00259              Kind);
00260 #endif
00261 
00262   /* allocate memory */
00263   if (UndoN >= UndoMax)
00264     {
00265       size_t size;
00266 
00267       UndoMax += STEP_UNDOLIST;
00268       size = UndoMax * sizeof (UndoListType);
00269       UndoList = (UndoListType *) realloc (UndoList, size);
00270       memset (&UndoList[UndoN], 0, STEP_REMOVELIST * sizeof (UndoListType));
00271 
00272       /* ask user to flush the table because of it's size */
00273       if (size > limit)
00274         {
00275           limit = (size / UNDO_WARNING_SIZE + 1) * UNDO_WARNING_SIZE;
00276           Message (_("Size of 'undo-list' exceeds %li kb\n"),
00277                    (long) (size >> 10));
00278         }
00279     }
00280 
00281   /* free structures from the pruned redo list */
00282 
00283   for (ptr = &UndoList[UndoN]; RedoN; ptr++, RedoN--)
00284     switch (ptr->Type)
00285       {
00286       case UNDO_CHANGENAME:
00287         free (ptr->Data.ChangeName.Name);
00288         break;
00289       case UNDO_REMOVE:
00290         type =
00291           SearchObjectByID (RemoveList, &ptr1, &ptr2, &ptr3, ptr->ID,
00292                             ptr->Kind);
00293         if (type != NO_TYPE)
00294           {
00295             DestroyObject (RemoveList, type, ptr1, ptr2, ptr3);
00296           }
00297         break;
00298       default:
00299         break;
00300       }
00301 
00302   if (between_increment_and_restore)
00303     added_undo_between_increment_and_restore = true;
00304 
00305   /* copy typefield and serial number to the list */
00306   ptr = &UndoList[UndoN++];
00307   ptr->Type = CommandType;
00308   ptr->Kind = Kind;
00309   ptr->ID = ID;
00310   ptr->Serial = Serial;
00311   return (ptr);
00312 }
00313 
00317 static void
00318 DrawRecoveredObject (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
00319 {
00320   if (Type & (LINE_TYPE | TEXT_TYPE | POLYGON_TYPE | ARC_TYPE))
00321     {
00322       LayerType *layer;
00323 
00324       layer = LAYER_PTR (GetLayerNumber (RemoveList, (LayerType *) Ptr1));
00325       DrawObject (Type, (void *) layer, Ptr2);
00326     }
00327   else
00328     DrawObject (Type, Ptr1, Ptr2);
00329 }
00330 
00336 static bool
00337 UndoRotate (UndoListType *Entry)
00338 {
00339   void *ptr1, *ptr2, *ptr3;
00340   int type;
00341 
00342   /* lookup entry by it's ID */
00343   type =
00344     SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
00345   if (type != NO_TYPE)
00346     {
00347       RotateObject (type, ptr1, ptr2, ptr3,
00348                     Entry->Data.Rotate.CenterX, Entry->Data.Rotate.CenterY,
00349                     (4 - Entry->Data.Rotate.Steps) & 0x03);
00350       Entry->Data.Rotate.Steps = (4 - Entry->Data.Rotate.Steps) & 0x03;
00351       return (true);
00352     }
00353   return (false);
00354 }
00355 
00361 static bool
00362 UndoClearPoly (UndoListType *Entry)
00363 {
00364   void *ptr1, *ptr2, *ptr3;
00365   int type;
00366 
00367   type =
00368     SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
00369   if (type != NO_TYPE)
00370     {
00371       if (Entry->Data.ClearPoly.Clear)
00372         RestoreToPolygon (PCB->Data, type, Entry->Data.ClearPoly.Layer, ptr3);
00373       else
00374         ClearFromPolygon (PCB->Data, type, Entry->Data.ClearPoly.Layer, ptr3);
00375       Entry->Data.ClearPoly.Clear = !Entry->Data.ClearPoly.Clear;
00376       return true;
00377     }
00378   return false;
00379 }
00380 
00386 static bool
00387 UndoChangeName (UndoListType *Entry)
00388 {
00389   void *ptr1, *ptr2, *ptr3;
00390   int type;
00391 
00392   /* lookup entry by it's ID */
00393   type =
00394     SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
00395   if (type != NO_TYPE)
00396     {
00397       Entry->Data.ChangeName.Name =
00398         (char *)(ChangeObjectName (type, ptr1, ptr2, ptr3,
00399                            Entry->Data.ChangeName.Name));
00400       return (true);
00401     }
00402   return (false);
00403 }
00404 
00408 static bool
00409 UndoChange2ndSize (UndoListType *Entry)
00410 {
00411   void *ptr1, *ptr2, *ptr3;
00412   int type;
00413   Coord swap;
00414 
00415   /* lookup entry by ID */
00416   type =
00417     SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
00418   if (type != NO_TYPE)
00419     {
00420       swap = ((PinType *) ptr2)->DrillingHole;
00421       if (andDraw)
00422         EraseObject (type, ptr1, ptr2);
00423       ((PinType *) ptr2)->DrillingHole = Entry->Data.Size;
00424       Entry->Data.Size = swap;
00425       DrawObject (type, ptr1, ptr2);
00426       return (true);
00427     }
00428   return (false);
00429 }
00430 
00434 static bool
00435 UndoChangeAngles (UndoListType *Entry)
00436 {
00437   void *ptr1, *ptr2, *ptr3;
00438   int type;
00439   long int old_sa, old_da;
00440 
00441   /* lookup entry by ID */
00442   type =
00443     SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
00444   if (type == ARC_TYPE)
00445     {
00446       LayerType *Layer = (LayerType *) ptr1;
00447       ArcType *a = (ArcType *) ptr2;
00448       r_delete_entry (Layer->arc_tree, (BoxType *) a);
00449       old_sa = a->StartAngle;
00450       old_da = a->Delta;
00451       if (andDraw)
00452         EraseObject (type, Layer, a);
00453       a->StartAngle = Entry->Data.Move.DX;
00454       a->Delta = Entry->Data.Move.DY;
00455       SetArcBoundingBox (a);
00456       r_insert_entry (Layer->arc_tree, (BoxType *) a, 0);
00457       Entry->Data.Move.DX = old_sa;
00458       Entry->Data.Move.DY = old_da;;
00459       DrawObject (type, ptr1, a);
00460       return (true);
00461     }
00462   return (false);
00463 }
00464 
00468 static bool
00469 UndoChangeClearSize (UndoListType *Entry)
00470 {
00471   void *ptr1, *ptr2, *ptr3;
00472   int type;
00473   Coord swap;
00474 
00475   /* lookup entry by ID */
00476   type =
00477     SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
00478   if (type != NO_TYPE)
00479     {
00480       swap = ((PinType *) ptr2)->Clearance;
00481       RestoreToPolygon (PCB->Data, type, ptr1, ptr2);
00482       if (andDraw)
00483         EraseObject (type, ptr1, ptr2);
00484       ((PinType *) ptr2)->Clearance = Entry->Data.Size;
00485       ClearFromPolygon (PCB->Data, type, ptr1, ptr2);
00486       Entry->Data.Size = swap;
00487       if (andDraw)
00488         DrawObject (type, ptr1, ptr2);
00489       return (true);
00490     }
00491   return (false);
00492 }
00493 
00497 static bool
00498 UndoChangeMaskSize (UndoListType *Entry)
00499 {
00500   void *ptr1, *ptr2, *ptr3;
00501   int type;
00502   Coord swap;
00503 
00504   /* lookup entry by ID */
00505   type =
00506     SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
00507   if (type & (VIA_TYPE | PIN_TYPE | PAD_TYPE))
00508     {
00509       swap =
00510         (type ==
00511          PAD_TYPE ? ((PadType *) ptr2)->Mask : ((PinType *) ptr2)->Mask);
00512       if (andDraw)
00513         EraseObject (type, ptr1, ptr2);
00514       if (type == PAD_TYPE)
00515         ((PadType *) ptr2)->Mask = Entry->Data.Size;
00516       else
00517         ((PinType *) ptr2)->Mask = Entry->Data.Size;
00518       Entry->Data.Size = swap;
00519       if (andDraw)
00520         DrawObject (type, ptr1, ptr2);
00521       return (true);
00522     }
00523   return (false);
00524 }
00525 
00526 
00530 static bool
00531 UndoChangeSize (UndoListType *Entry)
00532 {
00533   void *ptr1, *ptr2, *ptr3;
00534   int type, iswap = 0;
00535   Coord swap = 0;
00536 
00537   /* lookup entry by ID */
00538   type =
00539     SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
00540   if (type != NO_TYPE)
00541     {
00542       /* Wow! can any object be treated as a pin type for size change?? */
00543       /* pins, vias, lines, and arcs can. Text can't but it has it's own mechanism */
00544       switch (type)
00545         {
00546         case PIN_TYPE:
00547         case VIA_TYPE:
00548           swap = ((PinType *) ptr2)->Thickness;
00549           break;
00550         case LINE_TYPE:
00551         case ELEMENTLINE_TYPE:
00552           swap = ((LineType *) ptr2)->Thickness;
00553           break;
00554         case TEXT_TYPE:
00555         case ELEMENTNAME_TYPE:
00556           iswap = ((TextType *) ptr2)->Scale;
00557           break;
00558         case PAD_TYPE:
00559           swap = ((PadType *) ptr2)->Thickness;
00560           break;
00561         case ARC_TYPE:
00562         case ELEMENTARC_TYPE:
00563           swap = ((ArcType *) ptr2)->Thickness;
00564           break;
00565         }
00566 
00567       RestoreToPolygon (PCB->Data, type, ptr1, ptr2);
00568       if (andDraw)
00569         EraseObject (type, ptr1, ptr2);
00570 
00571       switch (type)
00572         {
00573         case PIN_TYPE:
00574         case VIA_TYPE:
00575           ((PinType *) ptr2)->Thickness = Entry->Data.Size;
00576           Entry->Data.Size = swap;
00577           break;
00578         case LINE_TYPE:
00579         case ELEMENTLINE_TYPE:
00580           ((LineType *) ptr2)->Thickness = Entry->Data.Size;
00581           Entry->Data.Size = swap;
00582           break;
00583         case TEXT_TYPE:
00584         case ELEMENTNAME_TYPE:
00585           ((TextType *) ptr2)->Scale = Entry->Data.Scale;
00586           Entry->Data.Scale = iswap;
00587           break;
00588         case PAD_TYPE:
00589           ((PadType *) ptr2)->Thickness = Entry->Data.Size;
00590           Entry->Data.Size = swap;
00591           break;
00592         case ARC_TYPE:
00593         case ELEMENTARC_TYPE:
00594           ((ArcType *) ptr2)->Thickness = Entry->Data.Size;
00595           Entry->Data.Size = swap;
00596           break;
00597         }
00598 
00599       ClearFromPolygon (PCB->Data, type, ptr1, ptr2);
00600       if (andDraw)
00601         DrawObject (type, ptr1, ptr2);
00602       return (true);
00603     }
00604   return (false);
00605 }
00606 
00610 static bool
00611 UndoFlag (UndoListType *Entry)
00612 {
00613   void *ptr1, *ptr2, *ptr3;
00614   int type;
00615   FlagType swap;
00616   int must_redraw;
00617 
00618   /* lookup entry by ID */
00619   type =
00620     SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
00621   if (type != NO_TYPE)
00622     {
00623       FlagType f1, f2;
00624       PinType *pin = (PinType *) ptr2;
00625 
00626       swap = pin->Flags;
00627 
00628       must_redraw = 0;
00629       f1 = MaskFlags (pin->Flags, ~DRAW_FLAGS);
00630       f2 = MaskFlags (Entry->Data.Flags, ~DRAW_FLAGS);
00631 
00632       if (!FLAGS_EQUAL (f1, f2))
00633         must_redraw = 1;
00634 
00635       if (andDraw && must_redraw)
00636         EraseObject (type, ptr1, ptr2);
00637 
00638       pin->Flags = Entry->Data.Flags;
00639 
00640       Entry->Data.Flags = swap;
00641 
00642       if (andDraw && must_redraw)
00643         DrawObject (type, ptr1, ptr2);
00644       return (true);
00645     }
00646   Message ("hace Internal error: Can't find ID %d type %08x\n", Entry->ID,
00647            Entry->Kind);
00648   Message ("for UndoFlag Operation. Previous flags: %s\n",
00649            flags_to_string (Entry->Data.Flags, 0));
00650   return (false);
00651 }
00652 
00658 static bool
00659 UndoMirror (UndoListType *Entry)
00660 {
00661   void *ptr1, *ptr2, *ptr3;
00662   int type;
00663 
00664   /* lookup entry by ID */
00665   type =
00666     SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
00667   if (type == ELEMENT_TYPE)
00668     {
00669       ElementType *element = (ElementType *) ptr3;
00670       if (andDraw)
00671         EraseElement (element);
00672       MirrorElementCoordinates (PCB->Data, element, Entry->Data.Move.DY);
00673       if (andDraw)
00674         DrawElement (element);
00675       return (true);
00676     }
00677   Message ("hace Internal error: UndoMirror on object type %d\n", type);
00678   return (false);
00679 }
00680 
00686 static bool
00687 UndoCopyOrCreate (UndoListType *Entry)
00688 {
00689   void *ptr1, *ptr2, *ptr3;
00690   int type;
00691 
00692   /* lookup entry by it's ID */
00693   type =
00694     SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
00695   if (type != NO_TYPE)
00696     {
00697       if (!RemoveList)
00698         RemoveList = CreateNewBuffer ();
00699       if (andDraw)
00700         EraseObject (type, ptr1, ptr2);
00701       /* in order to make this re-doable we move it to the RemoveList */
00702       MoveObjectToBuffer (RemoveList, PCB->Data, type, ptr1, ptr2, ptr3);
00703       Entry->Type = UNDO_REMOVE;
00704       return (true);
00705     }
00706   return (false);
00707 }
00708 
00714 static bool
00715 UndoMove (UndoListType *Entry)
00716 {
00717   void *ptr1, *ptr2, *ptr3;
00718   int type;
00719 
00720   /* lookup entry by it's ID */
00721   type =
00722     SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
00723   if (type != NO_TYPE)
00724     {
00725       MoveObject (type, ptr1, ptr2, ptr3,
00726                   -Entry->Data.Move.DX, -Entry->Data.Move.DY);
00727       Entry->Data.Move.DX *= -1;
00728       Entry->Data.Move.DY *= -1;
00729       return (true);
00730     }
00731   return (false);
00732 }
00733 
00739 static bool
00740 UndoRemove (UndoListType *Entry)
00741 {
00742   void *ptr1, *ptr2, *ptr3;
00743   int type;
00744 
00745   /* lookup entry by it's ID */
00746   type =
00747     SearchObjectByID (RemoveList, &ptr1, &ptr2, &ptr3, Entry->ID,
00748                       Entry->Kind);
00749   if (type != NO_TYPE)
00750     {
00751       if (andDraw)
00752         DrawRecoveredObject (type, ptr1, ptr2, ptr3);
00753       MoveObjectToBuffer (PCB->Data, RemoveList, type, ptr1, ptr2, ptr3);
00754       Entry->Type = UNDO_CREATE;
00755       return (true);
00756     }
00757   return (false);
00758 }
00759 
00765 static bool
00766 UndoMoveToLayer (UndoListType *Entry)
00767 {
00768   void *ptr1, *ptr2, *ptr3;
00769   int type, swap;
00770 
00771   /* lookup entry by it's ID */
00772   type =
00773     SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
00774   if (type != NO_TYPE)
00775     {
00776       swap = GetLayerNumber (PCB->Data, (LayerType *) ptr1);
00777       MoveObjectToLayer (type, ptr1, ptr2, ptr3,
00778                          LAYER_PTR (Entry->Data.
00779                                     MoveToLayer.OriginalLayer), true);
00780       Entry->Data.MoveToLayer.OriginalLayer = swap;
00781       return (true);
00782     }
00783   return (false);
00784 }
00785 
00791 static bool
00792 UndoRemovePoint (UndoListType *Entry)
00793 {
00794   LayerType *layer;
00795   PolygonType *polygon;
00796   void *ptr3;
00797   int type;
00798 
00799   /* lookup entry (polygon not point was saved) by it's ID */
00800   assert (Entry->Kind == POLYGON_TYPE);
00801   type =
00802     SearchObjectByID (PCB->Data, (void **) &layer, (void **) &polygon, &ptr3,
00803                       Entry->ID, Entry->Kind);
00804   switch (type)
00805     {
00806     case POLYGON_TYPE:          /* restore the removed point */
00807       {
00808         /* recover the point */
00809         if (andDraw && layer->On)
00810           ErasePolygon (polygon);
00811         InsertPointIntoObject (POLYGON_TYPE, layer, polygon,
00812                                &Entry->Data.RemovedPoint.Index,
00813                                Entry->Data.RemovedPoint.X,
00814                                Entry->Data.RemovedPoint.Y, true,
00815                                Entry->Data.RemovedPoint.last_in_contour);
00816 
00817         polygon->Points[Entry->Data.RemovedPoint.Index].ID =
00818           Entry->Data.RemovedPoint.ID;
00819         if (andDraw && layer->On)
00820           DrawPolygon (layer, polygon);
00821         Entry->Type = UNDO_INSERT_POINT;
00822         Entry->ID = Entry->Data.RemovedPoint.ID;
00823         Entry->Kind = POLYGONPOINT_TYPE;
00824         return (true);
00825       }
00826 
00827     default:
00828       return (false);
00829     }
00830 }
00831 
00837 static bool
00838 UndoInsertPoint (UndoListType *Entry)
00839 {
00840   LayerType *layer;
00841   PolygonType *polygon;
00842   PointType *pnt;
00843   int type;
00844   Cardinal point_idx;
00845   Cardinal hole;
00846   bool last_in_contour = false;
00847 
00848   assert (Entry->Kind == POLYGONPOINT_TYPE);
00849   /* lookup entry by it's ID */
00850   type =
00851     SearchObjectByID (PCB->Data, (void **) &layer, (void **) &polygon,
00852                       (void **) &pnt, Entry->ID, Entry->Kind);
00853   switch (type)
00854     {
00855     case POLYGONPOINT_TYPE:     /* removes an inserted polygon point */
00856       {
00857         if (andDraw && layer->On)
00858           ErasePolygon (polygon);
00859 
00860         /* Check whether this point was at the end of its contour.
00861          * If so, we need to flag as such when re-adding the point
00862          * so it goes back in the correct place
00863          */
00864         point_idx = polygon_point_idx (polygon, pnt);
00865         for (hole = 0; hole < polygon->HoleIndexN; hole++)
00866           if (point_idx == polygon->HoleIndex[hole] - 1)
00867             last_in_contour = true;
00868         if (point_idx == polygon->PointN - 1)
00869           last_in_contour = true;
00870         Entry->Data.RemovedPoint.last_in_contour = last_in_contour;
00871 
00872         Entry->Data.RemovedPoint.X = pnt->X;
00873         Entry->Data.RemovedPoint.Y = pnt->Y;
00874         Entry->Data.RemovedPoint.ID = pnt->ID;
00875         Entry->ID = polygon->ID;
00876         Entry->Kind = POLYGON_TYPE;
00877         Entry->Type = UNDO_REMOVE_POINT;
00878         Entry->Data.RemovedPoint.Index = point_idx;
00879         DestroyObject (PCB->Data, POLYGONPOINT_TYPE, layer, polygon, pnt);
00880         if (andDraw && layer->On)
00881           DrawPolygon (layer, polygon);
00882         return (true);
00883       }
00884 
00885     default:
00886       return (false);
00887     }
00888 }
00889 
00890 static bool
00891 UndoSwapCopiedObject (UndoListType *Entry)
00892 {
00893   void *ptr1, *ptr2, *ptr3;
00894   void *ptr1b, *ptr2b, *ptr3b;
00895   AnyObjectType *obj, *obj2;
00896   int type;
00897   long int swap_id;
00898 
00899   /* lookup entry by it's ID */
00900   type =
00901     SearchObjectByID (RemoveList, &ptr1, &ptr2, &ptr3, Entry->Data.CopyID,
00902                       Entry->Kind);
00903   if (type == NO_TYPE)
00904     return false;
00905 
00906   type =
00907     SearchObjectByID (PCB->Data, &ptr1b, &ptr2b, &ptr3b, Entry->ID,
00908                       Entry->Kind);
00909   if (type == NO_TYPE)
00910     return FALSE;
00911 
00912   obj = (AnyObjectType *)ptr2;
00913   obj2 = (AnyObjectType *)ptr2b;
00914 
00915   swap_id = obj->ID;
00916   obj->ID = obj2->ID;
00917   obj2->ID = swap_id;
00918 
00919   MoveObjectToBuffer (RemoveList, PCB->Data, type, ptr1b, ptr2b, ptr3b);
00920 
00921   if (andDraw)
00922     DrawRecoveredObject (Entry->Kind, ptr1, ptr2, ptr3);
00923 
00924   obj = (AnyObjectType *)MoveObjectToBuffer (PCB->Data, RemoveList, type, ptr1, ptr2, ptr3);
00925   if (Entry->Kind == POLYGON_TYPE)
00926     InitClip (PCB->Data, (LayerType *)ptr1b, (PolygonType *)obj);
00927   return (true);
00928 }
00929 
00935 static bool
00936 UndoRemoveContour (UndoListType *Entry)
00937 {
00938   assert (Entry->Kind == POLYGON_TYPE);
00939   return UndoSwapCopiedObject (Entry);
00940 }
00941 
00947 static bool
00948 UndoInsertContour (UndoListType *Entry)
00949 {
00950   assert (Entry->Kind == POLYGON_TYPE);
00951   return UndoSwapCopiedObject (Entry);
00952 }
00953 
00959 static bool
00960 UndoLayerChange (UndoListType *Entry)
00961 {
00962   LayerChangeType *l = &Entry->Data.LayerChange;
00963   int tmp;
00964 
00965   tmp = l->new_index;
00966   l->new_index = l->old_index;
00967   l->old_index = tmp;
00968 
00969   if (MoveLayer (l->old_index, l->new_index))
00970     return false;
00971   else
00972     return true;
00973 }
00974 
00980 static bool
00981 UndoNetlistChange (UndoListType *Entry)
00982 {
00983   NetlistChangeType *l = & Entry->Data.NetlistChange;
00984   unsigned int i, j;
00985   LibraryType *lib, *saved;
00986 
00987   lib = l->lib;
00988   saved = l->old;
00989 
00990   /* iterate over each net */
00991   for (i = 0 ; i < lib->MenuN; i++)
00992     {
00993       if (lib->Menu[i].Name)
00994         free (lib->Menu[i].Name);
00995 
00996       if (lib->Menu[i].directory)
00997         free (lib->Menu[i].directory);
00998 
00999       if (lib->Menu[i].Style)
01000         free (lib->Menu[i].Style);
01001 
01002       /* iterate over each pin on the net */
01003       for (j = 0; j < lib->Menu[i].EntryN; j++) {
01004         
01005         if (lib->Menu[i].Entry[j].ListEntry)
01006           free (lib->Menu[i].Entry[j].ListEntry);
01007         
01008         if (lib->Menu[i].Entry[j].AllocatedMemory)
01009           free (lib->Menu[i].Entry[j].AllocatedMemory);
01010         
01011         if (lib->Menu[i].Entry[j].Template)
01012           free (lib->Menu[i].Entry[j].Template);
01013         
01014         if (lib->Menu[i].Entry[j].Package)
01015           free (lib->Menu[i].Entry[j].Package);
01016         
01017         if (lib->Menu[i].Entry[j].Value)
01018           free (lib->Menu[i].Entry[j].Value);
01019         
01020         if (lib->Menu[i].Entry[j].Description)
01021           free (lib->Menu[i].Entry[j].Description);
01022         
01023       }
01024     }
01025 
01026   if (lib->Menu)
01027     free (lib->Menu);
01028 
01029   *lib = *saved;
01030 
01031   NetlistChanged (0);
01032   return true;
01033 }
01034 
01035 /* ---------------------------------------------------------------------------
01036  * recovers an object from a Size change operation
01037  */
01038 static bool
01039 UndoSetViaLayers (UndoListType *Entry)
01040 {
01041   void *ptr1, *ptr2, *ptr3;
01042   int type;
01043   int from, to;
01044 
01045   /* lookup entry by ID */
01046   type =
01047     SearchObjectByID (PCB->Data, &ptr1, &ptr2, &ptr3, Entry->ID, Entry->Kind);
01048   if (type == VIA_TYPE)
01049     {
01050       from = ((PinType *) ptr2)->BuriedFrom;
01051       to = ((PinType *) ptr2)->BuriedTo;
01052       RestoreToPolygon (PCB->Data, type, ptr1, ptr2);
01053       if (andDraw)
01054         EraseObject (type, ptr1, ptr2);
01055       ((PinType *) ptr2)->BuriedFrom = Entry->Data.SetViaLayersChange.from;
01056       ((PinType *) ptr2)->BuriedTo = Entry->Data.SetViaLayersChange.to;
01057       Entry->Data.SetViaLayersChange.from = from;
01058       Entry->Data.SetViaLayersChange.to = to;
01059       ClearFromPolygon (PCB->Data, type, ptr1, ptr2);
01060       if (andDraw)
01061         DrawObject (type, ptr1, ptr2);
01062       return (true);
01063     }
01064   return (false);
01065 }
01066 
01067 /* ---------------------------------------------------------------------------
01068  * \brief Undo of any 'hard to recover' operation
01069  *
01070  * \return The bitfield for the types of operations that were undone.
01071  */
01072 int
01073 Undo (bool draw)
01074 {
01075   UndoListType *ptr;
01076   int Types = 0;
01077   int unique;
01078   bool error_undoing = false;
01079 
01080   unique = TEST_FLAG (UNIQUENAMEFLAG, PCB);
01081   CLEAR_FLAG (UNIQUENAMEFLAG, PCB);
01082 
01083   andDraw = draw;
01084 
01085   if (Serial == 0)
01086     {
01087       Message (_("ERROR: Attempt to Undo() with Serial == 0\n"
01088                  "       Please save your work and report this bug.\n"));
01089       return 0;
01090     }
01091 
01092   if (UndoN == 0)
01093     {
01094       Message (_("Nothing to undo - buffer is empty\n"));
01095       return 0;
01096     }
01097 
01098   Serial --;
01099 
01100   ptr = &UndoList[UndoN - 1];
01101 
01102   if (ptr->Serial > Serial)
01103     {
01104       Message (_("ERROR: Bad undo serial number %d in undo stack - expecting %d or lower\n"
01105                  "       Please save your work and report this bug.\n"),
01106                ptr->Serial, Serial);
01107 
01108       /* It is likely that the serial number got corrupted through some bad
01109        * use of the SaveUndoSerialNumber() / RestoreUndoSerialNumber() APIs.
01110        *
01111        * Reset the serial number to be consistent with that of the last
01112        * operation on the undo stack in the hope that this might clear
01113        * the problem and  allow the user to hit Undo again.
01114        */
01115       Serial = ptr->Serial + 1;
01116       return 0;
01117     }
01118 
01119   LockUndo (); /* lock undo module to prevent from loops */
01120 
01121   /* Loop over all entries with the correct serial number */
01122   for (; UndoN && ptr->Serial == Serial; ptr--, UndoN--, RedoN++)
01123     {
01124       int undid = PerformUndo (ptr);
01125       if (undid == 0)
01126         error_undoing = true;
01127       Types |= undid;
01128     }
01129 
01130   UnlockUndo ();
01131 
01132   if (error_undoing)
01133     Message (_("ERROR: Failed to undo some operations\n"));
01134 
01135   if (Types && andDraw)
01136     Draw ();
01137 
01138   /* restore the unique flag setting */
01139   if (unique)
01140     SET_FLAG (UNIQUENAMEFLAG, PCB);
01141 
01142   return Types;
01143 }
01144 
01145 static int
01146 PerformUndo (UndoListType *ptr)
01147 {
01148   switch (ptr->Type)
01149     {
01150     case UNDO_CHANGENAME:
01151       if (UndoChangeName (ptr))
01152         return (UNDO_CHANGENAME);
01153       break;
01154 
01155     case UNDO_CREATE:
01156       if (UndoCopyOrCreate (ptr))
01157         return (UNDO_CREATE);
01158       break;
01159 
01160     case UNDO_MOVE:
01161       if (UndoMove (ptr))
01162         return (UNDO_MOVE);
01163       break;
01164 
01165     case UNDO_REMOVE:
01166       if (UndoRemove (ptr))
01167         return (UNDO_REMOVE);
01168       break;
01169 
01170     case UNDO_REMOVE_POINT:
01171       if (UndoRemovePoint (ptr))
01172         return (UNDO_REMOVE_POINT);
01173       break;
01174 
01175     case UNDO_INSERT_POINT:
01176       if (UndoInsertPoint (ptr))
01177         return (UNDO_INSERT_POINT);
01178       break;
01179 
01180     case UNDO_REMOVE_CONTOUR:
01181       if (UndoRemoveContour (ptr))
01182         return (UNDO_REMOVE_CONTOUR);
01183       break;
01184 
01185     case UNDO_INSERT_CONTOUR:
01186       if (UndoInsertContour (ptr))
01187         return (UNDO_INSERT_CONTOUR);
01188       break;
01189 
01190     case UNDO_ROTATE:
01191       if (UndoRotate (ptr))
01192         return (UNDO_ROTATE);
01193       break;
01194 
01195     case UNDO_CLEAR:
01196       if (UndoClearPoly (ptr))
01197         return (UNDO_CLEAR);
01198       break;
01199 
01200     case UNDO_MOVETOLAYER:
01201       if (UndoMoveToLayer (ptr))
01202         return (UNDO_MOVETOLAYER);
01203       break;
01204 
01205     case UNDO_FLAG:
01206       if (UndoFlag (ptr))
01207         return (UNDO_FLAG);
01208       break;
01209 
01210     case UNDO_CHANGESIZE:
01211       if (UndoChangeSize (ptr))
01212         return (UNDO_CHANGESIZE);
01213       break;
01214 
01215     case UNDO_CHANGECLEARSIZE:
01216       if (UndoChangeClearSize (ptr))
01217         return (UNDO_CHANGECLEARSIZE);
01218       break;
01219 
01220     case UNDO_CHANGEMASKSIZE:
01221       if (UndoChangeMaskSize (ptr))
01222         return (UNDO_CHANGEMASKSIZE);
01223       break;
01224 
01225     case UNDO_CHANGE2NDSIZE:
01226       if (UndoChange2ndSize (ptr))
01227         return (UNDO_CHANGE2NDSIZE);
01228       break;
01229 
01230     case UNDO_CHANGEANGLES:
01231       if (UndoChangeAngles (ptr))
01232         return (UNDO_CHANGEANGLES);
01233       break;
01234 
01235     case UNDO_LAYERCHANGE:
01236       if (UndoLayerChange (ptr))
01237         return (UNDO_LAYERCHANGE);
01238       break;
01239 
01240     case UNDO_NETLISTCHANGE:
01241       if (UndoNetlistChange (ptr))
01242         return (UNDO_NETLISTCHANGE);
01243       break;
01244 
01245     case UNDO_MIRROR:
01246       if (UndoMirror (ptr))
01247         return (UNDO_MIRROR);
01248       break;
01249 
01250     case UNDO_CHANGESETVIALAYERS:
01251       if (UndoSetViaLayers (ptr))
01252         return (UNDO_CHANGESETVIALAYERS);
01253       break;
01254     }
01255   return 0;
01256 }
01257 
01263 int
01264 Redo (bool draw)
01265 {
01266   UndoListType *ptr;
01267   int Types = 0;
01268   bool error_undoing = false;
01269 
01270   andDraw = draw;
01271 
01272   if (RedoN == 0)
01273     {
01274       Message (_("Nothing to redo. Perhaps changes have been made since last undo\n"));
01275       return 0;
01276     }
01277 
01278   ptr = &UndoList[UndoN];
01279 
01280   if (ptr->Serial < Serial)
01281     {
01282       Message (_("ERROR: Bad undo serial number %d in redo stack - expecting %d or higher\n"
01283                  "       Please save your work and report this bug.\n"),
01284                ptr->Serial, Serial);
01285 
01286       /* It is likely that the serial number got corrupted through some bad
01287        * use of the SaveUndoSerialNumber() / RestoreUndoSerialNumber() APIs.
01288        *
01289        * Reset the serial number to be consistent with that of the first
01290        * operation on the redo stack in the hope that this might clear
01291        * the problem and  allow the user to hit Redo again.
01292        */
01293       Serial = ptr->Serial;
01294       return 0;
01295     }
01296 
01297   LockUndo (); /* lock undo module to prevent from loops */
01298 
01299   /* and loop over all entries with the correct serial number */
01300   for (; RedoN && ptr->Serial == Serial; ptr++, UndoN++, RedoN--)
01301     {
01302       int undid = PerformUndo (ptr);
01303       if (undid == 0)
01304         error_undoing = true;
01305       Types |= undid;
01306     }
01307 
01308   /* Make next serial number current */
01309   Serial++;
01310 
01311   UnlockUndo ();
01312 
01313   if (error_undoing)
01314     Message (_("ERROR: Failed to redo some operations\n"));
01315 
01316   if (Types && andDraw)
01317     Draw ();
01318 
01319   return Types;
01320 }
01321 
01325 void
01326 RestoreUndoSerialNumber (void)
01327 {
01328   if (added_undo_between_increment_and_restore)
01329     Message (_("ERROR: Operations were added to the Undo stack with an incorrect serial number\n"));
01330   between_increment_and_restore = false;
01331   added_undo_between_increment_and_restore = false;
01332   Serial = SavedSerial;
01333 }
01334 
01338 void
01339 SaveUndoSerialNumber (void)
01340 {
01341   Bumped = false;
01342   between_increment_and_restore = false;
01343   added_undo_between_increment_and_restore = false;
01344   SavedSerial = Serial;
01345 }
01346 
01353 void
01354 IncrementUndoSerialNumber (void)
01355 {
01356   if (!Locked)
01357     {
01358       /* Set the changed flag if anything was added prior to this bump */
01359       if (UndoN > 0 && UndoList[UndoN - 1].Serial == Serial)
01360         SetChangedFlag (true);
01361       Serial++;
01362       Bumped = true;
01363       between_increment_and_restore = true;
01364     }
01365 }
01366 
01370 void
01371 ClearUndoList (bool Force)
01372 {
01373   UndoListType *undo;
01374 
01375   if (UndoN
01376       && (Force || gui->confirm_dialog ("OK to clear 'undo' buffer?", 0)))
01377     {
01378       /* release memory allocated by objects in undo list */
01379       for (undo = UndoList; UndoN; undo++, UndoN--)
01380         {
01381           if (undo->Type == UNDO_CHANGENAME)
01382             free (undo->Data.ChangeName.Name);
01383         }
01384       free (UndoList);
01385       UndoList = NULL;
01386       if (RemoveList)
01387         {
01388           FreeDataMemory (RemoveList);
01389           free (RemoveList);
01390           RemoveList = NULL;
01391         }
01392 
01393       /* reset some counters */
01394       UndoN = UndoMax = RedoN = 0;
01395     }
01396 
01397   /* reset counter in any case */
01398   Serial = 1;
01399 }
01400 
01404 void
01405 AddObjectToClearPolyUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
01406                               bool clear)
01407 {
01408   UndoListType *undo;
01409 
01410   if (!Locked)
01411     {
01412       undo = GetUndoSlot (UNDO_CLEAR, OBJECT_ID (Ptr3), Type);
01413       undo->Data.ClearPoly.Clear = clear;
01414       undo->Data.ClearPoly.Layer = (LayerType *) Ptr1;
01415     }
01416 }
01417 
01421 void
01422 AddObjectToMirrorUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
01423                            Coord yoff)
01424 {
01425   UndoListType *undo;
01426 
01427   if (!Locked)
01428     {
01429       undo = GetUndoSlot (UNDO_MIRROR, OBJECT_ID (Ptr3), Type);
01430       undo->Data.Move.DY = yoff;
01431     }
01432 }
01433 
01437 void
01438 AddObjectToRotateUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
01439                            Coord CenterX, Coord CenterY,
01440                            BYTE Steps)
01441 {
01442   UndoListType *undo;
01443 
01444   if (!Locked)
01445     {
01446       undo = GetUndoSlot (UNDO_ROTATE, OBJECT_ID (Ptr3), Type);
01447       undo->Data.Rotate.CenterX = CenterX;
01448       undo->Data.Rotate.CenterY = CenterY;
01449       undo->Data.Rotate.Steps = Steps;
01450     }
01451 }
01452 
01457 void
01458 MoveObjectToRemoveUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
01459 {
01460   if (Locked)
01461     return;
01462 
01463   if (!RemoveList)
01464     RemoveList = CreateNewBuffer ();
01465 
01466   GetUndoSlot (UNDO_REMOVE, OBJECT_ID (Ptr3), Type);
01467   MoveObjectToBuffer (RemoveList, PCB->Data, Type, Ptr1, Ptr2, Ptr3);
01468 }
01469 
01473 void
01474 AddObjectToRemovePointUndoList (int Type,
01475                                 void *Ptr1, void *Ptr2, Cardinal index)
01476 {
01477   UndoListType *undo;
01478   PolygonType *polygon = (PolygonType *) Ptr2;
01479   Cardinal hole;
01480   bool last_in_contour = false;
01481 
01482   if (!Locked)
01483     {
01484       switch (Type)
01485         {
01486         case POLYGONPOINT_TYPE:
01487           {
01488             /* save the ID of the parent object; else it will be
01489              * impossible to recover the point
01490              */
01491             undo =
01492               GetUndoSlot (UNDO_REMOVE_POINT, OBJECT_ID (polygon),
01493                            POLYGON_TYPE);
01494             undo->Data.RemovedPoint.X = polygon->Points[index].X;
01495             undo->Data.RemovedPoint.Y = polygon->Points[index].Y;
01496             undo->Data.RemovedPoint.ID = polygon->Points[index].ID;
01497             undo->Data.RemovedPoint.Index = index;
01498 
01499             /* Check whether this point was at the end of its contour.
01500              * If so, we need to flag as such when re-adding the point
01501              * so it goes back in the correct place
01502              */
01503             for (hole = 0; hole < polygon->HoleIndexN; hole++)
01504               if (index == polygon->HoleIndex[hole] - 1)
01505                 last_in_contour = true;
01506             if (index == polygon->PointN - 1)
01507               last_in_contour = true;
01508             undo->Data.RemovedPoint.last_in_contour = last_in_contour;
01509           }
01510           break;
01511         }
01512     }
01513 }
01514 
01518 void
01519 AddObjectToInsertPointUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
01520 {
01521   if (!Locked)
01522     GetUndoSlot (UNDO_INSERT_POINT, OBJECT_ID (Ptr3), Type);
01523 }
01524 
01525 static void
01526 CopyObjectToUndoList (int undo_type, int Type, void *Ptr1, void *Ptr2, void *Ptr3)
01527 {
01528   UndoListType *undo;
01529   AnyObjectType *copy;
01530 
01531   if (Locked)
01532     return;
01533 
01534   if (!RemoveList)
01535     RemoveList = CreateNewBuffer ();
01536 
01537   undo = GetUndoSlot (undo_type, OBJECT_ID (Ptr2), Type);
01538   copy = (AnyObjectType *)CopyObjectToBuffer (RemoveList, PCB->Data, Type, Ptr1, Ptr2, Ptr3);
01539   undo->Data.CopyID = copy->ID;
01540 }
01541 
01547 void
01548 AddObjectToRemoveContourUndoList (int Type,
01549                                   LayerType *Layer, PolygonType *Polygon)
01550 {
01551   CopyObjectToUndoList (UNDO_REMOVE_CONTOUR, Type, Layer, Polygon, NULL);
01552 }
01553 
01559 void
01560 AddObjectToInsertContourUndoList (int Type,
01561                                   LayerType *Layer, PolygonType *Polygon)
01562 {
01563   CopyObjectToUndoList (UNDO_INSERT_CONTOUR, Type, Layer, Polygon, NULL);
01564 }
01565 
01569 void
01570 AddObjectToMoveUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
01571                          Coord DX, Coord DY)
01572 {
01573   UndoListType *undo;
01574 
01575   if (!Locked)
01576     {
01577       undo = GetUndoSlot (UNDO_MOVE, OBJECT_ID (Ptr3), Type);
01578       undo->Data.Move.DX = DX;
01579       undo->Data.Move.DY = DY;
01580     }
01581 }
01582 
01586 void
01587 AddObjectToChangeNameUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
01588                                char *OldName)
01589 {
01590   UndoListType *undo;
01591 
01592   if (!Locked)
01593     {
01594       undo = GetUndoSlot (UNDO_CHANGENAME, OBJECT_ID (Ptr3), Type);
01595       undo->Data.ChangeName.Name = OldName;
01596     }
01597 }
01598 
01602 void
01603 AddObjectToMoveToLayerUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
01604 {
01605   UndoListType *undo;
01606 
01607   if (!Locked)
01608     {
01609       undo = GetUndoSlot (UNDO_MOVETOLAYER, OBJECT_ID (Ptr3), Type);
01610       undo->Data.MoveToLayer.OriginalLayer =
01611         GetLayerNumber (PCB->Data, (LayerType *) Ptr1);
01612     }
01613 }
01614 
01618 void
01619 AddObjectToCreateUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
01620 {
01621   if (!Locked)
01622     GetUndoSlot (UNDO_CREATE, OBJECT_ID (Ptr3), Type);
01623   ClearFromPolygon (PCB->Data, Type, Ptr1, Ptr2);
01624 }
01625 
01629 void
01630 AddObjectToFlagUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
01631 {
01632   UndoListType *undo;
01633 
01634   if (!Locked)
01635     {
01636       undo = GetUndoSlot (UNDO_FLAG, OBJECT_ID (Ptr2), Type);
01637       undo->Data.Flags = ((PinType *) Ptr2)->Flags;
01638     }
01639 }
01640 
01644 void
01645 AddObjectToSizeUndoList (int Type, void *ptr1, void *ptr2, void *ptr3)
01646 {
01647   UndoListType *undo;
01648 
01649   if (!Locked)
01650     {
01651       undo = GetUndoSlot (UNDO_CHANGESIZE, OBJECT_ID (ptr2), Type);
01652       switch (Type)
01653         {
01654         case PIN_TYPE:
01655         case VIA_TYPE:
01656           undo->Data.Size = ((PinType *) ptr2)->Thickness;
01657           break;
01658         case LINE_TYPE:
01659         case ELEMENTLINE_TYPE:
01660           undo->Data.Size = ((LineType *) ptr2)->Thickness;
01661           break;
01662         case TEXT_TYPE:
01663         case ELEMENTNAME_TYPE:
01664           undo->Data.Scale = ((TextType *) ptr2)->Scale;
01665           break;
01666         case PAD_TYPE:
01667           undo->Data.Size = ((PadType *) ptr2)->Thickness;
01668           break;
01669         case ARC_TYPE:
01670         case ELEMENTARC_TYPE:
01671           undo->Data.Size = ((ArcType *) ptr2)->Thickness;
01672           break;
01673         }
01674     }
01675 }
01676 
01680 void
01681 AddObjectToClearSizeUndoList (int Type, void *ptr1, void *ptr2, void *ptr3)
01682 {
01683   UndoListType *undo;
01684 
01685   if (!Locked)
01686     {
01687       undo = GetUndoSlot (UNDO_CHANGECLEARSIZE, OBJECT_ID (ptr2), Type);
01688       switch (Type)
01689         {
01690         case PIN_TYPE:
01691         case VIA_TYPE:
01692           undo->Data.Size = ((PinType *) ptr2)->Clearance;
01693           break;
01694         case LINE_TYPE:
01695           undo->Data.Size = ((LineType *) ptr2)->Clearance;
01696           break;
01697         case PAD_TYPE:
01698           undo->Data.Size = ((PadType *) ptr2)->Clearance;
01699           break;
01700         case ARC_TYPE:
01701           undo->Data.Size = ((ArcType *) ptr2)->Clearance;
01702           break;
01703         }
01704     }
01705 }
01706 
01710 void
01711 AddObjectToMaskSizeUndoList (int Type, void *ptr1, void *ptr2, void *ptr3)
01712 {
01713   UndoListType *undo;
01714 
01715   if (!Locked)
01716     {
01717       undo = GetUndoSlot (UNDO_CHANGEMASKSIZE, OBJECT_ID (ptr2), Type);
01718       switch (Type)
01719         {
01720         case PIN_TYPE:
01721         case VIA_TYPE:
01722           undo->Data.Size = ((PinType *) ptr2)->Mask;
01723           break;
01724         case PAD_TYPE:
01725           undo->Data.Size = ((PadType *) ptr2)->Mask;
01726           break;
01727         }
01728     }
01729 }
01730 
01734 void
01735 AddObjectTo2ndSizeUndoList (int Type, void *ptr1, void *ptr2, void *ptr3)
01736 {
01737   UndoListType *undo;
01738 
01739   if (!Locked)
01740     {
01741       undo = GetUndoSlot (UNDO_CHANGE2NDSIZE, OBJECT_ID (ptr2), Type);
01742       if (Type == PIN_TYPE || Type == VIA_TYPE)
01743         undo->Data.Size = ((PinType *) ptr2)->DrillingHole;
01744     }
01745 }
01746 
01753 void
01754 AddObjectToChangeAnglesUndoList (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
01755 {
01756   UndoListType *undo;
01757   ArcType *a = (ArcType *) Ptr3;
01758 
01759   if (!Locked)
01760     {
01761       undo = GetUndoSlot (UNDO_CHANGEANGLES, OBJECT_ID (Ptr3), Type);
01762       undo->Data.Move.DX = a->StartAngle;
01763       undo->Data.Move.DY = a->Delta;
01764     }
01765 }
01766 
01770 void
01771 AddLayerChangeToUndoList (int old_index, int new_index)
01772 {
01773   UndoListType *undo;
01774 
01775   if (!Locked)
01776     {
01777       undo = GetUndoSlot (UNDO_LAYERCHANGE, 0, 0);
01778       undo->Data.LayerChange.old_index = old_index;
01779       undo->Data.LayerChange.new_index = new_index;
01780     }
01781 }
01782 
01786 void
01787 AddNetlistLibToUndoList (LibraryType *lib)
01788 {
01789   UndoListType *undo;
01790   unsigned int i, j;
01791   LibraryType *old;
01792   
01793   if (!Locked)
01794     {
01795       undo = GetUndoSlot (UNDO_NETLISTCHANGE, 0, 0);
01796       /* keep track of where the data needs to go */
01797       undo->Data.NetlistChange.lib = lib;
01798 
01799       /* and what the old data is that we'll need to restore */
01800       undo->Data.NetlistChange.old = (LibraryType *)malloc (sizeof (LibraryType));
01801       old = undo->Data.NetlistChange.old;
01802       old->MenuN = lib->MenuN;
01803       old->MenuMax = lib->MenuMax;
01804       old->Menu = (LibraryMenuType *)malloc (old->MenuMax * sizeof (LibraryMenuType));
01805       if (old->Menu == NULL)
01806         {
01807           fprintf (stderr, "malloc() failed in %s\n", __FUNCTION__);
01808           exit (1);
01809         }
01810 
01811       /* iterate over each net */
01812       for (i = 0 ; i < lib->MenuN; i++)
01813         {
01814           old->Menu[i].EntryN = lib->Menu[i].EntryN;
01815           old->Menu[i].EntryMax = lib->Menu[i].EntryMax;
01816 
01817           old->Menu[i].Name = 
01818             lib->Menu[i].Name ? strdup (lib->Menu[i].Name) : NULL;
01819           
01820           old->Menu[i].directory = 
01821             lib->Menu[i].directory ? strdup (lib->Menu[i].directory) : NULL;
01822           
01823           old->Menu[i].Style = 
01824             lib->Menu[i].Style ? strdup (lib->Menu[i].Style) : NULL;
01825 
01826       
01827           old->Menu[i].Entry = 
01828             (LibraryEntryType *)malloc (old->Menu[i].EntryMax * sizeof (LibraryEntryType));
01829           if (old->Menu[i].Entry == NULL)
01830             {
01831               fprintf (stderr, "malloc() failed in %s\n", __FUNCTION__);
01832               exit (1);
01833             }
01834           
01835           /* iterate over each pin on the net */
01836           for (j = 0; j < lib->Menu[i].EntryN; j++) {
01837 
01838             old->Menu[i].Entry[j].ListEntry = 
01839               lib->Menu[i].Entry[j].ListEntry ? 
01840               strdup (lib->Menu[i].Entry[j].ListEntry) :
01841               NULL;
01842 
01843             old->Menu[i].Entry[j].AllocatedMemory = 
01844               lib->Menu[i].Entry[j].AllocatedMemory ? 
01845               strdup (lib->Menu[i].Entry[j].AllocatedMemory) :
01846               NULL;
01847 
01848             old->Menu[i].Entry[j].Template = 
01849               lib->Menu[i].Entry[j].Template ? 
01850               strdup (lib->Menu[i].Entry[j].Template) :
01851               NULL;
01852 
01853             old->Menu[i].Entry[j].Package = 
01854               lib->Menu[i].Entry[j].Package ? 
01855               strdup (lib->Menu[i].Entry[j].Package) :
01856               NULL;
01857 
01858             old->Menu[i].Entry[j].Value = 
01859               lib->Menu[i].Entry[j].Value ? 
01860               strdup (lib->Menu[i].Entry[j].Value) :
01861               NULL;
01862 
01863             old->Menu[i].Entry[j].Description = 
01864               lib->Menu[i].Entry[j].Description ? 
01865               strdup (lib->Menu[i].Entry[j].Description) :
01866               NULL;
01867             
01868 
01869           }
01870         }
01871 
01872     }
01873 }
01874 
01875 /* ---------------------------------------------------------------------------
01876  * adds an object to the list of objects with buried info data
01877  */
01878 void
01879 AddObjectToSetViaLayersUndoList (void *ptr1, void *ptr2, void *ptr3)
01880 {
01881   UndoListType *undo;
01882 
01883   if (!Locked)
01884     {
01885       undo = GetUndoSlot (UNDO_CHANGESETVIALAYERS, OBJECT_ID (ptr2), VIA_TYPE);
01886       undo->Data.SetViaLayersChange.from = ((PinType *) ptr2)->BuriedFrom;
01887       undo->Data.SetViaLayersChange.to = ((PinType *) ptr2)->BuriedTo;
01888     }
01889 }
01890 
01891 
01892 /* ---------------------------------------------------------------------------
01893  * \brief Set lock flag
01894  */
01895 void
01896 LockUndo (void)
01897 {
01898   Locked = true;
01899 }
01900 
01904 void
01905 UnlockUndo (void)
01906 {
01907   Locked = false;
01908 }
01909 
01913 bool
01914 Undoing (void)
01915 {
01916   return (Locked);
01917 }