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