Add support for filling / thindrawing raw polygons to the HID interface
[geda-pcb/gde.git] / src / move.c
blob003c2e05517df222423f6137e952e4352abc9903
1 /* $Id$ */
3 /*
4 * COPYRIGHT
6 * PCB, interactive printed circuit board design
7 * Copyright (C) 1994,1995,1996 Thomas Nau
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 * Contact addresses for paper mail and Email:
24 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
25 * Thomas.Nau@rz.uni-ulm.de
30 /* functions used to move pins, elements ...
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
37 #include <setjmp.h>
38 #include <stdlib.h>
40 #include "global.h"
42 #include "create.h"
43 #include "crosshair.h"
44 #include "data.h"
45 #include "draw.h"
46 #include "error.h"
47 #include "misc.h"
48 #include "move.h"
49 #include "mymem.h"
50 #include "polygon.h"
51 #include "rtree.h"
52 #include "search.h"
53 #include "select.h"
54 #include "thermal.h"
55 #include "undo.h"
57 #ifdef HAVE_LIBDMALLOC
58 #include <dmalloc.h>
59 #endif
61 RCSID ("$Id$");
66 /* ---------------------------------------------------------------------------
67 * some local prototypes
69 static void *MoveElementName (ElementTypePtr);
70 static void *MoveElement (ElementTypePtr);
71 static void *MoveVia (PinTypePtr);
72 static void *MoveLine (LayerTypePtr, LineTypePtr);
73 static void *MoveArc (LayerTypePtr, ArcTypePtr);
74 static void *MoveText (LayerTypePtr, TextTypePtr);
75 static void *MovePolygon (LayerTypePtr, PolygonTypePtr);
76 static void *MoveLinePoint (LayerTypePtr, LineTypePtr, PointTypePtr);
77 static void *MovePolygonPoint (LayerTypePtr, PolygonTypePtr, PointTypePtr);
78 static void *MoveLineToLayer (LayerTypePtr, LineTypePtr);
79 static void *MoveArcToLayer (LayerTypePtr, ArcTypePtr);
80 static void *MoveRatToLayer (RatTypePtr);
81 static void *MoveTextToLayer (LayerTypePtr, TextTypePtr);
82 static void *MovePolygonToLayer (LayerTypePtr, PolygonTypePtr);
84 /* ---------------------------------------------------------------------------
85 * some local identifiers
87 static LocationType DeltaX, /* used by local routines as offset */
88 DeltaY;
89 static LayerTypePtr Dest;
90 static Boolean MoreToCome;
91 static ObjectFunctionType MoveFunctions = {
92 MoveLine,
93 MoveText,
94 MovePolygon,
95 MoveVia,
96 MoveElement,
97 MoveElementName,
98 NULL,
99 NULL,
100 MoveLinePoint,
101 MovePolygonPoint,
102 MoveArc,
103 NULL
104 }, MoveToLayerFunctions =
107 MoveLineToLayer,
108 MoveTextToLayer,
109 MovePolygonToLayer,
110 NULL, NULL, NULL, NULL, NULL, NULL, NULL, MoveArcToLayer, MoveRatToLayer};
112 /* ---------------------------------------------------------------------------
113 * moves a element by +-X and +-Y
115 void
116 MoveElementLowLevel (DataTypePtr Data, ElementTypePtr Element,
117 LocationType DX, LocationType DY)
119 if (Data)
120 r_delete_entry (Data->element_tree, (BoxType *) Element);
121 ELEMENTLINE_LOOP (Element);
123 MOVE_LINE_LOWLEVEL (line, DX, DY);
125 END_LOOP;
126 PIN_LOOP (Element);
128 if (Data)
130 r_delete_entry (Data->pin_tree, (BoxType *) pin);
131 RestoreToPolygon (Data, PIN_TYPE, Element, pin);
133 MOVE_PIN_LOWLEVEL (pin, DX, DY);
134 if (Data)
136 r_insert_entry (Data->pin_tree, (BoxType *) pin, 0);
137 ClearFromPolygon (Data, PIN_TYPE, Element, pin);
140 END_LOOP;
141 PAD_LOOP (Element);
143 if (Data)
145 r_delete_entry (Data->pad_tree, (BoxType *) pad);
146 RestoreToPolygon (Data, PAD_TYPE, Element, pad);
148 MOVE_PAD_LOWLEVEL (pad, DX, DY);
149 if (Data)
151 r_insert_entry (Data->pad_tree, (BoxType *) pad, 0);
152 ClearFromPolygon (Data, PAD_TYPE, Element, pad);
155 END_LOOP;
156 ARC_LOOP (Element);
158 MOVE_ARC_LOWLEVEL (arc, DX, DY);
160 END_LOOP;
161 ELEMENTTEXT_LOOP (Element);
163 if (Data && Data->name_tree[n])
164 r_delete_entry (PCB->Data->name_tree[n], (BoxType *) text);
165 MOVE_TEXT_LOWLEVEL (text, DX, DY);
166 if (Data && Data->name_tree[n])
167 r_insert_entry (PCB->Data->name_tree[n], (BoxType *) text, 0);
169 END_LOOP;
170 MOVE_BOX_LOWLEVEL (&Element->BoundingBox, DX, DY);
171 MOVE_BOX_LOWLEVEL (&Element->VBox, DX, DY);
172 MOVE (Element->MarkX, Element->MarkY, DX, DY);
173 if (Data)
174 r_insert_entry (Data->element_tree, (BoxType *) Element, 0);
177 /* ----------------------------------------------------------------------
178 * moves all names of an element to a new position
180 static void *
181 MoveElementName (ElementTypePtr Element)
183 if (PCB->ElementOn && (FRONT (Element) || PCB->InvisibleObjectsOn))
185 EraseElementName (Element);
186 ELEMENTTEXT_LOOP (Element);
188 if (PCB->Data->name_tree[n])
189 r_delete_entry (PCB->Data->name_tree[n], (BoxType *) text);
190 MOVE_TEXT_LOWLEVEL (text, DeltaX, DeltaY);
191 if (PCB->Data->name_tree[n])
192 r_insert_entry (PCB->Data->name_tree[n], (BoxType *) text, 0);
194 END_LOOP;
195 DrawElementName (Element, 0);
196 Draw ();
198 else
200 ELEMENTTEXT_LOOP (Element);
202 if (PCB->Data->name_tree[n])
203 r_delete_entry (PCB->Data->name_tree[n], (BoxType *) text);
204 MOVE_TEXT_LOWLEVEL (text, DeltaX, DeltaY);
205 if (PCB->Data->name_tree[n])
206 r_insert_entry (PCB->Data->name_tree[n], (BoxType *) text, 0);
208 END_LOOP;
210 return (Element);
213 /* ---------------------------------------------------------------------------
214 * moves an element
216 static void *
217 MoveElement (ElementTypePtr Element)
219 Boolean didDraw = False;
221 if (PCB->ElementOn && (FRONT (Element) || PCB->InvisibleObjectsOn))
223 EraseElement (Element);
224 MoveElementLowLevel (PCB->Data, Element, DeltaX, DeltaY);
225 DrawElementName (Element, 0);
226 DrawElementPackage (Element, 0);
227 didDraw = True;
229 else
231 if (PCB->PinOn)
232 EraseElementPinsAndPads (Element);
233 MoveElementLowLevel (PCB->Data, Element, DeltaX, DeltaY);
235 if (PCB->PinOn)
237 DrawElementPinsAndPads (Element, 0);
238 didDraw = True;
240 if (didDraw)
241 Draw ();
242 return (Element);
245 /* ---------------------------------------------------------------------------
246 * moves a via
248 static void *
249 MoveVia (PinTypePtr Via)
251 r_delete_entry (PCB->Data->via_tree, (BoxTypePtr) Via);
252 RestoreToPolygon (PCB->Data, VIA_TYPE, Via, Via);
253 MOVE_VIA_LOWLEVEL (Via, DeltaX, DeltaY);
254 if (PCB->ViaOn)
255 EraseVia (Via);
256 r_insert_entry (PCB->Data->via_tree, (BoxTypePtr) Via, 0);
257 ClearFromPolygon (PCB->Data, VIA_TYPE, Via, Via);
258 if (PCB->ViaOn)
260 DrawVia (Via, 0);
261 Draw ();
263 return (Via);
266 /* ---------------------------------------------------------------------------
267 * moves a line
269 static void *
270 MoveLine (LayerTypePtr Layer, LineTypePtr Line)
272 if (Layer->On)
273 EraseLine (Line);
274 RestoreToPolygon (PCB->Data, LINE_TYPE, Layer, Line);
275 r_delete_entry (Layer->line_tree, (BoxTypePtr) Line);
276 MOVE_LINE_LOWLEVEL (Line, DeltaX, DeltaY);
277 r_insert_entry (Layer->line_tree, (BoxTypePtr) Line, 0);
278 ClearFromPolygon (PCB->Data, LINE_TYPE, Layer, Line);
279 if (Layer->On)
281 DrawLine (Layer, Line, 0);
282 Draw ();
284 return (Line);
287 /* ---------------------------------------------------------------------------
288 * moves an arc
290 static void *
291 MoveArc (LayerTypePtr Layer, ArcTypePtr Arc)
293 RestoreToPolygon (PCB->Data, ARC_TYPE, Layer, Arc);
294 r_delete_entry (Layer->arc_tree, (BoxTypePtr) Arc);
295 if (Layer->On)
297 EraseArc (Arc);
298 MOVE_ARC_LOWLEVEL (Arc, DeltaX, DeltaY);
299 DrawArc (Layer, Arc, 0);
300 Draw ();
302 else
304 MOVE_ARC_LOWLEVEL (Arc, DeltaX, DeltaY);
306 r_insert_entry (Layer->arc_tree, (BoxTypePtr) Arc, 0);
307 ClearFromPolygon (PCB->Data, ARC_TYPE, Layer, Arc);
308 return (Arc);
311 /* ---------------------------------------------------------------------------
312 * moves a text object
314 static void *
315 MoveText (LayerTypePtr Layer, TextTypePtr Text)
317 RestoreToPolygon (PCB->Data, TEXT_TYPE, Layer, Text);
318 r_delete_entry (Layer->text_tree, (BoxTypePtr) Text);
319 if (Layer->On)
321 EraseText (Layer, Text);
322 MOVE_TEXT_LOWLEVEL (Text, DeltaX, DeltaY);
323 DrawText (Layer, Text, 0);
324 Draw ();
326 else
327 MOVE_TEXT_LOWLEVEL (Text, DeltaX, DeltaY);
328 r_insert_entry (Layer->text_tree, (BoxTypePtr) Text, 0);
329 ClearFromPolygon (PCB->Data, TEXT_TYPE, Layer, Text);
330 return (Text);
333 /* ---------------------------------------------------------------------------
334 * low level routine to move a polygon
336 void
337 MovePolygonLowLevel (PolygonTypePtr Polygon, LocationType DeltaX,
338 LocationType DeltaY)
340 POLYGONPOINT_LOOP (Polygon);
342 MOVE (point->X, point->Y, DeltaX, DeltaY);
344 END_LOOP;
345 MOVE_BOX_LOWLEVEL (&Polygon->BoundingBox, DeltaX, DeltaY);
348 /* ---------------------------------------------------------------------------
349 * moves a polygon
351 static void *
352 MovePolygon (LayerTypePtr Layer, PolygonTypePtr Polygon)
354 if (Layer->On)
356 ErasePolygon (Polygon);
358 r_delete_entry (Layer->polygon_tree, (BoxType *) Polygon);
359 MovePolygonLowLevel (Polygon, DeltaX, DeltaY);
360 r_insert_entry (Layer->polygon_tree, (BoxType *) Polygon, 0);
361 InitClip (PCB->Data, Layer, Polygon);
362 if (Layer->On)
364 DrawPolygon (Layer, Polygon, 0);
365 Draw ();
367 return (Polygon);
370 /* ---------------------------------------------------------------------------
371 * moves one end of a line
373 static void *
374 MoveLinePoint (LayerTypePtr Layer, LineTypePtr Line, PointTypePtr Point)
376 if (Layer)
378 if (Layer->On)
379 EraseLine (Line);
380 RestoreToPolygon (PCB->Data, LINE_TYPE, Layer, Line);
381 r_delete_entry (Layer->line_tree, &Line->BoundingBox);
382 MOVE (Point->X, Point->Y, DeltaX, DeltaY);
383 SetLineBoundingBox (Line);
384 r_insert_entry (Layer->line_tree, &Line->BoundingBox, 0);
385 ClearFromPolygon (PCB->Data, LINE_TYPE, Layer, Line);
386 if (Layer->On)
388 DrawLine (Layer, Line, 0);
389 Draw ();
391 return (Line);
393 else /* must be a rat */
395 if (PCB->RatOn)
396 EraseRat ((RatTypePtr) Line);
397 r_delete_entry (PCB->Data->rat_tree, &Line->BoundingBox);
398 MOVE (Point->X, Point->Y, DeltaX, DeltaY);
399 SetLineBoundingBox (Line);
400 r_insert_entry (PCB->Data->rat_tree, &Line->BoundingBox, 0);
401 if (PCB->RatOn)
403 DrawRat ((RatTypePtr) Line, 0);
404 Draw ();
406 return (Line);
410 /* ---------------------------------------------------------------------------
411 * moves a polygon-point
413 static void *
414 MovePolygonPoint (LayerTypePtr Layer, PolygonTypePtr Polygon,
415 PointTypePtr Point)
417 if (Layer->On)
419 ErasePolygon (Polygon);
421 r_delete_entry (Layer->polygon_tree, (BoxType *) Polygon);
422 MOVE (Point->X, Point->Y, DeltaX, DeltaY);
423 SetPolygonBoundingBox (Polygon);
424 r_insert_entry (Layer->polygon_tree, (BoxType *) Polygon, 0);
425 RemoveExcessPolygonPoints (Layer, Polygon);
426 InitClip (PCB->Data, Layer, Polygon);
427 if (Layer->On)
429 DrawPolygon (Layer, Polygon, 0);
430 Draw ();
432 return (Point);
435 /* ---------------------------------------------------------------------------
436 * moves a line between layers; lowlevel routines
438 void *
439 MoveLineToLayerLowLevel (LayerTypePtr Source, LineTypePtr Line,
440 LayerTypePtr Destination)
442 LineTypePtr new = GetLineMemory (Destination);
444 r_delete_entry (Source->line_tree, (BoxTypePtr) Line);
445 /* copy the data and remove it from the former layer */
446 *new = *Line;
447 *Line = Source->Line[--Source->LineN];
448 r_substitute (Source->line_tree, (BoxType *) & Source->Line[Source->LineN],
449 (BoxType *) Line);
450 memset (&Source->Line[Source->LineN], 0, sizeof (LineType));
451 if (!Destination->line_tree)
452 Destination->line_tree = r_create_tree (NULL, 0, 0);
453 r_insert_entry (Destination->line_tree, (BoxTypePtr) new, 0);
454 return (new);
457 /* ---------------------------------------------------------------------------
458 * moves an arc between layers; lowlevel routines
460 void *
461 MoveArcToLayerLowLevel (LayerTypePtr Source, ArcTypePtr Arc,
462 LayerTypePtr Destination)
464 ArcTypePtr new = GetArcMemory (Destination);
466 r_delete_entry (Source->arc_tree, (BoxTypePtr) Arc);
467 /* copy the data and remove it from the former layer */
468 *new = *Arc;
469 *Arc = Source->Arc[--Source->ArcN];
470 r_substitute (Source->arc_tree, (BoxType *) & Source->Arc[Source->ArcN],
471 (BoxType *) Arc);
472 memset (&Source->Arc[Source->ArcN], 0, sizeof (ArcType));
473 if (!Destination->arc_tree)
474 Destination->arc_tree = r_create_tree (NULL, 0, 0);
475 r_insert_entry (Destination->arc_tree, (BoxTypePtr) new, 0);
476 return (new);
480 /* ---------------------------------------------------------------------------
481 * moves an arc between layers
483 static void *
484 MoveArcToLayer (LayerTypePtr Layer, ArcTypePtr Arc)
486 ArcTypePtr new;
488 if (TEST_FLAG (LOCKFLAG, Arc))
490 Message (_("Sorry, the object is locked\n"));
491 return NULL;
493 if (Dest == Layer && Layer->On)
495 DrawArc (Layer, Arc, 0);
496 Draw ();
498 if (((long int) Dest == -1) || Dest == Layer)
499 return (Arc);
500 AddObjectToMoveToLayerUndoList (ARC_TYPE, Layer, Arc, Arc);
501 RestoreToPolygon (PCB->Data, ARC_TYPE, Layer, Arc);
502 if (Layer->On)
503 EraseArc (Arc);
504 new = MoveArcToLayerLowLevel (Layer, Arc, Dest);
505 ClearFromPolygon (PCB->Data, ARC_TYPE, Dest, Arc);
506 if (Dest->On)
507 DrawArc (Dest, new, 0);
508 Draw ();
509 return (new);
512 /* ---------------------------------------------------------------------------
513 * moves a line between layers
515 static void *
516 MoveRatToLayer (RatTypePtr Rat)
518 LineTypePtr new;
519 //LocationType X1 = Rat->Point1.X, Y1 = Rat->Point1.Y;
520 //LocationType X1 = Rat->Point1.X, Y1 = Rat->Point1.Y;
521 // if VIAFLAG
522 // if we're on a pin, add a thermal
523 // else make a via and a wire, but 0-length wire not good
524 // else as before
526 new = CreateNewLineOnLayer (Dest, Rat->Point1.X, Rat->Point1.Y,
527 Rat->Point2.X, Rat->Point2.Y,
528 Settings.LineThickness, 2 * Settings.Keepaway,
529 Rat->Flags);
530 if (TEST_FLAG (CLEARNEWFLAG, PCB))
531 SET_FLAG (CLEARLINEFLAG, new);
532 if (!new)
533 return (NULL);
534 AddObjectToCreateUndoList (LINE_TYPE, Dest, new, new);
535 if (PCB->RatOn)
536 EraseRat (Rat);
537 MoveObjectToRemoveUndoList (RATLINE_TYPE, Rat, Rat, Rat);
538 DrawLine (Dest, new, 0);
539 Draw ();
540 return (new);
543 /* ---------------------------------------------------------------------------
544 * moves a line between layers
547 struct via_info
549 LocationType X, Y;
550 jmp_buf env;
553 static int
554 moveline_callback (const BoxType * b, void *cl)
556 struct via_info *i = (struct via_info *) cl;
557 PinTypePtr via;
559 if ((via =
560 CreateNewVia (PCB->Data, i->X, i->Y,
561 Settings.ViaThickness, 2 * Settings.Keepaway,
562 NOFLAG, Settings.ViaDrillingHole, NULL,
563 NoFlags ())) != NULL)
565 AddObjectToCreateUndoList (VIA_TYPE, via, via, via);
566 DrawVia (via, 0);
568 longjmp (i->env, 1);
571 static void *
572 MoveLineToLayer (LayerTypePtr Layer, LineTypePtr Line)
574 struct via_info info;
575 BoxType sb;
576 LineTypePtr new;
577 void *ptr1, *ptr2, *ptr3;
579 if (TEST_FLAG (LOCKFLAG, Line))
581 Message (_("Sorry, the object is locked\n"));
582 return NULL;
584 if (Dest == Layer && Layer->On)
586 DrawLine (Layer, Line, 0);
587 Draw ();
589 if (((long int) Dest == -1) || Dest == Layer)
590 return (Line);
592 AddObjectToMoveToLayerUndoList (LINE_TYPE, Layer, Line, Line);
593 if (Layer->On)
594 EraseLine (Line);
595 RestoreToPolygon (PCB->Data, LINE_TYPE, Layer, Line);
596 new = MoveLineToLayerLowLevel (Layer, Line, Dest);
597 Line = NULL;
598 ClearFromPolygon (PCB->Data, LINE_TYPE, Dest, new);
599 if (Dest->On)
600 DrawLine (Dest, new, 0);
601 Draw ();
602 if (!PCB->ViaOn || MoreToCome ||
603 GetLayerGroupNumberByPointer (Layer) ==
604 GetLayerGroupNumberByPointer (Dest) ||
605 TEST_SILK_LAYER(Layer) ||
606 TEST_SILK_LAYER(Dest))
607 return (new);
608 /* consider via at Point1 */
609 sb.X1 = new->Point1.X - new->Thickness / 2;
610 sb.X2 = new->Point1.X + new->Thickness / 2;
611 sb.Y1 = new->Point1.Y - new->Thickness / 2;
612 sb.Y2 = new->Point1.Y + new->Thickness / 2;
613 if ((SearchObjectByLocation (PIN_TYPES, &ptr1, &ptr2, &ptr3,
614 new->Point1.X, new->Point1.Y,
615 Settings.ViaThickness / 2) == NO_TYPE))
617 info.X = new->Point1.X;
618 info.Y = new->Point1.Y;
619 if (setjmp (info.env) == 0)
620 r_search (Layer->line_tree, &sb, NULL, moveline_callback, &info);
622 /* consider via at Point2 */
623 sb.X1 = new->Point2.X - new->Thickness / 2;
624 sb.X2 = new->Point2.X + new->Thickness / 2;
625 sb.Y1 = new->Point2.Y - new->Thickness / 2;
626 sb.Y2 = new->Point2.Y + new->Thickness / 2;
627 if ((SearchObjectByLocation (PIN_TYPES, &ptr1, &ptr2, &ptr3,
628 new->Point2.X, new->Point2.Y,
629 Settings.ViaThickness / 2) == NO_TYPE))
631 info.X = new->Point2.X;
632 info.Y = new->Point2.Y;
633 if (setjmp (info.env) == 0)
634 r_search (Layer->line_tree, &sb, NULL, moveline_callback, &info);
636 Draw ();
637 return (new);
640 /* ---------------------------------------------------------------------------
641 * moves a text object between layers; lowlevel routines
643 void *
644 MoveTextToLayerLowLevel (LayerTypePtr Source, TextTypePtr Text,
645 LayerTypePtr Destination)
647 TextTypePtr new = GetTextMemory (Destination);
649 RestoreToPolygon (PCB->Data, TEXT_TYPE, Source, Text);
650 r_delete_entry (Source->text_tree, (BoxTypePtr) Text);
651 /* copy the data and remove it from the former layer */
652 *new = *Text;
653 *Text = Source->Text[--Source->TextN];
654 r_substitute (Source->text_tree, (BoxType *) & Source->Text[Source->TextN],
655 (BoxType *) Text);
656 memset (&Source->Text[Source->TextN], 0, sizeof (TextType));
657 if (GetLayerGroupNumberByNumber (MAX_LAYER + SOLDER_LAYER) ==
658 GetLayerGroupNumberByPointer (Destination))
659 SET_FLAG (ONSOLDERFLAG, new);
660 else
661 CLEAR_FLAG (ONSOLDERFLAG, new);
662 /* re-calculate the bounding box (it could be mirrored now) */
663 SetTextBoundingBox (&PCB->Font, new);
664 if (!Destination->text_tree)
665 Destination->text_tree = r_create_tree (NULL, 0, 0);
666 r_insert_entry (Destination->text_tree, (BoxTypePtr) new, 0);
667 ClearFromPolygon (PCB->Data, TEXT_TYPE, Destination, new);
668 return (new);
671 /* ---------------------------------------------------------------------------
672 * moves a text object between layers
674 static void *
675 MoveTextToLayer (LayerTypePtr Layer, TextTypePtr Text)
677 TextTypePtr new;
679 if (TEST_FLAG (LOCKFLAG, Text))
681 Message (_("Sorry, the object is locked\n"));
682 return NULL;
684 if (Dest != Layer)
686 AddObjectToMoveToLayerUndoList (TEXT_TYPE, Layer, Text, Text);
687 if (Layer->On)
688 EraseText (Layer, Text);
689 new = MoveTextToLayerLowLevel (Layer, Text, Dest);
690 if (Dest->On)
691 DrawText (Dest, new, 0);
692 if (Layer->On || Dest->On)
693 Draw ();
694 return (new);
696 return (Text);
699 /* ---------------------------------------------------------------------------
700 * moves a polygon between layers; lowlevel routines
702 void *
703 MovePolygonToLayerLowLevel (LayerTypePtr Source, PolygonTypePtr Polygon,
704 LayerTypePtr Destination)
706 PolygonTypePtr new = GetPolygonMemory (Destination);
708 r_delete_entry (Source->polygon_tree, (BoxType *) Polygon);
709 /* copy the data and remove it from the former layer */
710 *new = *Polygon;
711 *Polygon = Source->Polygon[--Source->PolygonN];
712 r_substitute (Source->polygon_tree,
713 (BoxType *) & Source->Polygon[Source->PolygonN],
714 (BoxType *) Polygon);
715 memset (&Source->Polygon[Source->PolygonN], 0, sizeof (PolygonType));
716 if (!Destination->polygon_tree)
717 Destination->polygon_tree = r_create_tree (NULL, 0, 0);
718 r_insert_entry (Destination->polygon_tree, (BoxType *) new, 0);
719 return (new);
722 struct mptlc
724 Cardinal snum, dnum;
725 int type;
726 PolygonTypePtr polygon;
727 } mptlc;
730 mptl_pin_callback (const BoxType *b, void *cl)
732 struct mptlc *d = (struct mptlc *) cl;
733 PinTypePtr pin = (PinTypePtr) b;
734 if (!TEST_THERM (d->snum, pin) || !
735 IsPointInPolygon (pin->X, pin->Y, pin->Thickness + pin->Clearance + 2,
736 d->polygon))
737 return 0;
738 if (d->type == PIN_TYPE)
739 AddObjectToFlagUndoList (PIN_TYPE, pin->Element, pin, pin);
740 else
741 AddObjectToFlagUndoList (VIA_TYPE, pin, pin, pin);
742 ASSIGN_THERM (d->dnum, GET_THERM (d->snum, pin), pin);
743 CLEAR_THERM (d->snum, pin);
744 return 1;
747 /* ---------------------------------------------------------------------------
748 * moves a polygon between layers
750 static void *
751 MovePolygonToLayer (LayerTypePtr Layer, PolygonTypePtr Polygon)
753 PolygonTypePtr new;
754 struct mptlc d;
756 if (TEST_FLAG (LOCKFLAG, Polygon))
758 Message (_("Sorry, the object is locked\n"));
759 return NULL;
761 if (((long int) Dest == -1) || (Layer == Dest))
762 return (Polygon);
763 AddObjectToMoveToLayerUndoList (POLYGON_TYPE, Layer, Polygon, Polygon);
764 if (Layer->On)
765 ErasePolygon (Polygon);
766 /* Move all of the thermals with the polygon */
767 d.snum = GetLayerNumber (PCB->Data, Layer);
768 d.dnum = GetLayerNumber (PCB->Data, Dest);
769 d.polygon = Polygon;
770 d.type = PIN_TYPE;
771 r_search (PCB->Data->pin_tree, &Polygon->BoundingBox, NULL, mptl_pin_callback, &d);
772 d.type = VIA_TYPE;
773 r_search (PCB->Data->via_tree, &Polygon->BoundingBox, NULL, mptl_pin_callback, &d);
774 new = MovePolygonToLayerLowLevel (Layer, Polygon, Dest);
775 InitClip (PCB->Data, Dest, new);
776 if (Dest->On)
778 DrawPolygon (Dest, new, 0);
779 Draw ();
781 return (new);
784 /* ---------------------------------------------------------------------------
785 * moves the object identified by its data pointers and the type
786 * not we don't bump the undo serial number
788 void *
789 MoveObject (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
790 LocationType DX, LocationType DY)
792 void *result;
793 /* setup offset */
794 DeltaX = DX;
795 DeltaY = DY;
796 AddObjectToMoveUndoList (Type, Ptr1, Ptr2, Ptr3, DX, DY);
797 result = ObjectOperation (&MoveFunctions, Type, Ptr1, Ptr2, Ptr3);
798 return (result);
801 /* ---------------------------------------------------------------------------
802 * moves the object identified by its data pointers and the type
803 * as well as all attached rubberband lines
805 void *
806 MoveObjectAndRubberband (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
807 LocationType DX, LocationType DY)
809 RubberbandTypePtr ptr;
810 void *ptr2;
812 /* setup offset */
813 DeltaX = DX;
814 DeltaY = DY;
815 if (DX == 0 && DY == 0)
816 return (NULL);
818 /* move all the lines... and reset the counter */
819 ptr = Crosshair.AttachedObject.Rubberband;
820 while (Crosshair.AttachedObject.RubberbandN)
822 /* first clear any marks that we made in the line flags */
823 CLEAR_FLAG (RUBBERENDFLAG, ptr->Line);
824 AddObjectToMoveUndoList (LINEPOINT_TYPE,
825 ptr->Layer, ptr->Line, ptr->MovedPoint, DX,
826 DY);
827 MoveLinePoint (ptr->Layer, ptr->Line, ptr->MovedPoint);
828 Crosshair.AttachedObject.RubberbandN--;
829 ptr++;
832 AddObjectToMoveUndoList (Type, Ptr1, Ptr2, Ptr3, DX, DY);
833 ptr2 = ObjectOperation (&MoveFunctions, Type, Ptr1, Ptr2, Ptr3);
834 IncrementUndoSerialNumber ();
835 return (ptr2);
838 /* ---------------------------------------------------------------------------
839 * moves the object identified by its data pointers and the type
840 * to a new layer without changing it's position
842 void *
843 MoveObjectToLayer (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
844 LayerTypePtr Target, Boolean enmasse)
846 void *result;
848 /* setup global identifiers */
849 Dest = Target;
850 MoreToCome = enmasse;
851 result = ObjectOperation (&MoveToLayerFunctions, Type, Ptr1, Ptr2, Ptr3);
852 IncrementUndoSerialNumber ();
853 return (result);
856 /* ---------------------------------------------------------------------------
857 * moves the selected objects to a new layer without changing their
858 * positions
860 Boolean
861 MoveSelectedObjectsToLayer (LayerTypePtr Target)
863 Boolean changed;
865 /* setup global identifiers */
866 Dest = Target;
867 MoreToCome = True;
868 changed = SelectedOperation (&MoveToLayerFunctions, True, ALL_TYPES);
869 /* passing True to above operation causes Undoserial to auto-increment */
870 return (changed);
873 /* ---------------------------------------------------------------------------
874 * moves the selected layers to a new index in the layer list.
877 static void
878 move_one_thermal (int old_index, int new_index, PinType *pin)
880 int t1=0, i;
881 int oi=old_index, ni=new_index;
883 if (old_index != -1)
884 t1 = GET_THERM (old_index, pin);
886 if (oi == -1)
887 oi = MAX_LAYER-1; /* inserting a layer */
888 if (ni == -1)
889 ni = MAX_LAYER-1; /* deleting a layer */
891 if (oi < ni)
893 for (i=oi; i<ni; i++)
894 ASSIGN_THERM (i, GET_THERM (i+1, pin), pin);
896 else
898 for (i=oi; i>ni; i--)
899 ASSIGN_THERM (i, GET_THERM (i-1, pin), pin);
902 if (new_index != -1)
903 ASSIGN_THERM (new_index, t1, pin);
904 else
905 ASSIGN_THERM (ni, 0, pin);
908 static void
909 move_all_thermals (int old_index, int new_index)
911 VIA_LOOP (PCB->Data);
913 move_one_thermal (old_index, new_index, via);
915 END_LOOP;
917 ALLPIN_LOOP (PCB->Data);
919 move_one_thermal (old_index, new_index, pin);
921 ENDALL_LOOP;
926 MoveLayer (int old_index, int new_index)
928 int groups[MAX_LAYER + 2], l, g;
929 LayerType saved_layer;
930 int saved_group;
932 AddLayerChangeToUndoList (old_index, new_index);
933 IncrementUndoSerialNumber ();
935 if (old_index < -1 || old_index >= max_layer)
937 Message ("Invalid old layer %d for move: must be -1..%d\n",
938 old_index, max_layer - 1);
939 return 1;
941 if (new_index < -1 || new_index > max_layer || new_index >= MAX_LAYER)
943 Message ("Invalid new layer %d for move: must be -1..%d\n",
944 new_index, max_layer);
945 return 1;
947 if (old_index == new_index)
948 return 0;
950 for (g = 0; g < MAX_LAYER; g++)
951 for (l = 0; l < PCB->LayerGroups.Number[g]; l++)
952 groups[PCB->LayerGroups.Entries[g][l]] = g;
954 if (old_index == -1)
956 LayerTypePtr lp;
957 if (max_layer == MAX_LAYER)
959 Message ("No room for new layers\n");
960 return 1;
962 /* Create a new layer at new_index. */
963 lp = &PCB->Data->Layer[new_index];
964 memmove (&PCB->Data->Layer[new_index + 1],
965 &PCB->Data->Layer[new_index],
966 (max_layer - new_index + 2) * sizeof (LayerType));
967 memmove (&groups[new_index + 1],
968 &groups[new_index],
969 (max_layer - new_index + 2) * sizeof (int));
970 max_layer++;
971 memset (lp, 0, sizeof (LayerType));
972 lp->On = 1;
973 lp->Name = MyStrdup ("New Layer", "MoveLayer");
974 lp->Color = Settings.LayerColor[new_index];
975 lp->SelectedColor = Settings.LayerSelectedColor[new_index];
976 for (l = 0; l < max_layer; l++)
977 if (LayerStack[l] >= new_index)
978 LayerStack[l]++;
979 LayerStack[max_layer - 1] = new_index;
981 else if (new_index == -1)
983 /* Delete the layer at old_index */
984 memmove (&PCB->Data->Layer[old_index],
985 &PCB->Data->Layer[old_index + 1],
986 (max_layer - old_index + 2 - 1) * sizeof (LayerType));
987 memset (&PCB->Data->Layer[max_layer + 1], 0, sizeof (LayerType));
988 memmove (&groups[old_index],
989 &groups[old_index + 1],
990 (max_layer - old_index + 2 - 1) * sizeof (int));
991 for (l = 0; l < max_layer; l++)
992 if (LayerStack[l] == old_index)
993 memmove (LayerStack + l,
994 LayerStack + l + 1,
995 (max_layer - l - 1) * sizeof (LayerStack[0]));
996 max_layer--;
997 for (l = 0; l < max_layer; l++)
998 if (LayerStack[l] > old_index)
999 LayerStack[l]--;
1001 else
1003 /* Move an existing layer */
1004 memcpy (&saved_layer, &PCB->Data->Layer[old_index], sizeof (LayerType));
1005 saved_group = groups[old_index];
1006 if (old_index < new_index)
1008 memmove (&PCB->Data->Layer[old_index],
1009 &PCB->Data->Layer[old_index + 1],
1010 (new_index - old_index) * sizeof (LayerType));
1011 memmove (&groups[old_index],
1012 &groups[old_index + 1],
1013 (new_index - old_index) * sizeof (int));
1015 else
1017 memmove (&PCB->Data->Layer[new_index + 1],
1018 &PCB->Data->Layer[new_index],
1019 (old_index - new_index) * sizeof (LayerType));
1020 memmove (&groups[new_index + 1],
1021 &groups[new_index],
1022 (old_index - new_index) * sizeof (int));
1024 memcpy (&PCB->Data->Layer[new_index], &saved_layer, sizeof (LayerType));
1025 groups[new_index] = saved_group;
1028 move_all_thermals(old_index, new_index);
1030 for (g = 0; g < MAX_LAYER; g++)
1031 PCB->LayerGroups.Number[g] = 0;
1032 for (l = 0; l < max_layer + 2; l++)
1034 int i;
1035 g = groups[l];
1036 i = PCB->LayerGroups.Number[g]++;
1037 PCB->LayerGroups.Entries[g][i] = l;
1040 for (g = 0; g < MAX_LAYER; g++)
1041 if (PCB->LayerGroups.Number[g] == 0)
1043 memmove (&PCB->LayerGroups.Number[g],
1044 &PCB->LayerGroups.Number[g + 1],
1045 (MAX_LAYER - g - 1) * sizeof (PCB->LayerGroups.Number[g]));
1046 memmove (&PCB->LayerGroups.Entries[g],
1047 &PCB->LayerGroups.Entries[g + 1],
1048 (MAX_LAYER - g - 1) * sizeof (PCB->LayerGroups.Entries[g]));
1051 hid_action ("LayersChanged");
1052 gui->invalidate_all ();
1053 return 0;
1056 /* --------------------------------------------------------------------------- */
1058 static const char movelayer_syntax[] = "MoveLayer(old,new)";
1060 static const char movelayer_help[] = "Moves/Creates/Deletes Layers";
1062 /* %start-doc actions MoveLayer
1064 Moves a layer, creates a new layer, or deletes a layer.
1066 @table @code
1068 @item old
1069 The is the layer number to act upon. Allowed values are:
1070 @table @code
1072 @item c
1073 Currently selected layer.
1075 @item -1
1076 Create a new layer.
1078 @item number
1079 An existing layer number.
1081 @end table
1083 @item new
1084 Specifies where to move the layer to. Allowed values are:
1085 @table @code
1086 @item -1
1087 Deletes the layer.
1089 @item up
1090 Moves the layer up.
1092 @item down
1093 Moves the layer down.
1095 @item c
1096 Creates a new layer.
1098 @end table
1100 @end table
1102 %end-doc */
1105 MoveLayerAction (int argc, char **argv, int x, int y)
1107 int old_index, new_index;
1108 int new_top = -1;
1110 if (argc != 2)
1112 Message ("Usage; MoveLayer(old,new)");
1113 return 1;
1116 if (strcmp (argv[0], "c") == 0)
1117 old_index = INDEXOFCURRENT;
1118 else
1119 old_index = atoi (argv[0]);
1121 if (strcmp (argv[1], "c") == 0)
1123 new_index = INDEXOFCURRENT;
1124 if (new_index < 0)
1125 new_index = 0;
1127 else if (strcmp (argv[1], "up") == 0)
1129 new_index = INDEXOFCURRENT - 1;
1130 if (new_index < 0)
1131 return 1;
1132 new_top = new_index;
1134 else if (strcmp (argv[1], "down") == 0)
1136 new_index = INDEXOFCURRENT + 1;
1137 if (new_index >= max_layer)
1138 return 1;
1139 new_top = new_index;
1141 else
1142 new_index = atoi (argv[1]);
1144 if (MoveLayer (old_index, new_index))
1145 return 1;
1147 if (new_index == -1)
1149 new_top = old_index;
1150 if (new_top >= max_layer)
1151 new_top--;
1152 new_index = new_top;
1154 if (old_index == -1)
1155 new_top = new_index;
1157 if (new_top != -1)
1158 ChangeGroupVisibility (new_index, 1, 1);
1160 return 0;
1163 HID_Action move_action_list[] = {
1164 {"MoveLayer", 0, MoveLayerAction,
1165 movelayer_help, movelayer_syntax}
1168 REGISTER_ACTIONS (move_action_list)