pcb 4.1.1
An interactive printed circuit board layout editor.

move.c

Go to the documentation of this file.
00001 
00035 #ifdef HAVE_CONFIG_H
00036 #include "config.h"
00037 #endif
00038 
00039 #include <setjmp.h>
00040 #include <stdlib.h>
00041 
00042 #include "global.h"
00043 
00044 #include "create.h"
00045 #include "crosshair.h"
00046 #include "data.h"
00047 #include "draw.h"
00048 #include "error.h"
00049 #include "misc.h"
00050 #include "move.h"
00051 #include "mymem.h"
00052 #include "polygon.h"
00053 #include "rtree.h"
00054 #include "search.h"
00055 #include "select.h"
00056 #include "thermal.h"
00057 #include "undo.h"
00058 
00059 #ifdef HAVE_LIBDMALLOC
00060 #include <dmalloc.h>
00061 #endif
00062 
00063 /* ---------------------------------------------------------------------------
00064  * some local prototypes
00065  */
00066 static void *MoveElementName (ElementType *);
00067 static void *MoveElement (ElementType *);
00068 static void *MoveVia (PinType *);
00069 static void *MoveLine (LayerType *, LineType *);
00070 static void *MoveArc (LayerType *, ArcType *);
00071 static void *MoveText (LayerType *, TextType *);
00072 static void *MovePolygon (LayerType *, PolygonType *);
00073 static void *MoveLinePoint (LayerType *, LineType *, PointType *);
00074 static void *MovePolygonPoint (LayerType *, PolygonType *, PointType *);
00075 static void *MoveLineToLayer (LayerType *, LineType *);
00076 static void *MoveArcToLayer (LayerType *, ArcType *);
00077 static void *MoveRatToLayer (RatType *);
00078 static void *MoveTextToLayer (LayerType *, TextType *);
00079 static void *MovePolygonToLayer (LayerType *, PolygonType *);
00080 
00081 /* ---------------------------------------------------------------------------
00082  * some local identifiers
00083  */
00084 static Coord DeltaX, DeltaY;    /* used by local routines as offset */
00085 static LayerType *Dest;
00086 static bool MoreToCome;
00087 static ObjectFunctionType MoveFunctions = {
00088   MoveLine,
00089   MoveText,
00090   MovePolygon,
00091   MoveVia,
00092   MoveElement,
00093   MoveElementName,
00094   NULL,
00095   NULL,
00096   MoveLinePoint,
00097   MovePolygonPoint,
00098   MoveArc,
00099   NULL
00100 }, MoveToLayerFunctions =
00101 
00102 {
00103 MoveLineToLayer,
00104     MoveTextToLayer,
00105     MovePolygonToLayer,
00106     NULL, NULL, NULL, NULL, NULL, NULL, NULL, MoveArcToLayer, MoveRatToLayer};
00107 
00111 void
00112 MoveElementLowLevel (DataType *Data, ElementType *Element,
00113                      Coord DX, Coord DY)
00114 {
00115   if (Data)
00116     r_delete_entry (Data->element_tree, (BoxType *)Element);
00117   ELEMENTLINE_LOOP (Element);
00118   {
00119     MOVE_LINE_LOWLEVEL (line, DX, DY);
00120   }
00121   END_LOOP;
00122   PIN_LOOP (Element);
00123   {
00124     if (Data)
00125       {
00126         r_delete_entry (Data->pin_tree, (BoxType *)pin);
00127         RestoreToPolygon (Data, PIN_TYPE, Element, pin);
00128       }
00129     MOVE_PIN_LOWLEVEL (pin, DX, DY);
00130     if (Data)
00131       {
00132         r_insert_entry (Data->pin_tree, (BoxType *)pin, 0);
00133         ClearFromPolygon (Data, PIN_TYPE, Element, pin);
00134       }
00135   }
00136   END_LOOP;
00137   PAD_LOOP (Element);
00138   {
00139     if (Data)
00140       {
00141         r_delete_entry (Data->pad_tree, (BoxType *)pad);
00142         RestoreToPolygon (Data, PAD_TYPE, Element, pad);
00143       }
00144     MOVE_PAD_LOWLEVEL (pad, DX, DY);
00145     if (Data)
00146       {
00147         r_insert_entry (Data->pad_tree, (BoxType *)pad, 0);
00148         ClearFromPolygon (Data, PAD_TYPE, Element, pad);
00149       }
00150   }
00151   END_LOOP;
00152   ARC_LOOP (Element);
00153   {
00154     MOVE_ARC_LOWLEVEL (arc, DX, DY);
00155   }
00156   END_LOOP;
00157   ELEMENTTEXT_LOOP (Element);
00158   {
00159     if (Data && Data->name_tree[n])
00160       r_delete_entry (PCB->Data->name_tree[n], (BoxType *)text);
00161     MOVE_TEXT_LOWLEVEL (text, DX, DY);
00162     if (Data && Data->name_tree[n])
00163       r_insert_entry (PCB->Data->name_tree[n], (BoxType *)text, 0);
00164   }
00165   END_LOOP;
00166   MOVE_BOX_LOWLEVEL (&Element->BoundingBox, DX, DY);
00167   MOVE_BOX_LOWLEVEL (&Element->VBox, DX, DY);
00168   MOVE (Element->MarkX, Element->MarkY, DX, DY);
00169   if (Data)
00170     r_insert_entry (Data->element_tree, (BoxType *)Element, 0);
00171 }
00172 
00176 static void *
00177 MoveElementName (ElementType *Element)
00178 {
00179   if (PCB->ElementOn && (FRONT (Element) || PCB->InvisibleObjectsOn))
00180     {
00181       EraseElementName (Element);
00182       ELEMENTTEXT_LOOP (Element);
00183       {
00184         if (PCB->Data->name_tree[n])
00185           r_delete_entry (PCB->Data->name_tree[n], (BoxType *)text);
00186         MOVE_TEXT_LOWLEVEL (text, DeltaX, DeltaY);
00187         if (PCB->Data->name_tree[n])
00188           r_insert_entry (PCB->Data->name_tree[n], (BoxType *)text, 0);
00189       }
00190       END_LOOP;
00191       DrawElementName (Element);
00192       Draw ();
00193     }
00194   else
00195     {
00196       ELEMENTTEXT_LOOP (Element);
00197       {
00198         if (PCB->Data->name_tree[n])
00199           r_delete_entry (PCB->Data->name_tree[n], (BoxType *)text);
00200         MOVE_TEXT_LOWLEVEL (text, DeltaX, DeltaY);
00201         if (PCB->Data->name_tree[n])
00202           r_insert_entry (PCB->Data->name_tree[n], (BoxType *)text, 0);
00203       }
00204       END_LOOP;
00205     }
00206   return (Element);
00207 }
00208 
00212 static void *
00213 MoveElement (ElementType *Element)
00214 {
00215   bool didDraw = false;
00216 
00217   if (PCB->ElementOn && (FRONT (Element) || PCB->InvisibleObjectsOn))
00218     {
00219       EraseElement (Element);
00220       MoveElementLowLevel (PCB->Data, Element, DeltaX, DeltaY);
00221       DrawElementName (Element);
00222       DrawElementPackage (Element);
00223       didDraw = true;
00224     }
00225   else
00226     {
00227       if (PCB->PinOn)
00228         EraseElementPinsAndPads (Element);
00229       MoveElementLowLevel (PCB->Data, Element, DeltaX, DeltaY);
00230     }
00231   if (PCB->PinOn)
00232     {
00233       DrawElementPinsAndPads (Element);
00234       didDraw = true;
00235     }
00236   if (didDraw)
00237     Draw ();
00238   return (Element);
00239 }
00240 
00244 static void *
00245 MoveVia (PinType *Via)
00246 {
00247   r_delete_entry (PCB->Data->via_tree, (BoxType *)Via);
00248   RestoreToPolygon (PCB->Data, VIA_TYPE, Via, Via);
00249   MOVE_VIA_LOWLEVEL (Via, DeltaX, DeltaY);
00250   if (PCB->ViaOn)
00251     EraseVia (Via);
00252   r_insert_entry (PCB->Data->via_tree, (BoxType *)Via, 0);
00253   ClearFromPolygon (PCB->Data, VIA_TYPE, Via, Via);
00254   if (PCB->ViaOn)
00255     {
00256       DrawVia (Via);
00257       Draw ();
00258     }
00259   return (Via);
00260 }
00261 
00265 static void *
00266 MoveLine (LayerType *Layer, LineType *Line)
00267 {
00268   if (Layer->On)
00269     EraseLine (Line);
00270   RestoreToPolygon (PCB->Data, LINE_TYPE, Layer, Line);
00271   r_delete_entry (Layer->line_tree, (BoxType *)Line);
00272   MOVE_LINE_LOWLEVEL (Line, DeltaX, DeltaY);
00273   r_insert_entry (Layer->line_tree, (BoxType *)Line, 0);
00274   ClearFromPolygon (PCB->Data, LINE_TYPE, Layer, Line);
00275   if (Layer->On)
00276     {
00277       DrawLine (Layer, Line);
00278       Draw ();
00279     }
00280   return (Line);
00281 }
00282 
00286 static void *
00287 MoveArc (LayerType *Layer, ArcType *Arc)
00288 {
00289   RestoreToPolygon (PCB->Data, ARC_TYPE, Layer, Arc);
00290   r_delete_entry (Layer->arc_tree, (BoxType *)Arc);
00291   if (Layer->On)
00292     {
00293       EraseArc (Arc);
00294       MOVE_ARC_LOWLEVEL (Arc, DeltaX, DeltaY);
00295       DrawArc (Layer, Arc);
00296       Draw ();
00297     }
00298   else
00299     {
00300       MOVE_ARC_LOWLEVEL (Arc, DeltaX, DeltaY);
00301     }
00302   r_insert_entry (Layer->arc_tree, (BoxType *)Arc, 0);
00303   ClearFromPolygon (PCB->Data, ARC_TYPE, Layer, Arc);
00304   return (Arc);
00305 }
00306 
00310 static void *
00311 MoveText (LayerType *Layer, TextType *Text)
00312 {
00313   RestoreToPolygon (PCB->Data, TEXT_TYPE, Layer, Text);
00314   r_delete_entry (Layer->text_tree, (BoxType *)Text);
00315   if (Layer->On)
00316     {
00317       EraseText (Layer, Text);
00318       MOVE_TEXT_LOWLEVEL (Text, DeltaX, DeltaY);
00319       DrawText (Layer, Text);
00320       Draw ();
00321     }
00322   else
00323     MOVE_TEXT_LOWLEVEL (Text, DeltaX, DeltaY);
00324   r_insert_entry (Layer->text_tree, (BoxType *)Text, 0);
00325   ClearFromPolygon (PCB->Data, TEXT_TYPE, Layer, Text);
00326   return (Text);
00327 }
00328 
00332 void
00333 MovePolygonLowLevel (PolygonType *Polygon, Coord DeltaX, Coord DeltaY)
00334 {
00335   POLYGONPOINT_LOOP (Polygon);
00336   {
00337     MOVE (point->X, point->Y, DeltaX, DeltaY);
00338   }
00339   END_LOOP;
00340   MOVE_BOX_LOWLEVEL (&Polygon->BoundingBox, DeltaX, DeltaY);
00341 }
00342 
00346 static void *
00347 MovePolygon (LayerType *Layer, PolygonType *Polygon)
00348 {
00349   if (Layer->On)
00350     {
00351       ErasePolygon (Polygon);
00352     }
00353   r_delete_entry (Layer->polygon_tree, (BoxType *)Polygon);
00354   MovePolygonLowLevel (Polygon, DeltaX, DeltaY);
00355   r_insert_entry (Layer->polygon_tree, (BoxType *)Polygon, 0);
00356   InitClip (PCB->Data, Layer, Polygon);
00357   if (Layer->On)
00358     {
00359       DrawPolygon (Layer, Polygon);
00360       Draw ();
00361     }
00362   return (Polygon);
00363 }
00364 
00368 static void *
00369 MoveLinePoint (LayerType *Layer, LineType *Line, PointType *Point)
00370 {
00371   if (Layer)
00372     {
00373       if (Layer->On)
00374         EraseLine (Line);
00375       RestoreToPolygon (PCB->Data, LINE_TYPE, Layer, Line);
00376       r_delete_entry (Layer->line_tree, &Line->BoundingBox);
00377       MOVE (Point->X, Point->Y, DeltaX, DeltaY);
00378       SetLineBoundingBox (Line);
00379       r_insert_entry (Layer->line_tree, &Line->BoundingBox, 0);
00380       ClearFromPolygon (PCB->Data, LINE_TYPE, Layer, Line);
00381       if (Layer->On)
00382         {
00383           DrawLine (Layer, Line);
00384           Draw ();
00385         }
00386       return (Line);
00387     }
00388   else                          /* must be a rat */
00389     {
00390       if (PCB->RatOn)
00391         EraseRat ((RatType *) Line);
00392       r_delete_entry (PCB->Data->rat_tree, &Line->BoundingBox);
00393       MOVE (Point->X, Point->Y, DeltaX, DeltaY);
00394       SetLineBoundingBox (Line);
00395       r_insert_entry (PCB->Data->rat_tree, &Line->BoundingBox, 0);
00396       if (PCB->RatOn)
00397         {
00398           DrawRat ((RatType *) Line);
00399           Draw ();
00400         }
00401       return (Line);
00402     }
00403 }
00404 
00408 static void *
00409 MovePolygonPoint (LayerType *Layer, PolygonType *Polygon,
00410                   PointType *Point)
00411 {
00412   if (Layer->On)
00413     {
00414       ErasePolygon (Polygon);
00415     }
00416   r_delete_entry (Layer->polygon_tree, (BoxType *)Polygon);
00417   MOVE (Point->X, Point->Y, DeltaX, DeltaY);
00418   SetPolygonBoundingBox (Polygon);
00419   r_insert_entry (Layer->polygon_tree, (BoxType *)Polygon, 0);
00420   RemoveExcessPolygonPoints (Layer, Polygon);
00421   InitClip (PCB->Data, Layer, Polygon);
00422   if (Layer->On)
00423     {
00424       DrawPolygon (Layer, Polygon);
00425       Draw ();
00426     }
00427   return (Point);
00428 }
00429 
00433 static void *
00434 MoveLineToLayerLowLevel (LayerType *Source, LineType *line,
00435                          LayerType *Destination)
00436 {
00437   r_delete_entry (Source->line_tree, (BoxType *)line);
00438 
00439   Source->Line = g_list_remove (Source->Line, line);
00440   Source->LineN --;
00441   Destination->Line = g_list_append (Destination->Line, line);
00442   Destination->LineN ++;
00443 
00444   if (!Destination->line_tree)
00445     Destination->line_tree = r_create_tree (NULL, 0, 0);
00446   r_insert_entry (Destination->line_tree, (BoxType *)line, 0);
00447   return line;
00448 }
00449 
00453 static void *
00454 MoveArcToLayerLowLevel (LayerType *Source, ArcType *arc,
00455                         LayerType *Destination)
00456 {
00457   r_delete_entry (Source->arc_tree, (BoxType *)arc);
00458 
00459   Source->Arc = g_list_remove (Source->Arc, arc);
00460   Source->ArcN --;
00461   Destination->Arc = g_list_append (Destination->Arc, arc);
00462   Destination->ArcN ++;
00463 
00464   if (!Destination->arc_tree)
00465     Destination->arc_tree = r_create_tree (NULL, 0, 0);
00466   r_insert_entry (Destination->arc_tree, (BoxType *)arc, 0);
00467   return arc;
00468 }
00469 
00470 
00474 static void *
00475 MoveArcToLayer (LayerType *Layer, ArcType *Arc)
00476 {
00477   ArcType *newone;
00478 
00479   if (TEST_FLAG (LOCKFLAG, Arc))
00480     {
00481       Message (_("Sorry, the object is locked\n"));
00482       return NULL;
00483     }
00484   if (Dest == Layer && Layer->On)
00485     {
00486       DrawArc (Layer, Arc);
00487       Draw ();
00488     }
00489   if (((long int) Dest == -1) || Dest == Layer)
00490     return (Arc);
00491   AddObjectToMoveToLayerUndoList (ARC_TYPE, Layer, Arc, Arc);
00492   RestoreToPolygon (PCB->Data, ARC_TYPE, Layer, Arc);
00493   if (Layer->On)
00494     EraseArc (Arc);
00495   newone = (ArcType *)MoveArcToLayerLowLevel (Layer, Arc, Dest);
00496   ClearFromPolygon (PCB->Data, ARC_TYPE, Dest, Arc);
00497   if (Dest->On)
00498     DrawArc (Dest, newone);
00499   Draw ();
00500   return (newone);
00501 }
00502 
00506 static void *
00507 MoveRatToLayer (RatType *Rat)
00508 {
00509   LineType *newone;
00510   //Coord X1 = Rat->Point1.X, Y1 = Rat->Point1.Y;
00511   //Coord X1 = Rat->Point1.X, Y1 = Rat->Point1.Y;
00512   // if VIAFLAG
00513   //   if we're on a pin, add a thermal
00514   //   else make a via and a wire, but 0-length wire not good
00515   // else as before
00516 
00517   newone = CreateNewLineOnLayer (Dest, Rat->Point1.X, Rat->Point1.Y,
00518                               Rat->Point2.X, Rat->Point2.Y,
00519                               Settings.LineThickness, 2 * Settings.Keepaway,
00520                               Rat->Flags);
00521   if (TEST_FLAG (CLEARNEWFLAG, PCB))
00522     SET_FLAG (CLEARLINEFLAG, newone);
00523   if (!newone)
00524     return (NULL);
00525   AddObjectToCreateUndoList (LINE_TYPE, Dest, newone, newone);
00526   if (PCB->RatOn)
00527     EraseRat (Rat);
00528   MoveObjectToRemoveUndoList (RATLINE_TYPE, Rat, Rat, Rat);
00529   DrawLine (Dest, newone);
00530   Draw ();
00531   return (newone);
00532 }
00533 
00538 struct via_info
00539 {
00540   Coord X, Y;
00541   Cardinal layer_from, layer_to;
00542   jmp_buf env;
00543 };
00544 
00545 static int
00546 moveline_callback (const BoxType * b, void *cl)
00547 {
00548   struct via_info *i = (struct via_info *) cl;
00549   PinType *via;
00550 
00551   if ((via =
00552        CreateNewViaEx (PCB->Data, i->X, i->Y,
00553                      Settings.ViaThickness, 2 * Settings.Keepaway,
00554                      NOFLAG, Settings.ViaDrillingHole, NULL,
00555                      NoFlags (), i->layer_from, i->layer_to)) != NULL)
00556     {
00557       AddObjectToCreateUndoList (VIA_TYPE, via, via, via);
00558       DrawVia (via);
00559     }
00560   longjmp (i->env, 1);
00561 }
00562 
00563 static void *
00564 MoveLineToLayer (LayerType *Layer, LineType *Line)
00565 {
00566   struct via_info info;
00567   BoxType sb;
00568   LineType *newone;
00569   void *ptr1, *ptr2, *ptr3;
00570 
00571   if (TEST_FLAG (LOCKFLAG, Line))
00572     {
00573       Message (_("Sorry, the object is locked\n"));
00574       return NULL;
00575     }
00576   if (Dest == Layer && Layer->On)
00577     {
00578       DrawLine (Layer, Line);
00579       Draw ();
00580     }
00581   if (((long int) Dest == -1) || Dest == Layer)
00582     return (Line);
00583 
00584   AddObjectToMoveToLayerUndoList (LINE_TYPE, Layer, Line, Line);
00585   if (Layer->On)
00586     EraseLine (Line);
00587   RestoreToPolygon (PCB->Data, LINE_TYPE, Layer, Line);
00588   newone = (LineType *)MoveLineToLayerLowLevel (Layer, Line, Dest);
00589   Line = NULL;
00590   ClearFromPolygon (PCB->Data, LINE_TYPE, Dest, newone);
00591   if (Dest->On)
00592     DrawLine (Dest, newone);
00593   Draw ();
00594   if (!PCB->ViaOn || MoreToCome ||
00595       GetLayerGroupNumberByPointer (Layer) ==
00596       GetLayerGroupNumberByPointer (Dest) ||
00597       TEST_SILK_LAYER(Layer) ||
00598       TEST_SILK_LAYER(Dest))
00599     return (newone);
00600 
00601   if (TEST_FLAG (AUTOBURIEDVIASFLAG, PCB))
00602     {
00603       info.layer_from = GetLayerNumber (PCB->Data, Layer);
00604       info.layer_to = GetLayerNumber (PCB->Data, Dest);
00605     }
00606   else
00607     {
00608       info.layer_from = 0;
00609       info.layer_to = 0;
00610     }
00611   /* consider via at Point1 */
00612   sb.X1 = newone->Point1.X - newone->Thickness / 2;
00613   sb.X2 = newone->Point1.X + newone->Thickness / 2;
00614   sb.Y1 = newone->Point1.Y - newone->Thickness / 2;
00615   sb.Y2 = newone->Point1.Y + newone->Thickness / 2;
00616   if ((SearchObjectByLocation (PIN_TYPES, &ptr1, &ptr2, &ptr3,
00617                                newone->Point1.X, newone->Point1.Y,
00618                                Settings.ViaThickness / 2) == NO_TYPE))
00619     {
00620       info.X = newone->Point1.X;
00621       info.Y = newone->Point1.Y;
00622       if (setjmp (info.env) == 0)
00623         r_search (Layer->line_tree, &sb, NULL, moveline_callback, &info);
00624     }
00625   /* consider via at Point2 */
00626   sb.X1 = newone->Point2.X - newone->Thickness / 2;
00627   sb.X2 = newone->Point2.X + newone->Thickness / 2;
00628   sb.Y1 = newone->Point2.Y - newone->Thickness / 2;
00629   sb.Y2 = newone->Point2.Y + newone->Thickness / 2;
00630   if ((SearchObjectByLocation (PIN_TYPES, &ptr1, &ptr2, &ptr3,
00631                                newone->Point2.X, newone->Point2.Y,
00632                                Settings.ViaThickness / 2) == NO_TYPE))
00633     {
00634       info.X = newone->Point2.X;
00635       info.Y = newone->Point2.Y;
00636       if (setjmp (info.env) == 0)
00637         r_search (Layer->line_tree, &sb, NULL, moveline_callback, &info);
00638     }
00639   Draw ();
00640   return (newone);
00641 }
00642 
00646 static void *
00647 MoveTextToLayerLowLevel (LayerType *Source, TextType *text,
00648                          LayerType *Destination)
00649 {
00650   RestoreToPolygon (PCB->Data, TEXT_TYPE, Source, text);
00651   r_delete_entry (Source->text_tree, (BoxType *)text);
00652 
00653   Source->Text = g_list_remove (Source->Text, text);
00654   Source->TextN --;
00655   Destination->Text = g_list_append (Destination->Text, text);
00656   Destination->TextN ++;
00657 
00658   if (GetLayerGroupNumberBySide (BOTTOM_SIDE) ==
00659       GetLayerGroupNumberByPointer (Destination))
00660     SET_FLAG (ONSOLDERFLAG, text);
00661   else
00662     CLEAR_FLAG (ONSOLDERFLAG, text);
00663 
00664   /* re-calculate the bounding box (it could be mirrored now) */
00665   SetTextBoundingBox (&PCB->Font, text);
00666   if (!Destination->text_tree)
00667     Destination->text_tree = r_create_tree (NULL, 0, 0);
00668   r_insert_entry (Destination->text_tree, (BoxType *)text, 0);
00669   ClearFromPolygon (PCB->Data, TEXT_TYPE, Destination, text);
00670 
00671   return text;
00672 }
00673 
00677 static void *
00678 MoveTextToLayer (LayerType *layer, TextType *text)
00679 {
00680   if (TEST_FLAG (LOCKFLAG, text))
00681     {
00682       Message (_("Sorry, the object is locked\n"));
00683       return NULL;
00684     }
00685   if (Dest != layer)
00686     {
00687       AddObjectToMoveToLayerUndoList (TEXT_TYPE, layer, text, text);
00688       if (layer->On)
00689         EraseText (layer, text);
00690       text = MoveTextToLayerLowLevel (layer, text, Dest);
00691       if (Dest->On)
00692         DrawText (Dest, text);
00693       if (layer->On || Dest->On)
00694         Draw ();
00695     }
00696   return text;
00697 }
00698 
00702 static void *
00703 MovePolygonToLayerLowLevel (LayerType *Source, PolygonType *polygon,
00704                             LayerType *Destination)
00705 {
00706   r_delete_entry (Source->polygon_tree, (BoxType *)polygon);
00707 
00708   Source->Polygon = g_list_remove (Source->Polygon, polygon);
00709   Source->PolygonN --;
00710   Destination->Polygon = g_list_append (Destination->Polygon, polygon);
00711   Destination->PolygonN ++;
00712 
00713   if (!Destination->polygon_tree)
00714     Destination->polygon_tree = r_create_tree (NULL, 0, 0);
00715   r_insert_entry (Destination->polygon_tree, (BoxType *)polygon, 0);
00716 
00717   return polygon;
00718 }
00719 
00720 struct mptlc
00721 {
00722   Cardinal snum, dnum;
00723   int type;
00724   PolygonType *polygon;
00725 } mptlc;
00726 
00727 int
00728 mptl_pin_callback (const BoxType *b, void *cl)
00729 {
00730   struct mptlc *d = (struct mptlc *) cl;
00731   PinType *pin = (PinType *) b;
00732   if (!TEST_THERM (d->snum, pin) || !
00733         IsPointInPolygon (pin->X, pin->Y, pin->Thickness + pin->Clearance + 2,
00734                           d->polygon))
00735                           return 0;
00736   if (d->type == PIN_TYPE)
00737     AddObjectToFlagUndoList (PIN_TYPE, pin->Element, pin, pin);
00738   else
00739     AddObjectToFlagUndoList (VIA_TYPE, pin, pin, pin);
00740   ASSIGN_THERM (d->dnum, GET_THERM (d->snum, pin), pin);
00741   CLEAR_THERM (d->snum, pin);
00742   return 1;
00743 }
00744 
00748 static void *
00749 MovePolygonToLayer (LayerType *Layer, PolygonType *Polygon)
00750 {
00751   PolygonType *newone;
00752   struct mptlc d;
00753 
00754   if (TEST_FLAG (LOCKFLAG, Polygon))
00755     {
00756       Message (_("Sorry, the object is locked\n"));
00757       return NULL;
00758     }
00759   if (((long int) Dest == -1) || (Layer == Dest))
00760     return (Polygon);
00761   AddObjectToMoveToLayerUndoList (POLYGON_TYPE, Layer, Polygon, Polygon);
00762   if (Layer->On)
00763     ErasePolygon (Polygon);
00764   /* Move all of the thermals with the polygon */
00765   d.snum = GetLayerNumber (PCB->Data, Layer);
00766   d.dnum = GetLayerNumber (PCB->Data, Dest);
00767   d.polygon = Polygon;
00768   d.type = PIN_TYPE;
00769   r_search (PCB->Data->pin_tree, &Polygon->BoundingBox, NULL, mptl_pin_callback, &d);
00770   d.type = VIA_TYPE;
00771   r_search (PCB->Data->via_tree, &Polygon->BoundingBox, NULL, mptl_pin_callback, &d);
00772   newone = (struct polygon_st *)MovePolygonToLayerLowLevel (Layer, Polygon, Dest);
00773   InitClip (PCB->Data, Dest, newone);
00774   if (Dest->On)
00775     {
00776       DrawPolygon (Dest, newone);
00777       Draw ();
00778     }
00779   return (newone);
00780 }
00781 
00786 void *
00787 MoveObject (int Type, void *Ptr1, void *Ptr2, void *Ptr3, Coord DX, Coord DY)
00788 {
00789   void *result;
00790   /* setup offset */
00791   DeltaX = DX;
00792   DeltaY = DY;
00793   AddObjectToMoveUndoList (Type, Ptr1, Ptr2, Ptr3, DX, DY);
00794   result = ObjectOperation (&MoveFunctions, Type, Ptr1, Ptr2, Ptr3);
00795   return (result);
00796 }
00797 
00802 void *
00803 MoveObjectAndRubberband (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
00804                          Coord DX, Coord DY)
00805 {
00806   RubberbandType *ptr;
00807   void *ptr2;
00808 
00809   /* setup offset */
00810   DeltaX = DX;
00811   DeltaY = DY;
00812 
00813   /* move all the lines... and reset the counter */
00814   ptr = Crosshair.AttachedObject.Rubberband;
00815   while (Crosshair.AttachedObject.RubberbandN)
00816     {
00817       /* first clear any marks that we made in the line flags */
00818       CLEAR_FLAG (RUBBERENDFLAG, ptr->Line);
00819       /* only update undo list if an actual movement happened */
00820       if (DX != 0 || DY != 0)
00821         {
00822           AddObjectToMoveUndoList (LINEPOINT_TYPE,
00823                                    ptr->Layer, ptr->Line,
00824                                    ptr->MovedPoint, DX, DY);
00825           MoveLinePoint (ptr->Layer, ptr->Line, ptr->MovedPoint);
00826         }
00827       Crosshair.AttachedObject.RubberbandN--;
00828       ptr++;
00829     }
00830 
00831   if (DX == 0 && DY == 0)
00832     return (NULL);
00833 
00834   AddObjectToMoveUndoList (Type, Ptr1, Ptr2, Ptr3, DX, DY);
00835   ptr2 = ObjectOperation (&MoveFunctions, Type, Ptr1, Ptr2, Ptr3);
00836   IncrementUndoSerialNumber ();
00837   return (ptr2);
00838 }
00839 
00844 void *
00845 MoveObjectToLayer (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
00846                    LayerType *Target, bool enmasse)
00847 {
00848   void *result;
00849 
00850   /* setup global identifiers */
00851   Dest = Target;
00852   MoreToCome = enmasse;
00853   result = ObjectOperation (&MoveToLayerFunctions, Type, Ptr1, Ptr2, Ptr3);
00854   IncrementUndoSerialNumber ();
00855   return (result);
00856 }
00857 
00862 bool
00863 MoveSelectedObjectsToLayer (LayerType *Target)
00864 {
00865   bool changed;
00866 
00867   /* setup global identifiers */
00868   Dest = Target;
00869   MoreToCome = true;
00870   changed = SelectedOperation (&MoveToLayerFunctions, true, ALL_TYPES);
00871   /* passing true to above operation causes Undoserial to auto-increment */
00872   return (changed);
00873 }
00874 
00875 static void
00876 move_one_thermal (int old_index, int new_index, PinType *pin)
00877 {
00878   int t1=0, i;
00879   int oi=old_index, ni=new_index;
00880 
00881   if (old_index != -1)
00882     t1 = GET_THERM (old_index, pin);
00883 
00884   if (oi == -1)
00885     oi = MAX_LAYER-1; /* inserting a layer */
00886   if (ni == -1)
00887     ni = MAX_LAYER-1; /* deleting a layer */
00888 
00889   if (oi < ni)
00890     {
00891       for (i=oi; i<ni; i++)
00892         ASSIGN_THERM (i, GET_THERM (i+1, pin), pin);
00893     }
00894   else
00895     {
00896       for (i=oi; i>ni; i--)
00897         ASSIGN_THERM (i, GET_THERM (i-1, pin), pin);
00898     }
00899 
00900   if (new_index != -1)
00901     ASSIGN_THERM (new_index, t1, pin);
00902   else
00903     ASSIGN_THERM (ni, 0, pin);
00904 }
00905 
00906 static void
00907 move_all_thermals (int old_index, int new_index)
00908 {
00909   VIA_LOOP (PCB->Data);
00910     {
00911       move_one_thermal (old_index, new_index, via);
00912     }
00913   END_LOOP;
00914 
00915   ALLPIN_LOOP (PCB->Data);
00916     {
00917       move_one_thermal (old_index, new_index, pin);
00918     }
00919   ENDALL_LOOP;
00920 }
00921 
00922 static int
00923 LastNormalLayerInSideGroup (int side, int layer)
00924 {
00925   int side_group = GetLayerGroupNumberBySide (side);
00926   int lgroup = GetLayerGroupNumberByNumber (layer);
00927   if (side_group == lgroup
00928       && PCB->LayerGroups.Number[lgroup] == 2)
00929     return 1;
00930   return 0;
00931 }
00932 
00942 int
00943 MoveLayer (int old_index, int new_index)
00944 {
00945   int group_of_layer[MAX_ALL_LAYER], l, g, i;
00946   LayerType saved_layer;
00947   int saved_group;
00948 
00949   AddLayerChangeToUndoList (old_index, new_index);
00950 
00951   if (old_index < -1 || old_index >= max_copper_layer)
00952     {
00953       Message ("Invalid old layer %d for move: must be -1..%d\n",
00954                old_index, max_copper_layer - 1);
00955       return 1;
00956     }
00957   if (new_index < -1 || new_index > max_copper_layer ||
00958       new_index >= MAX_LAYER)
00959     {
00960       Message ("Invalid new layer %d for move: must be -1..%d\n",
00961                new_index, max_copper_layer);
00962       return 1;
00963     }
00964   if (old_index == new_index)
00965     return 0;
00966 
00967   if (new_index == -1
00968       && LastNormalLayerInSideGroup (TOP_SIDE, old_index))
00969     {
00970       gui->confirm_dialog ("You can't delete the last top-side layer\n", "Ok", NULL);
00971       return 1;
00972     }
00973 
00974   if (new_index == -1
00975       && LastNormalLayerInSideGroup (BOTTOM_SIDE, old_index))
00976     {
00977       gui->confirm_dialog ("You can't delete the last bottom-side layer\n", "Ok", NULL);
00978       return 1;
00979     }
00980 
00981   for (l = 0; l < MAX_ALL_LAYER; l++)
00982     group_of_layer[l] = -1;
00983 
00984   for (g = 0; g < MAX_GROUP; g++)
00985     for (i = 0; i < PCB->LayerGroups.Number[g]; i++)
00986       group_of_layer[PCB->LayerGroups.Entries[g][i]] = g;
00987 
00988   if (old_index == -1)
00989     {
00990       LayerType *lp;
00991       if (max_copper_layer == MAX_LAYER)
00992         {
00993           Message ("No room for new layers\n");
00994           return 1;
00995         }
00996       /* Create a new layer at new_index. */
00997       lp = &PCB->Data->Layer[new_index];
00998       memmove (&PCB->Data->Layer[new_index + 1],
00999                &PCB->Data->Layer[new_index],
01000                (max_copper_layer + SILK_LAYER - new_index) * sizeof (LayerType));
01001       memmove (&group_of_layer[new_index + 1],
01002          &group_of_layer[new_index],
01003          (max_copper_layer + SILK_LAYER - new_index) * sizeof (int));
01004       max_copper_layer++;
01005       memset (lp, 0, sizeof (LayerType));
01006       lp->On = 1;
01007       lp->Name = strdup ("New Layer");
01008       lp->Color = Settings.LayerColor[new_index];
01009       lp->SelectedColor = Settings.LayerSelectedColor[new_index];
01010       for (l = 0; l < max_copper_layer; l++)
01011         if (LayerStack[l] >= new_index)
01012           LayerStack[l]++;
01013       LayerStack[max_copper_layer - 1] = new_index;
01014 
01015       if (!Undoing ())
01016         ChangeBuriedViasAfterLayerCreate (new_index);
01017     }
01018   else if (new_index == -1)
01019     {
01020       /* Delete the layer at old_index */
01021       memmove (&PCB->Data->Layer[old_index],
01022                &PCB->Data->Layer[old_index + 1],
01023          (max_copper_layer + SILK_LAYER - old_index - 1) *
01024             sizeof (LayerType));
01025       memset (&PCB->Data->Layer[max_copper_layer + SILK_LAYER - 1],
01026               0, sizeof (LayerType));
01027       memmove (&group_of_layer[old_index],
01028                &group_of_layer[old_index + 1],
01029                (max_copper_layer + SILK_LAYER - old_index - 1) * sizeof (int));
01030       for (l = 0; l < max_copper_layer; l++)
01031         if (LayerStack[l] == old_index)
01032           memmove (LayerStack + l,
01033                    LayerStack + l + 1,
01034                    (max_copper_layer - l - 1) * sizeof (LayerStack[0]));
01035       max_copper_layer--;
01036       for (l = 0; l < max_copper_layer; l++)
01037         if (LayerStack[l] > old_index)
01038           LayerStack[l]--;
01039 
01040       if (!Undoing ())
01041         ChangeBuriedViasAfterLayerDelete (old_index);
01042     }
01043   else
01044     {
01045       /* Move an existing layer */
01046       memcpy (&saved_layer, &PCB->Data->Layer[old_index], sizeof (LayerType));
01047       saved_group = group_of_layer[old_index];
01048       if (old_index < new_index)
01049         {
01050           memmove (&PCB->Data->Layer[old_index],
01051                    &PCB->Data->Layer[old_index + 1],
01052                    (new_index - old_index) * sizeof (LayerType));
01053           memmove (&group_of_layer[old_index],
01054                    &group_of_layer[old_index + 1],
01055                    (new_index - old_index) * sizeof (int));
01056         }
01057       else
01058         {
01059           memmove (&PCB->Data->Layer[new_index + 1],
01060                    &PCB->Data->Layer[new_index],
01061                    (old_index - new_index) * sizeof (LayerType));
01062           memmove (&group_of_layer[new_index + 1],
01063                    &group_of_layer[new_index],
01064                    (old_index - new_index) * sizeof (int));
01065         }
01066       memcpy (&PCB->Data->Layer[new_index], &saved_layer, sizeof (LayerType));
01067       group_of_layer[new_index] = saved_group;
01068 
01069       if (!Undoing ())
01070          ChangeBuriedViasAfterLayerMove (old_index, new_index);
01071     }
01072 
01073   IncrementUndoSerialNumber ();
01074 
01075   move_all_thermals(old_index, new_index);
01076 
01077   for (g = 0; g < MAX_GROUP; g++)
01078     PCB->LayerGroups.Number[g] = 0;
01079   for (l = 0; l < max_copper_layer + SILK_LAYER; l++)
01080     {
01081       g = group_of_layer[l];
01082 
01083       /* XXX: Should this ever happen? */
01084       if (g < 0)
01085         continue;
01086 
01087       i = PCB->LayerGroups.Number[g]++;
01088       PCB->LayerGroups.Entries[g][i] = l;
01089     }
01090 
01091   for (g = 1; g < MAX_GROUP; g++)
01092     if (PCB->LayerGroups.Number[g - 1] == 0)
01093       {
01094         memmove (&PCB->LayerGroups.Number[g - 1],
01095                  &PCB->LayerGroups.Number[g],
01096                  (MAX_GROUP - g) * sizeof (PCB->LayerGroups.Number[g]));
01097         memmove (&PCB->LayerGroups.Entries[g - 1],
01098                  &PCB->LayerGroups.Entries[g],
01099                  (MAX_GROUP - g) * sizeof (PCB->LayerGroups.Entries[g]));
01100       }
01101 
01102   hid_action ("LayersChanged");
01103   gui->invalidate_all ();
01104   return 0;
01105 }
01106 
01107 /* --------------------------------------------------------------------------- */
01108 
01109 static const char movelayer_syntax[] = "MoveLayer(old,new)";
01110 
01111 static const char movelayer_help[] = "Moves/Creates/Deletes Layers.";
01112 
01113 /* %start-doc actions MoveLayer
01114 
01115 Moves a layer, creates a new layer, or deletes a layer.
01116 
01117 @table @code
01118 
01119 @item old
01120 The is the layer number to act upon.  Allowed values are:
01121 @table @code
01122 
01123 @item c
01124 Currently selected layer.
01125 
01126 @item -1
01127 Create a new layer.
01128 
01129 @item number
01130 An existing layer number.
01131 
01132 @end table
01133 
01134 @item new
01135 Specifies where to move the layer to.  Allowed values are:
01136 @table @code
01137 @item -1
01138 Deletes the layer.
01139 
01140 @item up
01141 Moves the layer up.
01142 
01143 @item down
01144 Moves the layer down.
01145 
01146 @item c
01147 Creates a new layer.
01148 
01149 @end table
01150 
01151 @end table
01152 
01153 %end-doc */
01154 
01155 int
01156 MoveLayerAction (int argc, char **argv, Coord x, Coord y)
01157 {
01158   int old_index, new_index;
01159   int new_top = -1;
01160 
01161   if (argc != 2)
01162     {
01163       Message ("Usage; MoveLayer(old,new)");
01164       return 1;
01165     }
01166 
01167   if (strcmp (argv[0], "c") == 0)
01168     old_index = INDEXOFCURRENT;
01169   else
01170     old_index = atoi (argv[0]);
01171 
01172   if (strcmp (argv[1], "c") == 0)
01173     {
01174       new_index = INDEXOFCURRENT;
01175       if (new_index < 0)
01176         new_index = 0;
01177     }
01178   else if (strcmp (argv[1], "up") == 0)
01179     {
01180       new_index = INDEXOFCURRENT - 1;
01181       if (new_index < 0)
01182         return 1;
01183       new_top = new_index;
01184     }
01185   else if (strcmp (argv[1], "down") == 0)
01186     {
01187       new_index = INDEXOFCURRENT + 1;
01188       if (new_index >= max_copper_layer)
01189         return 1;
01190       new_top = new_index;
01191     }
01192   else
01193     new_index = atoi (argv[1]);
01194 
01195   if (MoveLayer (old_index, new_index))
01196     return 1;
01197 
01198   if (new_index == -1)
01199     {
01200       new_top = old_index;
01201       if (new_top >= max_copper_layer)
01202         new_top--;
01203       new_index = new_top;
01204     }
01205   if (old_index == -1)
01206     new_top = new_index;
01207 
01208   if (new_top != -1)
01209     ChangeGroupVisibility (new_index, 1, 1);
01210 
01211   return 0;
01212 }
01213 
01214 HID_Action move_action_list[] = {
01215   {"MoveLayer", 0, MoveLayerAction,
01216    movelayer_help, movelayer_syntax}
01217 };
01218 
01219 REGISTER_ACTIONS (move_action_list)