(no commit message)
[geda-pcb/pcjc2.git] / src / move.c
blob9dcba90868713c98ad8c59b7c666abf39a1030bf
1 /*
2 * COPYRIGHT
4 * PCB, interactive printed circuit board design
5 * Copyright (C) 1994,1995,1996 Thomas Nau
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * Contact addresses for paper mail and Email:
22 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
23 * Thomas.Nau@rz.uni-ulm.de
28 /* functions used to move pins, elements ...
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
35 #include <setjmp.h>
36 #include <stdlib.h>
38 #include "global.h"
40 #include "create.h"
41 #include "crosshair.h"
42 #include "data.h"
43 #include "draw.h"
44 #include "error.h"
45 #include "misc.h"
46 #include "move.h"
47 #include "mymem.h"
48 #include "polygon.h"
49 #include "rtree.h"
50 #include "search.h"
51 #include "select.h"
52 #include "thermal.h"
53 #include "undo.h"
55 #ifdef HAVE_LIBDMALLOC
56 #include <dmalloc.h>
57 #endif
59 /* ---------------------------------------------------------------------------
60 * some local prototypes
62 static void *MoveElementName (ElementType *);
63 static void *MoveElement (ElementType *);
64 static void *MoveVia (PinType *);
65 static void *MoveLine (LayerType *, LineType *);
66 static void *MoveArc (LayerType *, ArcType *);
67 static void *MoveText (LayerType *, TextType *);
68 static void *MovePolygon (LayerType *, PolygonType *);
69 static void *MoveLinePoint (LayerType *, LineType *, PointType *);
70 static void *MovePolygonPoint (LayerType *, PolygonType *, PointType *);
71 static void *MoveLineToLayer (LayerType *, LineType *);
72 static void *MoveArcToLayer (LayerType *, ArcType *);
73 static void *MoveRatToLayer (RatType *);
74 static void *MoveTextToLayer (LayerType *, TextType *);
75 static void *MovePolygonToLayer (LayerType *, PolygonType *);
77 /* ---------------------------------------------------------------------------
78 * some local identifiers
80 static Coord DeltaX, DeltaY; /* used by local routines as offset */
81 static LayerType *Dest;
82 static bool MoreToCome;
83 static ObjectFunctionType MoveFunctions = {
84 MoveLine,
85 MoveText,
86 MovePolygon,
87 MoveVia,
88 MoveElement,
89 MoveElementName,
90 NULL,
91 NULL,
92 MoveLinePoint,
93 MovePolygonPoint,
94 MoveArc,
95 NULL
96 }, MoveToLayerFunctions =
99 MoveLineToLayer,
100 MoveTextToLayer,
101 MovePolygonToLayer,
102 NULL, NULL, NULL, NULL, NULL, NULL, NULL, MoveArcToLayer, MoveRatToLayer};
104 /* ---------------------------------------------------------------------------
105 * moves a element by +-X and +-Y
107 void
108 MoveElementLowLevel (DataType *Data, ElementType *Element,
109 Coord DX, Coord DY)
111 if (Data)
112 r_delete_entry (Data->element_tree, (BoxType *)Element);
113 ELEMENTLINE_LOOP (Element);
115 MOVE_LINE_LOWLEVEL (line, DX, DY);
117 END_LOOP;
118 PIN_LOOP (Element);
120 if (Data)
122 r_delete_entry (Data->pin_tree, (BoxType *)pin);
123 RestoreToPolygon (Data, PIN_TYPE, Element, pin);
125 MOVE_PIN_LOWLEVEL (pin, DX, DY);
126 if (Data)
128 r_insert_entry (Data->pin_tree, (BoxType *)pin, 0);
129 ClearFromPolygon (Data, PIN_TYPE, Element, pin);
132 END_LOOP;
133 PAD_LOOP (Element);
135 if (Data)
137 r_delete_entry (Data->pad_tree, (BoxType *)pad);
138 RestoreToPolygon (Data, PAD_TYPE, Element, pad);
140 MOVE_PAD_LOWLEVEL (pad, DX, DY);
141 if (Data)
143 r_insert_entry (Data->pad_tree, (BoxType *)pad, 0);
144 ClearFromPolygon (Data, PAD_TYPE, Element, pad);
147 END_LOOP;
148 ARC_LOOP (Element);
150 MOVE_ARC_LOWLEVEL (arc, DX, DY);
152 END_LOOP;
153 ELEMENTTEXT_LOOP (Element);
155 if (Data && Data->name_tree[n])
156 r_delete_entry (PCB->Data->name_tree[n], (BoxType *)text);
157 MOVE_TEXT_LOWLEVEL (text, DX, DY);
158 if (Data && Data->name_tree[n])
159 r_insert_entry (PCB->Data->name_tree[n], (BoxType *)text, 0);
161 END_LOOP;
162 MOVE_BOX_LOWLEVEL (&Element->BoundingBox, DX, DY);
163 MOVE_BOX_LOWLEVEL (&Element->VBox, DX, DY);
164 MOVE (Element->MarkX, Element->MarkY, DX, DY);
165 if (Data)
166 r_insert_entry (Data->element_tree, (BoxType *)Element, 0);
169 /* ----------------------------------------------------------------------
170 * moves all names of an element to a new position
172 static void *
173 MoveElementName (ElementType *Element)
175 if (PCB->ElementOn && (FRONT (Element) || PCB->InvisibleObjectsOn))
177 EraseElementName (Element);
178 ELEMENTTEXT_LOOP (Element);
180 if (PCB->Data->name_tree[n])
181 r_delete_entry (PCB->Data->name_tree[n], (BoxType *)text);
182 MOVE_TEXT_LOWLEVEL (text, DeltaX, DeltaY);
183 if (PCB->Data->name_tree[n])
184 r_insert_entry (PCB->Data->name_tree[n], (BoxType *)text, 0);
186 END_LOOP;
187 DrawElementName (Element);
188 Draw ();
190 else
192 ELEMENTTEXT_LOOP (Element);
194 if (PCB->Data->name_tree[n])
195 r_delete_entry (PCB->Data->name_tree[n], (BoxType *)text);
196 MOVE_TEXT_LOWLEVEL (text, DeltaX, DeltaY);
197 if (PCB->Data->name_tree[n])
198 r_insert_entry (PCB->Data->name_tree[n], (BoxType *)text, 0);
200 END_LOOP;
202 return (Element);
205 /* ---------------------------------------------------------------------------
206 * moves an element
208 static void *
209 MoveElement (ElementType *Element)
211 bool didDraw = false;
213 if (PCB->ElementOn && (FRONT (Element) || PCB->InvisibleObjectsOn))
215 EraseElement (Element);
216 MoveElementLowLevel (PCB->Data, Element, DeltaX, DeltaY);
217 DrawElementName (Element);
218 DrawElementPackage (Element);
219 didDraw = true;
221 else
223 if (PCB->PinOn)
224 EraseElementPinsAndPads (Element);
225 MoveElementLowLevel (PCB->Data, Element, DeltaX, DeltaY);
227 if (PCB->PinOn)
229 DrawElementPinsAndPads (Element);
230 didDraw = true;
232 if (didDraw)
233 Draw ();
234 return (Element);
237 /* ---------------------------------------------------------------------------
238 * moves a via
240 static void *
241 MoveVia (PinType *Via)
243 r_delete_entry (PCB->Data->via_tree, (BoxType *)Via);
244 RestoreToPolygon (PCB->Data, VIA_TYPE, Via, Via);
245 MOVE_VIA_LOWLEVEL (Via, DeltaX, DeltaY);
246 if (PCB->ViaOn)
247 EraseVia (Via);
248 r_insert_entry (PCB->Data->via_tree, (BoxType *)Via, 0);
249 ClearFromPolygon (PCB->Data, VIA_TYPE, Via, Via);
250 if (PCB->ViaOn)
252 DrawVia (Via);
253 Draw ();
255 return (Via);
258 /* ---------------------------------------------------------------------------
259 * moves a line
261 static void *
262 MoveLine (LayerType *Layer, LineType *Line)
264 if (Layer->On)
265 EraseLine (Line);
266 RestoreToPolygon (PCB->Data, LINE_TYPE, Layer, Line);
267 r_delete_entry (Layer->line_tree, (BoxType *)Line);
268 MOVE_LINE_LOWLEVEL (Line, DeltaX, DeltaY);
269 r_insert_entry (Layer->line_tree, (BoxType *)Line, 0);
270 ClearFromPolygon (PCB->Data, LINE_TYPE, Layer, Line);
271 if (Layer->On)
273 DrawLine (Layer, Line);
274 Draw ();
276 return (Line);
279 /* ---------------------------------------------------------------------------
280 * moves an arc
282 static void *
283 MoveArc (LayerType *Layer, ArcType *Arc)
285 RestoreToPolygon (PCB->Data, ARC_TYPE, Layer, Arc);
286 r_delete_entry (Layer->arc_tree, (BoxType *)Arc);
287 if (Layer->On)
289 EraseArc (Arc);
290 MOVE_ARC_LOWLEVEL (Arc, DeltaX, DeltaY);
291 DrawArc (Layer, Arc);
292 Draw ();
294 else
296 MOVE_ARC_LOWLEVEL (Arc, DeltaX, DeltaY);
298 r_insert_entry (Layer->arc_tree, (BoxType *)Arc, 0);
299 ClearFromPolygon (PCB->Data, ARC_TYPE, Layer, Arc);
300 return (Arc);
303 /* ---------------------------------------------------------------------------
304 * moves a text object
306 static void *
307 MoveText (LayerType *Layer, TextType *Text)
309 RestoreToPolygon (PCB->Data, TEXT_TYPE, Layer, Text);
310 r_delete_entry (Layer->text_tree, (BoxType *)Text);
311 if (Layer->On)
313 EraseText (Layer, Text);
314 MOVE_TEXT_LOWLEVEL (Text, DeltaX, DeltaY);
315 DrawText (Layer, Text);
316 Draw ();
318 else
319 MOVE_TEXT_LOWLEVEL (Text, DeltaX, DeltaY);
320 r_insert_entry (Layer->text_tree, (BoxType *)Text, 0);
321 ClearFromPolygon (PCB->Data, TEXT_TYPE, Layer, Text);
322 return (Text);
325 /* ---------------------------------------------------------------------------
326 * low level routine to move a polygon
328 void
329 MovePolygonLowLevel (PolygonType *Polygon, Coord DeltaX, Coord DeltaY)
331 POLYGONPOINT_LOOP (Polygon);
333 MOVE (point->X, point->Y, DeltaX, DeltaY);
335 END_LOOP;
336 MOVE_BOX_LOWLEVEL (&Polygon->BoundingBox, DeltaX, DeltaY);
339 /* ---------------------------------------------------------------------------
340 * moves a polygon
342 static void *
343 MovePolygon (LayerType *Layer, PolygonType *Polygon)
345 if (Layer->On)
347 ErasePolygon (Polygon);
349 r_delete_entry (Layer->polygon_tree, (BoxType *)Polygon);
350 MovePolygonLowLevel (Polygon, DeltaX, DeltaY);
351 r_insert_entry (Layer->polygon_tree, (BoxType *)Polygon, 0);
352 InitClip (PCB->Data, Layer, Polygon);
353 if (Layer->On)
355 DrawPolygon (Layer, Polygon);
356 Draw ();
358 return (Polygon);
361 /* ---------------------------------------------------------------------------
362 * moves one end of a line
364 static void *
365 MoveLinePoint (LayerType *Layer, LineType *Line, PointType *Point)
367 if (Layer)
369 if (Layer->On)
370 EraseLine (Line);
371 RestoreToPolygon (PCB->Data, LINE_TYPE, Layer, Line);
372 r_delete_entry (Layer->line_tree, &Line->BoundingBox);
373 MOVE (Point->X, Point->Y, DeltaX, DeltaY);
374 SetLineBoundingBox (Line);
375 r_insert_entry (Layer->line_tree, &Line->BoundingBox, 0);
376 ClearFromPolygon (PCB->Data, LINE_TYPE, Layer, Line);
377 if (Layer->On)
379 DrawLine (Layer, Line);
380 Draw ();
382 return (Line);
384 else /* must be a rat */
386 if (PCB->RatOn)
387 EraseRat ((RatType *) Line);
388 r_delete_entry (PCB->Data->rat_tree, &Line->BoundingBox);
389 MOVE (Point->X, Point->Y, DeltaX, DeltaY);
390 SetLineBoundingBox (Line);
391 r_insert_entry (PCB->Data->rat_tree, &Line->BoundingBox, 0);
392 if (PCB->RatOn)
394 DrawRat ((RatType *) Line);
395 Draw ();
397 return (Line);
401 /* ---------------------------------------------------------------------------
402 * moves a polygon-point
404 static void *
405 MovePolygonPoint (LayerType *Layer, PolygonType *Polygon,
406 PointType *Point)
408 if (Layer->On)
410 ErasePolygon (Polygon);
412 r_delete_entry (Layer->polygon_tree, (BoxType *)Polygon);
413 MOVE (Point->X, Point->Y, DeltaX, DeltaY);
414 SetPolygonBoundingBox (Polygon);
415 r_insert_entry (Layer->polygon_tree, (BoxType *)Polygon, 0);
416 RemoveExcessPolygonPoints (Layer, Polygon);
417 InitClip (PCB->Data, Layer, Polygon);
418 if (Layer->On)
420 DrawPolygon (Layer, Polygon);
421 Draw ();
423 return (Point);
426 /* ---------------------------------------------------------------------------
427 * moves a line between layers; lowlevel routines
429 static void *
430 MoveLineToLayerLowLevel (LayerType *Source, LineType *line,
431 LayerType *Destination)
433 r_delete_entry (Source->line_tree, (BoxType *)line);
435 Source->Line = g_list_remove (Source->Line, line);
436 Source->LineN --;
437 Destination->Line = g_list_append (Destination->Line, line);
438 Destination->LineN ++;
440 if (!Destination->line_tree)
441 Destination->line_tree = r_create_tree (NULL, 0, 0);
442 r_insert_entry (Destination->line_tree, (BoxType *)line, 0);
443 return line;
446 /* ---------------------------------------------------------------------------
447 * moves an arc between layers; lowlevel routines
449 static void *
450 MoveArcToLayerLowLevel (LayerType *Source, ArcType *arc,
451 LayerType *Destination)
453 r_delete_entry (Source->arc_tree, (BoxType *)arc);
455 Source->Arc = g_list_remove (Source->Arc, arc);
456 Source->ArcN --;
457 Destination->Arc = g_list_append (Destination->Arc, arc);
458 Destination->ArcN ++;
460 if (!Destination->arc_tree)
461 Destination->arc_tree = r_create_tree (NULL, 0, 0);
462 r_insert_entry (Destination->arc_tree, (BoxType *)arc, 0);
463 return arc;
467 /* ---------------------------------------------------------------------------
468 * moves an arc between layers
470 static void *
471 MoveArcToLayer (LayerType *Layer, ArcType *Arc)
473 ArcType *newone;
475 if (TEST_FLAG (LOCKFLAG, Arc))
477 Message (_("Sorry, the object is locked\n"));
478 return NULL;
480 if (Dest == Layer && Layer->On)
482 DrawArc (Layer, Arc);
483 Draw ();
485 if (((long int) Dest == -1) || Dest == Layer)
486 return (Arc);
487 AddObjectToMoveToLayerUndoList (ARC_TYPE, Layer, Arc, Arc);
488 RestoreToPolygon (PCB->Data, ARC_TYPE, Layer, Arc);
489 if (Layer->On)
490 EraseArc (Arc);
491 newone = (ArcType *)MoveArcToLayerLowLevel (Layer, Arc, Dest);
492 ClearFromPolygon (PCB->Data, ARC_TYPE, Dest, Arc);
493 if (Dest->On)
494 DrawArc (Dest, newone);
495 Draw ();
496 return (newone);
499 /* ---------------------------------------------------------------------------
500 * moves a line between layers
502 static void *
503 MoveRatToLayer (RatType *Rat)
505 LineType *newone;
506 //Coord X1 = Rat->Point1.X, Y1 = Rat->Point1.Y;
507 //Coord X1 = Rat->Point1.X, Y1 = Rat->Point1.Y;
508 // if VIAFLAG
509 // if we're on a pin, add a thermal
510 // else make a via and a wire, but 0-length wire not good
511 // else as before
513 newone = CreateNewLineOnLayer (Dest, Rat->Point1.X, Rat->Point1.Y,
514 Rat->Point2.X, Rat->Point2.Y,
515 Settings.LineThickness, 2 * Settings.Keepaway,
516 Rat->Flags);
517 if (TEST_FLAG (CLEARNEWFLAG, PCB))
518 SET_FLAG (CLEARLINEFLAG, newone);
519 if (!newone)
520 return (NULL);
521 AddObjectToCreateUndoList (LINE_TYPE, Dest, newone, newone);
522 if (PCB->RatOn)
523 EraseRat (Rat);
524 MoveObjectToRemoveUndoList (RATLINE_TYPE, Rat, Rat, Rat);
525 DrawLine (Dest, newone);
526 Draw ();
527 return (newone);
530 /* ---------------------------------------------------------------------------
531 * moves a line between layers
534 struct via_info
536 Coord X, Y;
537 jmp_buf env;
540 static int
541 moveline_callback (const BoxType * b, void *cl)
543 struct via_info *i = (struct via_info *) cl;
544 PinType *via;
546 if ((via =
547 CreateNewVia (PCB->Data, i->X, i->Y,
548 Settings.ViaThickness, 2 * Settings.Keepaway,
549 NOFLAG, Settings.ViaDrillingHole, NULL,
550 NoFlags ())) != NULL)
552 AddObjectToCreateUndoList (VIA_TYPE, via, via, via);
553 DrawVia (via);
555 longjmp (i->env, 1);
558 static void *
559 MoveLineToLayer (LayerType *Layer, LineType *Line)
561 struct via_info info;
562 BoxType sb;
563 LineType *newone;
564 void *ptr1, *ptr2, *ptr3;
566 if (TEST_FLAG (LOCKFLAG, Line))
568 Message (_("Sorry, the object is locked\n"));
569 return NULL;
571 if (Dest == Layer && Layer->On)
573 DrawLine (Layer, Line);
574 Draw ();
576 if (((long int) Dest == -1) || Dest == Layer)
577 return (Line);
579 AddObjectToMoveToLayerUndoList (LINE_TYPE, Layer, Line, Line);
580 if (Layer->On)
581 EraseLine (Line);
582 RestoreToPolygon (PCB->Data, LINE_TYPE, Layer, Line);
583 newone = (LineType *)MoveLineToLayerLowLevel (Layer, Line, Dest);
584 Line = NULL;
585 ClearFromPolygon (PCB->Data, LINE_TYPE, Dest, newone);
586 if (Dest->On)
587 DrawLine (Dest, newone);
588 Draw ();
589 if (!PCB->ViaOn || MoreToCome ||
590 GetLayerGroupNumberByPointer (Layer) ==
591 GetLayerGroupNumberByPointer (Dest) ||
592 TEST_SILK_LAYER(Layer) ||
593 TEST_SILK_LAYER(Dest))
594 return (newone);
595 /* consider via at Point1 */
596 sb.X1 = newone->Point1.X - newone->Thickness / 2;
597 sb.X2 = newone->Point1.X + newone->Thickness / 2;
598 sb.Y1 = newone->Point1.Y - newone->Thickness / 2;
599 sb.Y2 = newone->Point1.Y + newone->Thickness / 2;
600 if ((SearchObjectByLocation (PIN_TYPES, &ptr1, &ptr2, &ptr3,
601 newone->Point1.X, newone->Point1.Y,
602 Settings.ViaThickness / 2) == NO_TYPE))
604 info.X = newone->Point1.X;
605 info.Y = newone->Point1.Y;
606 if (setjmp (info.env) == 0)
607 r_search (Layer->line_tree, &sb, NULL, moveline_callback, &info);
609 /* consider via at Point2 */
610 sb.X1 = newone->Point2.X - newone->Thickness / 2;
611 sb.X2 = newone->Point2.X + newone->Thickness / 2;
612 sb.Y1 = newone->Point2.Y - newone->Thickness / 2;
613 sb.Y2 = newone->Point2.Y + newone->Thickness / 2;
614 if ((SearchObjectByLocation (PIN_TYPES, &ptr1, &ptr2, &ptr3,
615 newone->Point2.X, newone->Point2.Y,
616 Settings.ViaThickness / 2) == NO_TYPE))
618 info.X = newone->Point2.X;
619 info.Y = newone->Point2.Y;
620 if (setjmp (info.env) == 0)
621 r_search (Layer->line_tree, &sb, NULL, moveline_callback, &info);
623 Draw ();
624 return (newone);
627 /* ---------------------------------------------------------------------------
628 * moves a text object between layers; lowlevel routines
630 static void *
631 MoveTextToLayerLowLevel (LayerType *Source, TextType *text,
632 LayerType *Destination)
634 RestoreToPolygon (PCB->Data, TEXT_TYPE, Source, text);
635 r_delete_entry (Source->text_tree, (BoxType *)text);
637 Source->Text = g_list_remove (Source->Text, text);
638 Source->TextN --;
639 Destination->Text = g_list_append (Destination->Text, text);
640 Destination->TextN ++;
642 if (GetLayerGroupNumberBySide (BOTTOM_SIDE) ==
643 GetLayerGroupNumberByPointer (Destination))
644 SET_FLAG (ONSOLDERFLAG, text);
645 else
646 CLEAR_FLAG (ONSOLDERFLAG, text);
648 /* re-calculate the bounding box (it could be mirrored now) */
649 SetTextBoundingBox (&PCB->Font, text);
650 if (!Destination->text_tree)
651 Destination->text_tree = r_create_tree (NULL, 0, 0);
652 r_insert_entry (Destination->text_tree, (BoxType *)text, 0);
653 ClearFromPolygon (PCB->Data, TEXT_TYPE, Destination, text);
655 return text;
658 /* ---------------------------------------------------------------------------
659 * moves a text object between layers
661 static void *
662 MoveTextToLayer (LayerType *layer, TextType *text)
664 if (TEST_FLAG (LOCKFLAG, text))
666 Message (_("Sorry, the object is locked\n"));
667 return NULL;
669 if (Dest != layer)
671 AddObjectToMoveToLayerUndoList (TEXT_TYPE, layer, text, text);
672 if (layer->On)
673 EraseText (layer, text);
674 text = MoveTextToLayerLowLevel (layer, text, Dest);
675 if (Dest->On)
676 DrawText (Dest, text);
677 if (layer->On || Dest->On)
678 Draw ();
680 return text;
683 /* ---------------------------------------------------------------------------
684 * moves a polygon between layers; lowlevel routines
686 static void *
687 MovePolygonToLayerLowLevel (LayerType *Source, PolygonType *polygon,
688 LayerType *Destination)
690 r_delete_entry (Source->polygon_tree, (BoxType *)polygon);
692 Source->Polygon = g_list_remove (Source->Polygon, polygon);
693 Source->PolygonN --;
694 Destination->Polygon = g_list_append (Destination->Polygon, polygon);
695 Destination->PolygonN ++;
697 if (!Destination->polygon_tree)
698 Destination->polygon_tree = r_create_tree (NULL, 0, 0);
699 r_insert_entry (Destination->polygon_tree, (BoxType *)polygon, 0);
701 return polygon;
704 struct mptlc
706 Cardinal snum, dnum;
707 int type;
708 PolygonType *polygon;
709 } mptlc;
712 mptl_pin_callback (const BoxType *b, void *cl)
714 struct mptlc *d = (struct mptlc *) cl;
715 PinType *pin = (PinType *) b;
716 if (!TEST_THERM (d->snum, pin) || !
717 IsPointInPolygon (pin->X, pin->Y, pin->Thickness + pin->Clearance + 2,
718 d->polygon))
719 return 0;
720 if (d->type == PIN_TYPE)
721 AddObjectToFlagUndoList (PIN_TYPE, pin->Element, pin, pin);
722 else
723 AddObjectToFlagUndoList (VIA_TYPE, pin, pin, pin);
724 ASSIGN_THERM (d->dnum, GET_THERM (d->snum, pin), pin);
725 CLEAR_THERM (d->snum, pin);
726 return 1;
729 /* ---------------------------------------------------------------------------
730 * moves a polygon between layers
732 static void *
733 MovePolygonToLayer (LayerType *Layer, PolygonType *Polygon)
735 PolygonType *newone;
736 struct mptlc d;
738 if (TEST_FLAG (LOCKFLAG, Polygon))
740 Message (_("Sorry, the object is locked\n"));
741 return NULL;
743 if (((long int) Dest == -1) || (Layer == Dest))
744 return (Polygon);
745 AddObjectToMoveToLayerUndoList (POLYGON_TYPE, Layer, Polygon, Polygon);
746 if (Layer->On)
747 ErasePolygon (Polygon);
748 /* Move all of the thermals with the polygon */
749 d.snum = GetLayerNumber (PCB->Data, Layer);
750 d.dnum = GetLayerNumber (PCB->Data, Dest);
751 d.polygon = Polygon;
752 d.type = PIN_TYPE;
753 r_search (PCB->Data->pin_tree, &Polygon->BoundingBox, NULL, mptl_pin_callback, &d);
754 d.type = VIA_TYPE;
755 r_search (PCB->Data->via_tree, &Polygon->BoundingBox, NULL, mptl_pin_callback, &d);
756 newone = (struct polygon_st *)MovePolygonToLayerLowLevel (Layer, Polygon, Dest);
757 InitClip (PCB->Data, Dest, newone);
758 if (Dest->On)
760 DrawPolygon (Dest, newone);
761 Draw ();
763 return (newone);
766 /* ---------------------------------------------------------------------------
767 * moves the object identified by its data pointers and the type
768 * not we don't bump the undo serial number
770 void *
771 MoveObject (int Type, void *Ptr1, void *Ptr2, void *Ptr3, Coord DX, Coord DY)
773 void *result;
774 /* setup offset */
775 DeltaX = DX;
776 DeltaY = DY;
777 AddObjectToMoveUndoList (Type, Ptr1, Ptr2, Ptr3, DX, DY);
778 result = ObjectOperation (&MoveFunctions, Type, Ptr1, Ptr2, Ptr3);
779 return (result);
782 /* ---------------------------------------------------------------------------
783 * moves the object identified by its data pointers and the type
784 * as well as all attached rubberband lines
786 void *
787 MoveObjectAndRubberband (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
788 Coord DX, Coord DY)
790 RubberbandType *ptr;
791 void *ptr2;
793 /* setup offset */
794 DeltaX = DX;
795 DeltaY = DY;
797 /* move all the lines... and reset the counter */
798 ptr = Crosshair.AttachedObject.Rubberband;
799 while (Crosshair.AttachedObject.RubberbandN)
801 /* first clear any marks that we made in the line flags */
802 CLEAR_FLAG (RUBBERENDFLAG, ptr->Line);
803 /* only update undo list if an actual movement happened */
804 if (DX != 0 || DY != 0)
806 AddObjectToMoveUndoList (LINEPOINT_TYPE,
807 ptr->Layer, ptr->Line,
808 ptr->MovedPoint, DX, DY);
809 MoveLinePoint (ptr->Layer, ptr->Line, ptr->MovedPoint);
811 Crosshair.AttachedObject.RubberbandN--;
812 ptr++;
815 if (DX == 0 && DY == 0)
816 return (NULL);
818 AddObjectToMoveUndoList (Type, Ptr1, Ptr2, Ptr3, DX, DY);
819 ptr2 = ObjectOperation (&MoveFunctions, Type, Ptr1, Ptr2, Ptr3);
820 IncrementUndoSerialNumber ();
821 return (ptr2);
824 /* ---------------------------------------------------------------------------
825 * moves the object identified by its data pointers and the type
826 * to a new layer without changing it's position
828 void *
829 MoveObjectToLayer (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
830 LayerType *Target, bool enmasse)
832 void *result;
834 /* setup global identifiers */
835 Dest = Target;
836 MoreToCome = enmasse;
837 result = ObjectOperation (&MoveToLayerFunctions, Type, Ptr1, Ptr2, Ptr3);
838 IncrementUndoSerialNumber ();
839 return (result);
842 /* ---------------------------------------------------------------------------
843 * moves the selected objects to a new layer without changing their
844 * positions
846 bool
847 MoveSelectedObjectsToLayer (LayerType *Target)
849 bool changed;
851 /* setup global identifiers */
852 Dest = Target;
853 MoreToCome = true;
854 changed = SelectedOperation (&MoveToLayerFunctions, true, ALL_TYPES);
855 /* passing true to above operation causes Undoserial to auto-increment */
856 return (changed);
859 /* ---------------------------------------------------------------------------
860 * moves the selected layers to a new index in the layer list.
863 static void
864 move_one_thermal (int old_index, int new_index, PinType *pin)
866 int t1=0, i;
867 int oi=old_index, ni=new_index;
869 if (old_index != -1)
870 t1 = GET_THERM (old_index, pin);
872 if (oi == -1)
873 oi = MAX_LAYER-1; /* inserting a layer */
874 if (ni == -1)
875 ni = MAX_LAYER-1; /* deleting a layer */
877 if (oi < ni)
879 for (i=oi; i<ni; i++)
880 ASSIGN_THERM (i, GET_THERM (i+1, pin), pin);
882 else
884 for (i=oi; i>ni; i--)
885 ASSIGN_THERM (i, GET_THERM (i-1, pin), pin);
888 if (new_index != -1)
889 ASSIGN_THERM (new_index, t1, pin);
890 else
891 ASSIGN_THERM (ni, 0, pin);
894 static void
895 move_all_thermals (int old_index, int new_index)
897 VIA_LOOP (PCB->Data);
899 move_one_thermal (old_index, new_index, via);
901 END_LOOP;
903 ALLPIN_LOOP (PCB->Data);
905 move_one_thermal (old_index, new_index, pin);
907 ENDALL_LOOP;
910 static int
911 LastNormalLayerInSideGroup (int side, int layer)
913 int side_group = GetLayerGroupNumberBySide(side);
914 int lgroup = GetLayerGroupNumberByNumber(layer);
915 if (side_group == lgroup
916 && PCB->LayerGroups.Number[lgroup] == 2)
917 return 1;
918 return 0;
922 MoveLayer (int old_index, int new_index)
924 int group_of_layer[MAX_LAYER + 2], l, g, i;
925 LayerType saved_layer;
926 int saved_group;
928 AddLayerChangeToUndoList (old_index, new_index);
929 IncrementUndoSerialNumber ();
931 if (old_index < -1 || old_index >= max_copper_layer)
933 Message ("Invalid old layer %d for move: must be -1..%d\n",
934 old_index, max_copper_layer - 1);
935 return 1;
937 if (new_index < -1 || new_index > max_copper_layer || new_index >= MAX_LAYER)
939 Message ("Invalid new layer %d for move: must be -1..%d\n",
940 new_index, max_copper_layer);
941 return 1;
943 if (old_index == new_index)
944 return 0;
946 if (new_index == -1
947 && LastNormalLayerInSideGroup (TOP_SIDE, old_index))
949 gui->confirm_dialog ("You can't delete the last top-side layer\n", "Ok", NULL);
950 return 1;
953 if (new_index == -1
954 && LastNormalLayerInSideGroup (BOTTOM_SIDE, old_index))
956 gui->confirm_dialog ("You can't delete the last bottom-side layer\n", "Ok", NULL);
957 return 1;
960 for (l = 0; l < MAX_LAYER+2; l++)
961 group_of_layer[l] = -1;
963 for (g = 0; g < MAX_GROUP; g++)
964 for (i = 0; i < PCB->LayerGroups.Number[g]; i++)
965 group_of_layer[PCB->LayerGroups.Entries[g][i]] = g;
967 if (old_index == -1)
969 LayerType *lp;
970 if (max_copper_layer == MAX_LAYER)
972 Message ("No room for new layers\n");
973 return 1;
975 /* Create a new layer at new_index. */
976 lp = &PCB->Data->Layer[new_index];
977 memmove (&PCB->Data->Layer[new_index + 1],
978 &PCB->Data->Layer[new_index],
979 (max_copper_layer + 2 - new_index) * sizeof (LayerType));
980 memmove (&group_of_layer[new_index + 1],
981 &group_of_layer[new_index],
982 (max_copper_layer + 2 - new_index) * sizeof (int));
983 max_copper_layer++;
984 memset (lp, 0, sizeof (LayerType));
985 lp->On = 1;
986 lp->Name = strdup ("New Layer");
987 lp->Color = Settings.LayerColor[new_index];
988 lp->SelectedColor = Settings.LayerSelectedColor[new_index];
989 for (l = 0; l < max_copper_layer; l++)
990 if (LayerStack[l] >= new_index)
991 LayerStack[l]++;
992 LayerStack[max_copper_layer - 1] = new_index;
994 else if (new_index == -1)
996 /* Delete the layer at old_index */
997 memmove (&PCB->Data->Layer[old_index],
998 &PCB->Data->Layer[old_index + 1],
999 (max_copper_layer + 2 - old_index - 1) * sizeof (LayerType));
1000 memset (&PCB->Data->Layer[max_copper_layer + 2 - 1], 0, sizeof (LayerType));
1001 memmove (&group_of_layer[old_index],
1002 &group_of_layer[old_index + 1],
1003 (max_copper_layer + 2 - old_index - 1) * sizeof (int));
1004 for (l = 0; l < max_copper_layer; l++)
1005 if (LayerStack[l] == old_index)
1006 memmove (LayerStack + l,
1007 LayerStack + l + 1,
1008 (max_copper_layer - l - 1) * sizeof (LayerStack[0]));
1009 max_copper_layer--;
1010 for (l = 0; l < max_copper_layer; l++)
1011 if (LayerStack[l] > old_index)
1012 LayerStack[l]--;
1014 else
1016 /* Move an existing layer */
1017 memcpy (&saved_layer, &PCB->Data->Layer[old_index], sizeof (LayerType));
1018 saved_group = group_of_layer[old_index];
1019 if (old_index < new_index)
1021 memmove (&PCB->Data->Layer[old_index],
1022 &PCB->Data->Layer[old_index + 1],
1023 (new_index - old_index) * sizeof (LayerType));
1024 memmove (&group_of_layer[old_index],
1025 &group_of_layer[old_index + 1],
1026 (new_index - old_index) * sizeof (int));
1028 else
1030 memmove (&PCB->Data->Layer[new_index + 1],
1031 &PCB->Data->Layer[new_index],
1032 (old_index - new_index) * sizeof (LayerType));
1033 memmove (&group_of_layer[new_index + 1],
1034 &group_of_layer[new_index],
1035 (old_index - new_index) * sizeof (int));
1037 memcpy (&PCB->Data->Layer[new_index], &saved_layer, sizeof (LayerType));
1038 group_of_layer[new_index] = saved_group;
1041 move_all_thermals(old_index, new_index);
1043 for (g = 0; g < MAX_GROUP; g++)
1044 PCB->LayerGroups.Number[g] = 0;
1045 for (l = 0; l < max_copper_layer + 2; l++)
1047 g = group_of_layer[l];
1049 /* XXX: Should this ever happen? */
1050 if (g < 0)
1051 continue;
1053 i = PCB->LayerGroups.Number[g]++;
1054 PCB->LayerGroups.Entries[g][i] = l;
1057 for (g = 1; g < MAX_GROUP; g++)
1058 if (PCB->LayerGroups.Number[g - 1] == 0)
1060 memmove (&PCB->LayerGroups.Number[g - 1],
1061 &PCB->LayerGroups.Number[g],
1062 (MAX_GROUP - g) * sizeof (PCB->LayerGroups.Number[g]));
1063 memmove (&PCB->LayerGroups.Entries[g - 1],
1064 &PCB->LayerGroups.Entries[g],
1065 (MAX_GROUP - g) * sizeof (PCB->LayerGroups.Entries[g]));
1068 hid_action ("LayersChanged");
1069 gui->invalidate_all ();
1070 return 0;
1073 /* --------------------------------------------------------------------------- */
1075 static const char movelayer_syntax[] = "MoveLayer(old,new)";
1077 static const char movelayer_help[] = "Moves/Creates/Deletes Layers.";
1079 /* %start-doc actions MoveLayer
1081 Moves a layer, creates a new layer, or deletes a layer.
1083 @table @code
1085 @item old
1086 The is the layer number to act upon. Allowed values are:
1087 @table @code
1089 @item c
1090 Currently selected layer.
1092 @item -1
1093 Create a new layer.
1095 @item number
1096 An existing layer number.
1098 @end table
1100 @item new
1101 Specifies where to move the layer to. Allowed values are:
1102 @table @code
1103 @item -1
1104 Deletes the layer.
1106 @item up
1107 Moves the layer up.
1109 @item down
1110 Moves the layer down.
1112 @item c
1113 Creates a new layer.
1115 @end table
1117 @end table
1119 %end-doc */
1122 MoveLayerAction (int argc, char **argv, Coord x, Coord y)
1124 int old_index, new_index;
1125 int new_top = -1;
1127 if (argc != 2)
1129 Message ("Usage; MoveLayer(old,new)");
1130 return 1;
1133 if (strcmp (argv[0], "c") == 0)
1134 old_index = INDEXOFCURRENT;
1135 else
1136 old_index = atoi (argv[0]);
1138 if (strcmp (argv[1], "c") == 0)
1140 new_index = INDEXOFCURRENT;
1141 if (new_index < 0)
1142 new_index = 0;
1144 else if (strcmp (argv[1], "up") == 0)
1146 new_index = INDEXOFCURRENT - 1;
1147 if (new_index < 0)
1148 return 1;
1149 new_top = new_index;
1151 else if (strcmp (argv[1], "down") == 0)
1153 new_index = INDEXOFCURRENT + 1;
1154 if (new_index >= max_copper_layer)
1155 return 1;
1156 new_top = new_index;
1158 else
1159 new_index = atoi (argv[1]);
1161 if (MoveLayer (old_index, new_index))
1162 return 1;
1164 if (new_index == -1)
1166 new_top = old_index;
1167 if (new_top >= max_copper_layer)
1168 new_top--;
1169 new_index = new_top;
1171 if (old_index == -1)
1172 new_top = new_index;
1174 if (new_top != -1)
1175 ChangeGroupVisibility (new_index, 1, 1);
1177 return 0;
1180 HID_Action move_action_list[] = {
1181 {"MoveLayer", 0, MoveLayerAction,
1182 movelayer_help, movelayer_syntax}
1185 REGISTER_ACTIONS (move_action_list)