1 /*!
2  * \file src/move.c
3  *
4  * \brief Functions used to move pins, elements ...
5  *
6  * <hr>
7  *
8  * <h1><b>Copyright.</b></h1>\n
9  *
10  * PCB, interactive printed circuit board design
11  *
12  * Copyright (C) 1994,1995,1996 Thomas Nau
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License along
25  * with this program; if not, write to the Free Software Foundation, Inc.,
26  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27  *
28  * Contact addresses for paper mail and Email:
29  *
30  * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
31  *
32  * Thomas.Nau@rz.uni-ulm.de
33  */
34 
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif
38 
39 #include <setjmp.h>
40 #include <stdlib.h>
41 
42 #include "global.h"
43 
44 #include "create.h"
45 #include "crosshair.h"
46 #include "data.h"
47 #include "draw.h"
48 #include "error.h"
49 #include "misc.h"
50 #include "move.h"
51 #include "mymem.h"
52 #include "polygon.h"
53 #include "rtree.h"
54 #include "search.h"
55 #include "select.h"
56 #include "thermal.h"
57 #include "undo.h"
58 
59 #ifdef HAVE_LIBDMALLOC
60 #include <dmalloc.h>
61 #endif
62 
63 /* ---------------------------------------------------------------------------
64  * some local prototypes
65  */
66 static void *MoveElementName (ElementType *);
67 static void *MoveElement (ElementType *);
68 static void *MoveVia (PinType *);
69 static void *MoveLine (LayerType *, LineType *);
70 static void *MoveArc (LayerType *, ArcType *);
71 static void *MoveText (LayerType *, TextType *);
72 static void *MovePolygon (LayerType *, PolygonType *);
73 static void *MoveLinePoint (LayerType *, LineType *, PointType *);
74 static void *MovePolygonPoint (LayerType *, PolygonType *, PointType *);
75 static void *MoveLineToLayer (LayerType *, LineType *);
76 static void *MoveArcToLayer (LayerType *, ArcType *);
77 static void *MoveRatToLayer (RatType *);
78 static void *MoveTextToLayer (LayerType *, TextType *);
79 static void *MovePolygonToLayer (LayerType *, PolygonType *);
80 
81 /* ---------------------------------------------------------------------------
82  * some local identifiers
83  */
84 static Coord DeltaX, DeltaY;	/* used by local routines as offset */
85 static LayerType *Dest;
86 static bool MoreToCome;
87 static ObjectFunctionType MoveFunctions = {
88   MoveLine,
89   MoveText,
90   MovePolygon,
91   MoveVia,
92   MoveElement,
93   MoveElementName,
94   NULL,
95   NULL,
96   MoveLinePoint,
97   MovePolygonPoint,
98   MoveArc,
99   NULL
100 }, MoveToLayerFunctions =
101 
102 {
103 MoveLineToLayer,
104     MoveTextToLayer,
105     MovePolygonToLayer,
106     NULL, NULL, NULL, NULL, NULL, NULL, NULL, MoveArcToLayer, MoveRatToLayer};
107 
108 /*!
109  * \brief Moves a element by +-X and +-Y.
110  */
111 void
MoveElementLowLevel(DataType * Data,ElementType * Element,Coord DX,Coord DY)112 MoveElementLowLevel (DataType *Data, ElementType *Element,
113 		     Coord DX, Coord DY)
114 {
115   if (Data)
116     r_delete_entry (Data->element_tree, (BoxType *)Element);
117   ELEMENTLINE_LOOP (Element);
118   {
119     MOVE_LINE_LOWLEVEL (line, DX, DY);
120   }
121   END_LOOP;
122   PIN_LOOP (Element);
123   {
124     if (Data)
125       {
126 	r_delete_entry (Data->pin_tree, (BoxType *)pin);
127 	RestoreToPolygon (Data, PIN_TYPE, Element, pin);
128       }
129     MOVE_PIN_LOWLEVEL (pin, DX, DY);
130     if (Data)
131       {
132 	r_insert_entry (Data->pin_tree, (BoxType *)pin, 0);
133 	ClearFromPolygon (Data, PIN_TYPE, Element, pin);
134       }
135   }
136   END_LOOP;
137   PAD_LOOP (Element);
138   {
139     if (Data)
140       {
141 	r_delete_entry (Data->pad_tree, (BoxType *)pad);
142 	RestoreToPolygon (Data, PAD_TYPE, Element, pad);
143       }
144     MOVE_PAD_LOWLEVEL (pad, DX, DY);
145     if (Data)
146       {
147 	r_insert_entry (Data->pad_tree, (BoxType *)pad, 0);
148 	ClearFromPolygon (Data, PAD_TYPE, Element, pad);
149       }
150   }
151   END_LOOP;
152   ARC_LOOP (Element);
153   {
154     MOVE_ARC_LOWLEVEL (arc, DX, DY);
155   }
156   END_LOOP;
157   ELEMENTTEXT_LOOP (Element);
158   {
159     if (Data && Data->name_tree[n])
160       r_delete_entry (PCB->Data->name_tree[n], (BoxType *)text);
161     MOVE_TEXT_LOWLEVEL (text, DX, DY);
162     if (Data && Data->name_tree[n])
163       r_insert_entry (PCB->Data->name_tree[n], (BoxType *)text, 0);
164   }
165   END_LOOP;
166   MOVE_BOX_LOWLEVEL (&Element->BoundingBox, DX, DY);
167   MOVE_BOX_LOWLEVEL (&Element->VBox, DX, DY);
168   MOVE (Element->MarkX, Element->MarkY, DX, DY);
169   if (Data)
170     r_insert_entry (Data->element_tree, (BoxType *)Element, 0);
171 }
172 
173 /*!
174  * \brief Moves all names of an element to a new position.
175  */
176 static void *
MoveElementName(ElementType * Element)177 MoveElementName (ElementType *Element)
178 {
179   if (PCB->ElementOn && (FRONT (Element) || PCB->InvisibleObjectsOn))
180     {
181       EraseElementName (Element);
182       ELEMENTTEXT_LOOP (Element);
183       {
184 	if (PCB->Data->name_tree[n])
185 	  r_delete_entry (PCB->Data->name_tree[n], (BoxType *)text);
186 	MOVE_TEXT_LOWLEVEL (text, DeltaX, DeltaY);
187 	if (PCB->Data->name_tree[n])
188 	  r_insert_entry (PCB->Data->name_tree[n], (BoxType *)text, 0);
189       }
190       END_LOOP;
191       DrawElementName (Element);
192       Draw ();
193     }
194   else
195     {
196       ELEMENTTEXT_LOOP (Element);
197       {
198 	if (PCB->Data->name_tree[n])
199 	  r_delete_entry (PCB->Data->name_tree[n], (BoxType *)text);
200 	MOVE_TEXT_LOWLEVEL (text, DeltaX, DeltaY);
201 	if (PCB->Data->name_tree[n])
202 	  r_insert_entry (PCB->Data->name_tree[n], (BoxType *)text, 0);
203       }
204       END_LOOP;
205     }
206   return (Element);
207 }
208 
209 /*!
210  * \brief Moves an element.
211  */
212 static void *
MoveElement(ElementType * Element)213 MoveElement (ElementType *Element)
214 {
215   bool didDraw = false;
216 
217   if (PCB->ElementOn && (FRONT (Element) || PCB->InvisibleObjectsOn))
218     {
219       EraseElement (Element);
220       MoveElementLowLevel (PCB->Data, Element, DeltaX, DeltaY);
221       DrawElementName (Element);
222       DrawElementPackage (Element);
223       didDraw = true;
224     }
225   else
226     {
227       if (PCB->PinOn)
228 	EraseElementPinsAndPads (Element);
229       MoveElementLowLevel (PCB->Data, Element, DeltaX, DeltaY);
230     }
231   if (PCB->PinOn)
232     {
233       DrawElementPinsAndPads (Element);
234       didDraw = true;
235     }
236   if (didDraw)
237     Draw ();
238   return (Element);
239 }
240 
241 /*!
242  * \brief Moves a via.
243  */
244 static void *
MoveVia(PinType * Via)245 MoveVia (PinType *Via)
246 {
247   r_delete_entry (PCB->Data->via_tree, (BoxType *)Via);
248   RestoreToPolygon (PCB->Data, VIA_TYPE, Via, Via);
249   MOVE_VIA_LOWLEVEL (Via, DeltaX, DeltaY);
250   if (PCB->ViaOn)
251     EraseVia (Via);
252   r_insert_entry (PCB->Data->via_tree, (BoxType *)Via, 0);
253   ClearFromPolygon (PCB->Data, VIA_TYPE, Via, Via);
254   if (PCB->ViaOn)
255     {
256       DrawVia (Via);
257       Draw ();
258     }
259   return (Via);
260 }
261 
262 /*!
263  * \brief Moves a line.
264  */
265 static void *
MoveLine(LayerType * Layer,LineType * Line)266 MoveLine (LayerType *Layer, LineType *Line)
267 {
268   if (Layer->On)
269     EraseLine (Line);
270   RestoreToPolygon (PCB->Data, LINE_TYPE, Layer, Line);
271   r_delete_entry (Layer->line_tree, (BoxType *)Line);
272   MOVE_LINE_LOWLEVEL (Line, DeltaX, DeltaY);
273   r_insert_entry (Layer->line_tree, (BoxType *)Line, 0);
274   ClearFromPolygon (PCB->Data, LINE_TYPE, Layer, Line);
275   if (Layer->On)
276     {
277       DrawLine (Layer, Line);
278       Draw ();
279     }
280   return (Line);
281 }
282 
283 /*!
284  * \brief Moves an arc.
285  */
286 static void *
MoveArc(LayerType * Layer,ArcType * Arc)287 MoveArc (LayerType *Layer, ArcType *Arc)
288 {
289   RestoreToPolygon (PCB->Data, ARC_TYPE, Layer, Arc);
290   r_delete_entry (Layer->arc_tree, (BoxType *)Arc);
291   if (Layer->On)
292     {
293       EraseArc (Arc);
294       MOVE_ARC_LOWLEVEL (Arc, DeltaX, DeltaY);
295       DrawArc (Layer, Arc);
296       Draw ();
297     }
298   else
299     {
300       MOVE_ARC_LOWLEVEL (Arc, DeltaX, DeltaY);
301     }
302   r_insert_entry (Layer->arc_tree, (BoxType *)Arc, 0);
303   ClearFromPolygon (PCB->Data, ARC_TYPE, Layer, Arc);
304   return (Arc);
305 }
306 
307 /*!
308  * \brief Moves a text object.
309  */
310 static void *
MoveText(LayerType * Layer,TextType * Text)311 MoveText (LayerType *Layer, TextType *Text)
312 {
313   RestoreToPolygon (PCB->Data, TEXT_TYPE, Layer, Text);
314   r_delete_entry (Layer->text_tree, (BoxType *)Text);
315   if (Layer->On)
316     {
317       EraseText (Layer, Text);
318       MOVE_TEXT_LOWLEVEL (Text, DeltaX, DeltaY);
319       DrawText (Layer, Text);
320       Draw ();
321     }
322   else
323     MOVE_TEXT_LOWLEVEL (Text, DeltaX, DeltaY);
324   r_insert_entry (Layer->text_tree, (BoxType *)Text, 0);
325   ClearFromPolygon (PCB->Data, TEXT_TYPE, Layer, Text);
326   return (Text);
327 }
328 
329 /*!
330  * \brief Low level routine to move a polygon.
331  */
332 void
MovePolygonLowLevel(PolygonType * Polygon,Coord DeltaX,Coord DeltaY)333 MovePolygonLowLevel (PolygonType *Polygon, Coord DeltaX, Coord DeltaY)
334 {
335   POLYGONPOINT_LOOP (Polygon);
336   {
337     MOVE (point->X, point->Y, DeltaX, DeltaY);
338   }
339   END_LOOP;
340   MOVE_BOX_LOWLEVEL (&Polygon->BoundingBox, DeltaX, DeltaY);
341 }
342 
343 /*!
344  * \brief Moves a polygon.
345  */
346 static void *
MovePolygon(LayerType * Layer,PolygonType * Polygon)347 MovePolygon (LayerType *Layer, PolygonType *Polygon)
348 {
349   if (Layer->On)
350     {
351       ErasePolygon (Polygon);
352     }
353   r_delete_entry (Layer->polygon_tree, (BoxType *)Polygon);
354   MovePolygonLowLevel (Polygon, DeltaX, DeltaY);
355   r_insert_entry (Layer->polygon_tree, (BoxType *)Polygon, 0);
356   InitClip (PCB->Data, Layer, Polygon);
357   if (Layer->On)
358     {
359       DrawPolygon (Layer, Polygon);
360       Draw ();
361     }
362   return (Polygon);
363 }
364 
365 /*!
366  * \brief Moves one end of a line.
367  */
368 static void *
MoveLinePoint(LayerType * Layer,LineType * Line,PointType * Point)369 MoveLinePoint (LayerType *Layer, LineType *Line, PointType *Point)
370 {
371   if (Layer)
372     {
373       if (Layer->On)
374 	EraseLine (Line);
375       RestoreToPolygon (PCB->Data, LINE_TYPE, Layer, Line);
376       r_delete_entry (Layer->line_tree, &Line->BoundingBox);
377       MOVE (Point->X, Point->Y, DeltaX, DeltaY);
378       SetLineBoundingBox (Line);
379       r_insert_entry (Layer->line_tree, &Line->BoundingBox, 0);
380       ClearFromPolygon (PCB->Data, LINE_TYPE, Layer, Line);
381       if (Layer->On)
382 	{
383 	  DrawLine (Layer, Line);
384 	  Draw ();
385 	}
386       return (Line);
387     }
388   else				/* must be a rat */
389     {
390       if (PCB->RatOn)
391 	EraseRat ((RatType *) Line);
392       r_delete_entry (PCB->Data->rat_tree, &Line->BoundingBox);
393       MOVE (Point->X, Point->Y, DeltaX, DeltaY);
394       SetLineBoundingBox (Line);
395       r_insert_entry (PCB->Data->rat_tree, &Line->BoundingBox, 0);
396       if (PCB->RatOn)
397 	{
398 	  DrawRat ((RatType *) Line);
399 	  Draw ();
400 	}
401       return (Line);
402     }
403 }
404 
405 /*!
406  * \brief Moves a polygon-point.
407  */
408 static void *
MovePolygonPoint(LayerType * Layer,PolygonType * Polygon,PointType * Point)409 MovePolygonPoint (LayerType *Layer, PolygonType *Polygon,
410 		  PointType *Point)
411 {
412   if (Layer->On)
413     {
414       ErasePolygon (Polygon);
415     }
416   r_delete_entry (Layer->polygon_tree, (BoxType *)Polygon);
417   MOVE (Point->X, Point->Y, DeltaX, DeltaY);
418   SetPolygonBoundingBox (Polygon);
419   r_insert_entry (Layer->polygon_tree, (BoxType *)Polygon, 0);
420   RemoveExcessPolygonPoints (Layer, Polygon);
421   InitClip (PCB->Data, Layer, Polygon);
422   if (Layer->On)
423     {
424       DrawPolygon (Layer, Polygon);
425       Draw ();
426     }
427   return (Point);
428 }
429 
430 /*!
431  * \brief Moves a line between layers; lowlevel routines.
432  */
433 static void *
MoveLineToLayerLowLevel(LayerType * Source,LineType * line,LayerType * Destination)434 MoveLineToLayerLowLevel (LayerType *Source, LineType *line,
435 			 LayerType *Destination)
436 {
437   r_delete_entry (Source->line_tree, (BoxType *)line);
438 
439   Source->Line = g_list_remove (Source->Line, line);
440   Source->LineN --;
441   Destination->Line = g_list_append (Destination->Line, line);
442   Destination->LineN ++;
443 
444   if (!Destination->line_tree)
445     Destination->line_tree = r_create_tree (NULL, 0, 0);
446   r_insert_entry (Destination->line_tree, (BoxType *)line, 0);
447   return line;
448 }
449 
450 /*!
451  * \brief Moves an arc between layers; lowlevel routines.
452  */
453 static void *
MoveArcToLayerLowLevel(LayerType * Source,ArcType * arc,LayerType * Destination)454 MoveArcToLayerLowLevel (LayerType *Source, ArcType *arc,
455 			LayerType *Destination)
456 {
457   r_delete_entry (Source->arc_tree, (BoxType *)arc);
458 
459   Source->Arc = g_list_remove (Source->Arc, arc);
460   Source->ArcN --;
461   Destination->Arc = g_list_append (Destination->Arc, arc);
462   Destination->ArcN ++;
463 
464   if (!Destination->arc_tree)
465     Destination->arc_tree = r_create_tree (NULL, 0, 0);
466   r_insert_entry (Destination->arc_tree, (BoxType *)arc, 0);
467   return arc;
468 }
469 
470 
471 /*!
472  * \brief Moves an arc between layers.
473  */
474 static void *
MoveArcToLayer(LayerType * Layer,ArcType * Arc)475 MoveArcToLayer (LayerType *Layer, ArcType *Arc)
476 {
477   ArcType *newone;
478 
479   if (TEST_FLAG (LOCKFLAG, Arc))
480     {
481       Message (_("Sorry, the object is locked\n"));
482       return NULL;
483     }
484   if (Dest == Layer && Layer->On)
485     {
486       DrawArc (Layer, Arc);
487       Draw ();
488     }
489   if (((long int) Dest == -1) || Dest == Layer)
490     return (Arc);
491   AddObjectToMoveToLayerUndoList (ARC_TYPE, Layer, Arc, Arc);
492   RestoreToPolygon (PCB->Data, ARC_TYPE, Layer, Arc);
493   if (Layer->On)
494     EraseArc (Arc);
495   newone = (ArcType *)MoveArcToLayerLowLevel (Layer, Arc, Dest);
496   ClearFromPolygon (PCB->Data, ARC_TYPE, Dest, Arc);
497   if (Dest->On)
498     DrawArc (Dest, newone);
499   Draw ();
500   return (newone);
501 }
502 
503 /*!
504  * \brief Moves a line between layers.
505  */
506 static void *
MoveRatToLayer(RatType * Rat)507 MoveRatToLayer (RatType *Rat)
508 {
509   LineType *newone;
510   //Coord X1 = Rat->Point1.X, Y1 = Rat->Point1.Y;
511   //Coord X1 = Rat->Point1.X, Y1 = Rat->Point1.Y;
512   // if VIAFLAG
513   //   if we're on a pin, add a thermal
514   //   else make a via and a wire, but 0-length wire not good
515   // else as before
516 
517   newone = CreateNewLineOnLayer (Dest, Rat->Point1.X, Rat->Point1.Y,
518 			      Rat->Point2.X, Rat->Point2.Y,
519 			      Settings.LineThickness, 2 * Settings.Keepaway,
520 			      Rat->Flags);
521   if (TEST_FLAG (CLEARNEWFLAG, PCB))
522     SET_FLAG (CLEARLINEFLAG, newone);
523   if (!newone)
524     return (NULL);
525   AddObjectToCreateUndoList (LINE_TYPE, Dest, newone, newone);
526   if (PCB->RatOn)
527     EraseRat (Rat);
528   MoveObjectToRemoveUndoList (RATLINE_TYPE, Rat, Rat, Rat);
529   DrawLine (Dest, newone);
530   Draw ();
531   return (newone);
532 }
533 
534 /*!
535  * \brief Moves a line between layers.
536  */
537 
538 struct via_info
539 {
540   Coord X, Y;
541   Cardinal layer_from, layer_to;
542   jmp_buf env;
543 };
544 
545 static int
moveline_callback(const BoxType * b,void * cl)546 moveline_callback (const BoxType * b, void *cl)
547 {
548   struct via_info *i = (struct via_info *) cl;
549   PinType *via;
550 
551   if ((via =
552        CreateNewViaEx (PCB->Data, i->X, i->Y,
553 		     Settings.ViaThickness, 2 * Settings.Keepaway,
554 		     NOFLAG, Settings.ViaDrillingHole, NULL,
555 		     NoFlags (), i->layer_from, i->layer_to)) != NULL)
556     {
557       AddObjectToCreateUndoList (VIA_TYPE, via, via, via);
558       DrawVia (via);
559     }
560   longjmp (i->env, 1);
561 }
562 
563 static void *
MoveLineToLayer(LayerType * Layer,LineType * Line)564 MoveLineToLayer (LayerType *Layer, LineType *Line)
565 {
566   struct via_info info;
567   BoxType sb;
568   LineType *newone;
569   void *ptr1, *ptr2, *ptr3;
570 
571   if (TEST_FLAG (LOCKFLAG, Line))
572     {
573       Message (_("Sorry, the object is locked\n"));
574       return NULL;
575     }
576   if (Dest == Layer && Layer->On)
577     {
578       DrawLine (Layer, Line);
579       Draw ();
580     }
581   if (((long int) Dest == -1) || Dest == Layer)
582     return (Line);
583 
584   AddObjectToMoveToLayerUndoList (LINE_TYPE, Layer, Line, Line);
585   if (Layer->On)
586     EraseLine (Line);
587   RestoreToPolygon (PCB->Data, LINE_TYPE, Layer, Line);
588   newone = (LineType *)MoveLineToLayerLowLevel (Layer, Line, Dest);
589   Line = NULL;
590   ClearFromPolygon (PCB->Data, LINE_TYPE, Dest, newone);
591   if (Dest->On)
592     DrawLine (Dest, newone);
593   Draw ();
594   if (!PCB->ViaOn || MoreToCome ||
595       GetLayerGroupNumberByPointer (Layer) ==
596       GetLayerGroupNumberByPointer (Dest) ||
597       TEST_SILK_LAYER(Layer) ||
598       TEST_SILK_LAYER(Dest))
599     return (newone);
600 
601   if (TEST_FLAG (AUTOBURIEDVIASFLAG, PCB))
602     {
603       info.layer_from = GetLayerNumber (PCB->Data, Layer);
604       info.layer_to = GetLayerNumber (PCB->Data, Dest);
605     }
606   else
607     {
608       info.layer_from = 0;
609       info.layer_to = 0;
610     }
611   /* consider via at Point1 */
612   sb.X1 = newone->Point1.X - newone->Thickness / 2;
613   sb.X2 = newone->Point1.X + newone->Thickness / 2;
614   sb.Y1 = newone->Point1.Y - newone->Thickness / 2;
615   sb.Y2 = newone->Point1.Y + newone->Thickness / 2;
616   if ((SearchObjectByLocation (PIN_TYPES, &ptr1, &ptr2, &ptr3,
617 			       newone->Point1.X, newone->Point1.Y,
618 			       Settings.ViaThickness / 2) == NO_TYPE))
619     {
620       info.X = newone->Point1.X;
621       info.Y = newone->Point1.Y;
622       if (setjmp (info.env) == 0)
623 	r_search (Layer->line_tree, &sb, NULL, moveline_callback, &info);
624     }
625   /* consider via at Point2 */
626   sb.X1 = newone->Point2.X - newone->Thickness / 2;
627   sb.X2 = newone->Point2.X + newone->Thickness / 2;
628   sb.Y1 = newone->Point2.Y - newone->Thickness / 2;
629   sb.Y2 = newone->Point2.Y + newone->Thickness / 2;
630   if ((SearchObjectByLocation (PIN_TYPES, &ptr1, &ptr2, &ptr3,
631 			       newone->Point2.X, newone->Point2.Y,
632 			       Settings.ViaThickness / 2) == NO_TYPE))
633     {
634       info.X = newone->Point2.X;
635       info.Y = newone->Point2.Y;
636       if (setjmp (info.env) == 0)
637 	r_search (Layer->line_tree, &sb, NULL, moveline_callback, &info);
638     }
639   Draw ();
640   return (newone);
641 }
642 
643 /*!
644  * \brief Moves a text object between layers; lowlevel routines.
645  */
646 static void *
MoveTextToLayerLowLevel(LayerType * Source,TextType * text,LayerType * Destination)647 MoveTextToLayerLowLevel (LayerType *Source, TextType *text,
648 			 LayerType *Destination)
649 {
650   RestoreToPolygon (PCB->Data, TEXT_TYPE, Source, text);
651   r_delete_entry (Source->text_tree, (BoxType *)text);
652 
653   Source->Text = g_list_remove (Source->Text, text);
654   Source->TextN --;
655   Destination->Text = g_list_append (Destination->Text, text);
656   Destination->TextN ++;
657 
658   if (GetLayerGroupNumberBySide (BOTTOM_SIDE) ==
659       GetLayerGroupNumberByPointer (Destination))
660     SET_FLAG (ONSOLDERFLAG, text);
661   else
662     CLEAR_FLAG (ONSOLDERFLAG, text);
663 
664   /* re-calculate the bounding box (it could be mirrored now) */
665   SetTextBoundingBox (&PCB->Font, text);
666   if (!Destination->text_tree)
667     Destination->text_tree = r_create_tree (NULL, 0, 0);
668   r_insert_entry (Destination->text_tree, (BoxType *)text, 0);
669   ClearFromPolygon (PCB->Data, TEXT_TYPE, Destination, text);
670 
671   return text;
672 }
673 
674 /*!
675  * \brief Moves a text object between layers.
676  */
677 static void *
MoveTextToLayer(LayerType * layer,TextType * text)678 MoveTextToLayer (LayerType *layer, TextType *text)
679 {
680   if (TEST_FLAG (LOCKFLAG, text))
681     {
682       Message (_("Sorry, the object is locked\n"));
683       return NULL;
684     }
685   if (Dest != layer)
686     {
687       AddObjectToMoveToLayerUndoList (TEXT_TYPE, layer, text, text);
688       if (layer->On)
689 	EraseText (layer, text);
690       text = MoveTextToLayerLowLevel (layer, text, Dest);
691       if (Dest->On)
692 	DrawText (Dest, text);
693       if (layer->On || Dest->On)
694 	Draw ();
695     }
696   return text;
697 }
698 
699 /*!
700  * \brief Moves a polygon between layers; lowlevel routines.
701  */
702 static void *
MovePolygonToLayerLowLevel(LayerType * Source,PolygonType * polygon,LayerType * Destination)703 MovePolygonToLayerLowLevel (LayerType *Source, PolygonType *polygon,
704 			    LayerType *Destination)
705 {
706   r_delete_entry (Source->polygon_tree, (BoxType *)polygon);
707 
708   Source->Polygon = g_list_remove (Source->Polygon, polygon);
709   Source->PolygonN --;
710   Destination->Polygon = g_list_append (Destination->Polygon, polygon);
711   Destination->PolygonN ++;
712 
713   if (!Destination->polygon_tree)
714     Destination->polygon_tree = r_create_tree (NULL, 0, 0);
715   r_insert_entry (Destination->polygon_tree, (BoxType *)polygon, 0);
716 
717   return polygon;
718 }
719 
720 struct mptlc
721 {
722   Cardinal snum, dnum;
723   int type;
724   PolygonType *polygon;
725 } mptlc;
726 
727 int
mptl_pin_callback(const BoxType * b,void * cl)728 mptl_pin_callback (const BoxType *b, void *cl)
729 {
730   struct mptlc *d = (struct mptlc *) cl;
731   PinType *pin = (PinType *) b;
732   if (!TEST_THERM (d->snum, pin) || !
733 	IsPointInPolygon (pin->X, pin->Y, pin->Thickness + pin->Clearance + 2,
734 			  d->polygon))
735 			  return 0;
736   if (d->type == PIN_TYPE)
737     AddObjectToFlagUndoList (PIN_TYPE, pin->Element, pin, pin);
738   else
739     AddObjectToFlagUndoList (VIA_TYPE, pin, pin, pin);
740   ASSIGN_THERM (d->dnum, GET_THERM (d->snum, pin), pin);
741   CLEAR_THERM (d->snum, pin);
742   return 1;
743 }
744 
745 /*!
746  * \brief Moves a polygon between layers.
747  */
748 static void *
MovePolygonToLayer(LayerType * Layer,PolygonType * Polygon)749 MovePolygonToLayer (LayerType *Layer, PolygonType *Polygon)
750 {
751   PolygonType *newone;
752   struct mptlc d;
753 
754   if (TEST_FLAG (LOCKFLAG, Polygon))
755     {
756       Message (_("Sorry, the object is locked\n"));
757       return NULL;
758     }
759   if (((long int) Dest == -1) || (Layer == Dest))
760     return (Polygon);
761   AddObjectToMoveToLayerUndoList (POLYGON_TYPE, Layer, Polygon, Polygon);
762   if (Layer->On)
763     ErasePolygon (Polygon);
764   /* Move all of the thermals with the polygon */
765   d.snum = GetLayerNumber (PCB->Data, Layer);
766   d.dnum = GetLayerNumber (PCB->Data, Dest);
767   d.polygon = Polygon;
768   d.type = PIN_TYPE;
769   r_search (PCB->Data->pin_tree, &Polygon->BoundingBox, NULL, mptl_pin_callback, &d);
770   d.type = VIA_TYPE;
771   r_search (PCB->Data->via_tree, &Polygon->BoundingBox, NULL, mptl_pin_callback, &d);
772   newone = (struct polygon_st *)MovePolygonToLayerLowLevel (Layer, Polygon, Dest);
773   InitClip (PCB->Data, Dest, newone);
774   if (Dest->On)
775     {
776       DrawPolygon (Dest, newone);
777       Draw ();
778     }
779   return (newone);
780 }
781 
782 /*!
783  * \brief Moves the object identified by its data pointers and the type
784  * not we don't bump the undo serial number.
785  */
786 void *
MoveObject(int Type,void * Ptr1,void * Ptr2,void * Ptr3,Coord DX,Coord DY)787 MoveObject (int Type, void *Ptr1, void *Ptr2, void *Ptr3, Coord DX, Coord DY)
788 {
789   void *result;
790   /* setup offset */
791   DeltaX = DX;
792   DeltaY = DY;
793   AddObjectToMoveUndoList (Type, Ptr1, Ptr2, Ptr3, DX, DY);
794   result = ObjectOperation (&MoveFunctions, Type, Ptr1, Ptr2, Ptr3);
795   return (result);
796 }
797 
798 /*!
799  * \brief Moves the object identified by its data pointers and the type
800  * as well as all attached rubberband lines.
801  */
802 void *
MoveObjectAndRubberband(int Type,void * Ptr1,void * Ptr2,void * Ptr3,Coord DX,Coord DY)803 MoveObjectAndRubberband (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
804 			 Coord DX, Coord DY)
805 {
806   RubberbandType *ptr;
807   void *ptr2;
808 
809   /* setup offset */
810   DeltaX = DX;
811   DeltaY = DY;
812 
813   /* move all the lines... and reset the counter */
814   ptr = Crosshair.AttachedObject.Rubberband;
815   while (Crosshair.AttachedObject.RubberbandN)
816     {
817       /* first clear any marks that we made in the line flags */
818       CLEAR_FLAG (RUBBERENDFLAG, ptr->Line);
819       /* only update undo list if an actual movement happened */
820       if (DX != 0 || DY != 0)
821         {
822           AddObjectToMoveUndoList (LINEPOINT_TYPE,
823                                    ptr->Layer, ptr->Line,
824                                    ptr->MovedPoint, DX, DY);
825           MoveLinePoint (ptr->Layer, ptr->Line, ptr->MovedPoint);
826         }
827       Crosshair.AttachedObject.RubberbandN--;
828       ptr++;
829     }
830 
831   if (DX == 0 && DY == 0)
832     return (NULL);
833 
834   AddObjectToMoveUndoList (Type, Ptr1, Ptr2, Ptr3, DX, DY);
835   ptr2 = ObjectOperation (&MoveFunctions, Type, Ptr1, Ptr2, Ptr3);
836   IncrementUndoSerialNumber ();
837   return (ptr2);
838 }
839 
840 /*!
841  * \brief Moves the object identified by its data pointers and the type
842  * to a new layer without changing it's position.
843  */
844 void *
MoveObjectToLayer(int Type,void * Ptr1,void * Ptr2,void * Ptr3,LayerType * Target,bool enmasse)845 MoveObjectToLayer (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
846 		   LayerType *Target, bool enmasse)
847 {
848   void *result;
849 
850   /* setup global identifiers */
851   Dest = Target;
852   MoreToCome = enmasse;
853   result = ObjectOperation (&MoveToLayerFunctions, Type, Ptr1, Ptr2, Ptr3);
854   IncrementUndoSerialNumber ();
855   return (result);
856 }
857 
858 /*!
859  * \brief Moves the selected objects to a new layer without changing
860  * their positions.
861  */
862 bool
MoveSelectedObjectsToLayer(LayerType * Target)863 MoveSelectedObjectsToLayer (LayerType *Target)
864 {
865   bool changed;
866 
867   /* setup global identifiers */
868   Dest = Target;
869   MoreToCome = true;
870   changed = SelectedOperation (&MoveToLayerFunctions, true, ALL_TYPES);
871   /* passing true to above operation causes Undoserial to auto-increment */
872   return (changed);
873 }
874 
875 static void
move_one_thermal(int old_index,int new_index,PinType * pin)876 move_one_thermal (int old_index, int new_index, PinType *pin)
877 {
878   int t1=0, i;
879   int oi=old_index, ni=new_index;
880 
881   if (old_index != -1)
882     t1 = GET_THERM (old_index, pin);
883 
884   if (oi == -1)
885     oi = MAX_LAYER-1; /* inserting a layer */
886   if (ni == -1)
887     ni = MAX_LAYER-1; /* deleting a layer */
888 
889   if (oi < ni)
890     {
891       for (i=oi; i<ni; i++)
892 	ASSIGN_THERM (i, GET_THERM (i+1, pin), pin);
893     }
894   else
895     {
896       for (i=oi; i>ni; i--)
897 	ASSIGN_THERM (i, GET_THERM (i-1, pin), pin);
898     }
899 
900   if (new_index != -1)
901     ASSIGN_THERM (new_index, t1, pin);
902   else
903     ASSIGN_THERM (ni, 0, pin);
904 }
905 
906 static void
move_all_thermals(int old_index,int new_index)907 move_all_thermals (int old_index, int new_index)
908 {
909   VIA_LOOP (PCB->Data);
910     {
911       move_one_thermal (old_index, new_index, via);
912     }
913   END_LOOP;
914 
915   ALLPIN_LOOP (PCB->Data);
916     {
917       move_one_thermal (old_index, new_index, pin);
918     }
919   ENDALL_LOOP;
920 }
921 
922 static int
LastNormalLayerInSideGroup(int side,int layer)923 LastNormalLayerInSideGroup (int side, int layer)
924 {
925   int side_group = GetLayerGroupNumberBySide (side);
926   int lgroup = GetLayerGroupNumberByNumber (layer);
927   if (side_group == lgroup
928       && PCB->LayerGroups.Number[lgroup] == 2)
929     return 1;
930   return 0;
931 }
932 
933 /*!
934  * \brief Moves the selected layers to a new index in the layer list.
935  *
936  * index is 0..MAX_ALL_LAYER-1.
937  * If old_index is -1, a new layer is inserted at that index.
938  * If new_index is -1, the specified layer is deleted.
939  *
940  * \return non-zero on error, zero if OK.
941  */
942 int
MoveLayer(int old_index,int new_index)943 MoveLayer (int old_index, int new_index)
944 {
945   int group_of_layer[MAX_ALL_LAYER], l, g, i;
946   LayerType saved_layer;
947   int saved_group;
948 
949   AddLayerChangeToUndoList (old_index, new_index);
950 
951   if (old_index < -1 || old_index >= max_copper_layer)
952     {
953       Message ("Invalid old layer %d for move: must be -1..%d\n",
954 	       old_index, max_copper_layer - 1);
955       return 1;
956     }
957   if (new_index < -1 || new_index > max_copper_layer ||
958       new_index >= MAX_LAYER)
959     {
960       Message ("Invalid new layer %d for move: must be -1..%d\n",
961 	       new_index, max_copper_layer);
962       return 1;
963     }
964   if (old_index == new_index)
965     return 0;
966 
967   if (new_index == -1
968       && LastNormalLayerInSideGroup (TOP_SIDE, old_index))
969     {
970       gui->confirm_dialog ("You can't delete the last top-side layer\n", "Ok", NULL);
971       return 1;
972     }
973 
974   if (new_index == -1
975       && LastNormalLayerInSideGroup (BOTTOM_SIDE, old_index))
976     {
977       gui->confirm_dialog ("You can't delete the last bottom-side layer\n", "Ok", NULL);
978       return 1;
979     }
980 
981   for (l = 0; l < MAX_ALL_LAYER; l++)
982     group_of_layer[l] = -1;
983 
984   for (g = 0; g < MAX_GROUP; g++)
985     for (i = 0; i < PCB->LayerGroups.Number[g]; i++)
986       group_of_layer[PCB->LayerGroups.Entries[g][i]] = g;
987 
988   if (old_index == -1)
989     {
990       LayerType *lp;
991       if (max_copper_layer == MAX_LAYER)
992 	{
993 	  Message ("No room for new layers\n");
994 	  return 1;
995 	}
996       /* Create a new layer at new_index. */
997       lp = &PCB->Data->Layer[new_index];
998       memmove (&PCB->Data->Layer[new_index + 1],
999 	       &PCB->Data->Layer[new_index],
1000 	       (max_copper_layer + SILK_LAYER - new_index) * sizeof (LayerType));
1001       memmove (&group_of_layer[new_index + 1],
1002          &group_of_layer[new_index],
1003          (max_copper_layer + SILK_LAYER - new_index) * sizeof (int));
1004       max_copper_layer++;
1005       memset (lp, 0, sizeof (LayerType));
1006       lp->On = 1;
1007       lp->Name = strdup ("New Layer");
1008       lp->Color = Settings.LayerColor[new_index];
1009       lp->SelectedColor = Settings.LayerSelectedColor[new_index];
1010       for (l = 0; l < max_copper_layer; l++)
1011 	if (LayerStack[l] >= new_index)
1012 	  LayerStack[l]++;
1013       LayerStack[max_copper_layer - 1] = new_index;
1014 
1015       if (!Undoing ())
1016         ChangeBuriedViasAfterLayerCreate (new_index);
1017     }
1018   else if (new_index == -1)
1019     {
1020       /* Delete the layer at old_index */
1021       memmove (&PCB->Data->Layer[old_index],
1022 	       &PCB->Data->Layer[old_index + 1],
1023          (max_copper_layer + SILK_LAYER - old_index - 1) *
1024             sizeof (LayerType));
1025       memset (&PCB->Data->Layer[max_copper_layer + SILK_LAYER - 1],
1026               0, sizeof (LayerType));
1027       memmove (&group_of_layer[old_index],
1028 	       &group_of_layer[old_index + 1],
1029 	       (max_copper_layer + SILK_LAYER - old_index - 1) * sizeof (int));
1030       for (l = 0; l < max_copper_layer; l++)
1031 	if (LayerStack[l] == old_index)
1032 	  memmove (LayerStack + l,
1033 		   LayerStack + l + 1,
1034 		   (max_copper_layer - l - 1) * sizeof (LayerStack[0]));
1035       max_copper_layer--;
1036       for (l = 0; l < max_copper_layer; l++)
1037 	if (LayerStack[l] > old_index)
1038 	  LayerStack[l]--;
1039 
1040       if (!Undoing ())
1041         ChangeBuriedViasAfterLayerDelete (old_index);
1042     }
1043   else
1044     {
1045       /* Move an existing layer */
1046       memcpy (&saved_layer, &PCB->Data->Layer[old_index], sizeof (LayerType));
1047       saved_group = group_of_layer[old_index];
1048       if (old_index < new_index)
1049 	{
1050 	  memmove (&PCB->Data->Layer[old_index],
1051 		   &PCB->Data->Layer[old_index + 1],
1052 		   (new_index - old_index) * sizeof (LayerType));
1053 	  memmove (&group_of_layer[old_index],
1054 		   &group_of_layer[old_index + 1],
1055 		   (new_index - old_index) * sizeof (int));
1056 	}
1057       else
1058 	{
1059 	  memmove (&PCB->Data->Layer[new_index + 1],
1060 		   &PCB->Data->Layer[new_index],
1061 		   (old_index - new_index) * sizeof (LayerType));
1062 	  memmove (&group_of_layer[new_index + 1],
1063 		   &group_of_layer[new_index],
1064 		   (old_index - new_index) * sizeof (int));
1065 	}
1066       memcpy (&PCB->Data->Layer[new_index], &saved_layer, sizeof (LayerType));
1067       group_of_layer[new_index] = saved_group;
1068 
1069       if (!Undoing ())
1070          ChangeBuriedViasAfterLayerMove (old_index, new_index);
1071     }
1072 
1073   IncrementUndoSerialNumber ();
1074 
1075   move_all_thermals(old_index, new_index);
1076 
1077   for (g = 0; g < MAX_GROUP; g++)
1078     PCB->LayerGroups.Number[g] = 0;
1079   for (l = 0; l < max_copper_layer + SILK_LAYER; l++)
1080     {
1081       g = group_of_layer[l];
1082 
1083       /* XXX: Should this ever happen? */
1084       if (g < 0)
1085         continue;
1086 
1087       i = PCB->LayerGroups.Number[g]++;
1088       PCB->LayerGroups.Entries[g][i] = l;
1089     }
1090 
1091   for (g = 1; g < MAX_GROUP; g++)
1092     if (PCB->LayerGroups.Number[g - 1] == 0)
1093       {
1094 	memmove (&PCB->LayerGroups.Number[g - 1],
1095 		 &PCB->LayerGroups.Number[g],
1096 		 (MAX_GROUP - g) * sizeof (PCB->LayerGroups.Number[g]));
1097 	memmove (&PCB->LayerGroups.Entries[g - 1],
1098 		 &PCB->LayerGroups.Entries[g],
1099 		 (MAX_GROUP - g) * sizeof (PCB->LayerGroups.Entries[g]));
1100       }
1101 
1102   hid_action ("LayersChanged");
1103   gui->invalidate_all ();
1104   return 0;
1105 }
1106 
1107 /* --------------------------------------------------------------------------- */
1108 
1109 static const char movelayer_syntax[] = "MoveLayer(old,new)";
1110 
1111 static const char movelayer_help[] = "Moves/Creates/Deletes Layers.";
1112 
1113 /* %start-doc actions MoveLayer
1114 
1115 Moves a layer, creates a new layer, or deletes a layer.
1116 
1117 @table @code
1118 
1119 @item old
1120 The is the layer number to act upon.  Allowed values are:
1121 @table @code
1122 
1123 @item c
1124 Currently selected layer.
1125 
1126 @item -1
1127 Create a new layer.
1128 
1129 @item number
1130 An existing layer number.
1131 
1132 @end table
1133 
1134 @item new
1135 Specifies where to move the layer to.  Allowed values are:
1136 @table @code
1137 @item -1
1138 Deletes the layer.
1139 
1140 @item up
1141 Moves the layer up.
1142 
1143 @item down
1144 Moves the layer down.
1145 
1146 @item c
1147 Creates a new layer.
1148 
1149 @end table
1150 
1151 @end table
1152 
1153 %end-doc */
1154 
1155 int
MoveLayerAction(int argc,char ** argv,Coord x,Coord y)1156 MoveLayerAction (int argc, char **argv, Coord x, Coord y)
1157 {
1158   int old_index, new_index;
1159   int new_top = -1;
1160 
1161   if (argc != 2)
1162     {
1163       Message ("Usage; MoveLayer(old,new)");
1164       return 1;
1165     }
1166 
1167   if (strcmp (argv[0], "c") == 0)
1168     old_index = INDEXOFCURRENT;
1169   else
1170     old_index = atoi (argv[0]);
1171 
1172   if (strcmp (argv[1], "c") == 0)
1173     {
1174       new_index = INDEXOFCURRENT;
1175       if (new_index < 0)
1176 	new_index = 0;
1177     }
1178   else if (strcmp (argv[1], "up") == 0)
1179     {
1180       new_index = INDEXOFCURRENT - 1;
1181       if (new_index < 0)
1182 	return 1;
1183       new_top = new_index;
1184     }
1185   else if (strcmp (argv[1], "down") == 0)
1186     {
1187       new_index = INDEXOFCURRENT + 1;
1188       if (new_index >= max_copper_layer)
1189 	return 1;
1190       new_top = new_index;
1191     }
1192   else
1193     new_index = atoi (argv[1]);
1194 
1195   if (MoveLayer (old_index, new_index))
1196     return 1;
1197 
1198   if (new_index == -1)
1199     {
1200       new_top = old_index;
1201       if (new_top >= max_copper_layer)
1202 	new_top--;
1203       new_index = new_top;
1204     }
1205   if (old_index == -1)
1206     new_top = new_index;
1207 
1208   if (new_top != -1)
1209     ChangeGroupVisibility (new_index, 1, 1);
1210 
1211   return 0;
1212 }
1213 
1214 HID_Action move_action_list[] = {
1215   {"MoveLayer", 0, MoveLayerAction,
1216    movelayer_help, movelayer_syntax}
1217 };
1218 
1219 REGISTER_ACTIONS (move_action_list)
1220