/* $Id: move.c,v 1.2 2006/01/16 03:34:26 dj Exp $ */ /* * COPYRIGHT * * PCB, interactive printed circuit board design * Copyright (C) 1994,1995,1996 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Contact addresses for paper mail and Email: * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * Thomas.Nau@rz.uni-ulm.de * */ /* functions used to move pins, elements ... */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "global.h" #include "create.h" #include "crosshair.h" #include "data.h" #include "draw.h" #include "error.h" #include "misc.h" #include "move.h" #include "mymem.h" #include "polygon.h" #include "rtree.h" #include "search.h" #include "select.h" #include "undo.h" #ifdef HAVE_LIBDMALLOC #include #endif RCSID("$Id: move.c,v 1.2 2006/01/16 03:34:26 dj Exp $"); /* --------------------------------------------------------------------------- * some local prototypes */ static void *MoveElementName (ElementTypePtr); static void *MoveElement (ElementTypePtr); static void *MoveVia (PinTypePtr); static void *MoveLine (LayerTypePtr, LineTypePtr); static void *MoveArc (LayerTypePtr, ArcTypePtr); static void *MoveText (LayerTypePtr, TextTypePtr); static void *MovePolygon (LayerTypePtr, PolygonTypePtr); static void *MoveLinePoint (LayerTypePtr, LineTypePtr, PointTypePtr); static void *MovePolygonPoint (LayerTypePtr, PolygonTypePtr, PointTypePtr); static void *MoveLineToLayer (LayerTypePtr, LineTypePtr); static void *MoveArcToLayer (LayerTypePtr, ArcTypePtr); static void *MoveRatToLayer (RatTypePtr); static void *MoveTextToLayer (LayerTypePtr, TextTypePtr); static void *MovePolygonToLayer (LayerTypePtr, PolygonTypePtr); /* --------------------------------------------------------------------------- * some local identifiers */ static LocationType DeltaX, /* used by local routines as offset */ DeltaY; static LayerTypePtr Dest; static Boolean MoreToCome; static ObjectFunctionType MoveFunctions = { MoveLine, MoveText, MovePolygon, MoveVia, MoveElement, MoveElementName, NULL, NULL, MoveLinePoint, MovePolygonPoint, MoveArc, NULL }, MoveToLayerFunctions = { MoveLineToLayer, MoveTextToLayer, MovePolygonToLayer, NULL, NULL, NULL, NULL, NULL, NULL, NULL, MoveArcToLayer, MoveRatToLayer}; /* --------------------------------------------------------------------------- * moves a element by +-X and +-Y */ void MoveElementLowLevel (DataTypePtr Data, ElementTypePtr Element, LocationType DX, LocationType DY) { if (Data) r_delete_entry (Data->element_tree, (BoxType *) Element); ELEMENTLINE_LOOP (Element); { MOVE_LINE_LOWLEVEL (line, DX, DY); } END_LOOP; PIN_LOOP (Element); { if (Data) r_delete_entry (Data->pin_tree, (BoxType *) pin); MOVE_PIN_LOWLEVEL (pin, DX, DY); if (Data) r_insert_entry (Data->pin_tree, (BoxType *) pin, 0); } END_LOOP; PAD_LOOP (Element); { if (Data) r_delete_entry (Data->pad_tree, (BoxType *) pad); MOVE_PAD_LOWLEVEL (pad, DX, DY); if (Data) r_insert_entry (Data->pad_tree, (BoxType *) pad, 0); } END_LOOP; ARC_LOOP (Element); { MOVE_ARC_LOWLEVEL (arc, DX, DY); } END_LOOP; ELEMENTTEXT_LOOP (Element); { if (Data && Data->name_tree[n]) r_delete_entry (PCB->Data->name_tree[n], (BoxType *)text); MOVE_TEXT_LOWLEVEL (text, DX, DY); if (Data && Data->name_tree[n]) r_insert_entry (PCB->Data->name_tree[n], (BoxType *)text, 0); } END_LOOP; MOVE_BOX_LOWLEVEL (&Element->BoundingBox, DX, DY); MOVE_BOX_LOWLEVEL (&Element->VBox, DX, DY); MOVE (Element->MarkX, Element->MarkY, DX, DY); if (Data) r_insert_entry (Data->element_tree, (BoxType *) Element, 0); } /* ---------------------------------------------------------------------- * moves all names of an element to a new position */ static void * MoveElementName (ElementTypePtr Element) { if (PCB->ElementOn && (FRONT (Element) || PCB->InvisibleObjectsOn)) { EraseElementName (Element); ELEMENTTEXT_LOOP (Element); { if (PCB->Data->name_tree[n]) r_delete_entry (PCB->Data->name_tree[n], (BoxType *)text); MOVE_TEXT_LOWLEVEL (text, DeltaX, DeltaY); if (PCB->Data->name_tree[n]) r_insert_entry (PCB->Data->name_tree[n], (BoxType *)text, 0); } END_LOOP; DrawElementName (Element, 0); Draw (); } else { ELEMENTTEXT_LOOP (Element); { if (PCB->Data->name_tree[n]) r_delete_entry (PCB->Data->name_tree[n], (BoxType *)text); MOVE_TEXT_LOWLEVEL (text, DeltaX, DeltaY); if (PCB->Data->name_tree[n]) r_insert_entry (PCB->Data->name_tree[n], (BoxType *)text, 0); } END_LOOP; } return (Element); } /* --------------------------------------------------------------------------- * moves an element */ static void * MoveElement (ElementTypePtr Element) { Boolean didDraw = False; if (PCB->ElementOn && (FRONT (Element) || PCB->InvisibleObjectsOn)) { EraseElement (Element); MoveElementLowLevel (PCB->Data, Element, DeltaX, DeltaY); DrawElementName (Element, 0); DrawElementPackage (Element, 0); didDraw = True; } else { if (PCB->PinOn) EraseElementPinsAndPads (Element); MoveElementLowLevel (PCB->Data, Element, DeltaX, DeltaY); } UpdatePIPFlags (NULL, Element, NULL, True); if (PCB->PinOn) { DrawElementPinsAndPads (Element, 0); didDraw = True; } if (didDraw) Draw (); return (Element); } /* --------------------------------------------------------------------------- * moves a via */ static void * MoveVia (PinTypePtr Via) { r_delete_entry (PCB->Data->via_tree, (BoxTypePtr) Via); if (PCB->ViaOn) { EraseVia (Via); MOVE_VIA_LOWLEVEL (Via, DeltaX, DeltaY); } else MOVE_VIA_LOWLEVEL (Via, DeltaX, DeltaY); UpdatePIPFlags (Via, (ElementTypePtr) Via, NULL, True); r_insert_entry (PCB->Data->via_tree, (BoxTypePtr) Via, 0); if (PCB->ViaOn) { DrawVia (Via, 0); Draw (); } return (Via); } /* --------------------------------------------------------------------------- * moves a line */ static void * MoveLine (LayerTypePtr Layer, LineTypePtr Line) { r_delete_entry (Layer->line_tree, (BoxTypePtr) Line); if (Layer->On) { EraseLine (Line); MOVE_LINE_LOWLEVEL (Line, DeltaX, DeltaY); DrawLine (Layer, Line, 0); Draw (); } else MOVE_LINE_LOWLEVEL (Line, DeltaX, DeltaY); r_insert_entry (Layer->line_tree, (BoxTypePtr) Line, 0); return (Line); } /* --------------------------------------------------------------------------- * moves an arc */ static void * MoveArc (LayerTypePtr Layer, ArcTypePtr Arc) { r_delete_entry (Layer->arc_tree, (BoxTypePtr) Arc); if (Layer->On) { EraseArc (Arc); MOVE_ARC_LOWLEVEL (Arc, DeltaX, DeltaY); DrawArc (Layer, Arc, 0); Draw (); } else { MOVE_ARC_LOWLEVEL (Arc, DeltaX, DeltaY); } r_insert_entry (Layer->arc_tree, (BoxTypePtr) Arc, 0); return (Arc); } /* --------------------------------------------------------------------------- * moves a text object */ static void * MoveText (LayerTypePtr Layer, TextTypePtr Text) { r_delete_entry (Layer->text_tree, (BoxTypePtr) Text); if (Layer->On) { EraseText (Text); MOVE_TEXT_LOWLEVEL (Text, DeltaX, DeltaY); DrawText (Layer, Text, 0); Draw (); } else MOVE_TEXT_LOWLEVEL (Text, DeltaX, DeltaY); r_insert_entry (Layer->text_tree, (BoxTypePtr) Text, 0); return (Text); } /* --------------------------------------------------------------------------- * low level routine to move a polygon */ void MovePolygonLowLevel (PolygonTypePtr Polygon, LocationType DeltaX, LocationType DeltaY) { POLYGONPOINT_LOOP (Polygon); { MOVE (point->X, point->Y, DeltaX, DeltaY); } END_LOOP; MOVE_BOX_LOWLEVEL (&Polygon->BoundingBox, DeltaX, DeltaY); } /* --------------------------------------------------------------------------- * moves a polygon */ static void * MovePolygon (LayerTypePtr Layer, PolygonTypePtr Polygon) { if (Layer->On) { ErasePolygon (Polygon); } r_delete_entry (Layer->polygon_tree, (BoxType *) Polygon); MovePolygonLowLevel (Polygon, DeltaX, DeltaY); r_insert_entry (Layer->polygon_tree, (BoxType *) Polygon, 0); UpdatePIPFlags (NULL, NULL, Layer, True); if (Layer->On) { DrawPolygon (Layer, Polygon, 0); Draw (); } return (Polygon); } /* --------------------------------------------------------------------------- * moves one end of a line */ static void * MoveLinePoint (LayerTypePtr Layer, LineTypePtr Line, PointTypePtr Point) { if (Layer) { if (Layer->On) EraseLine (Line); r_delete_entry (Layer->line_tree, &Line->BoundingBox); MOVE (Point->X, Point->Y, DeltaX, DeltaY); SetLineBoundingBox (Line); r_insert_entry (Layer->line_tree, &Line->BoundingBox, 0); if (Layer->On) { DrawLine (Layer, Line, 0); Draw (); } return (Line); } else /* must be a rat */ { if (PCB->RatOn) EraseRat ((RatTypePtr) Line); r_delete_entry (PCB->Data->rat_tree, &Line->BoundingBox); MOVE (Point->X, Point->Y, DeltaX, DeltaY); SetLineBoundingBox (Line); r_insert_entry (PCB->Data->rat_tree, &Line->BoundingBox, 0); if (PCB->RatOn) { DrawRat ((RatTypePtr) Line, 0); Draw (); } return (Line); } } /* --------------------------------------------------------------------------- * moves a polygon-point */ static void * MovePolygonPoint (LayerTypePtr Layer, PolygonTypePtr Polygon, PointTypePtr Point) { if (Layer->On) { ErasePolygon (Polygon); } r_delete_entry (Layer->polygon_tree, (BoxType *) Polygon); MOVE (Point->X, Point->Y, DeltaX, DeltaY); SetPolygonBoundingBox (Polygon); r_insert_entry (Layer->polygon_tree, (BoxType *) Polygon, 0); RemoveExcessPolygonPoints (Layer, Polygon); UpdatePIPFlags (NULL, NULL, Layer, True); if (Layer->On) { DrawPolygon (Layer, Polygon, 0); Draw (); } return (Point); } /* --------------------------------------------------------------------------- * moves a line between layers; lowlevel routines */ void * MoveLineToLayerLowLevel (LayerTypePtr Source, LineTypePtr Line, LayerTypePtr Destination) { LineTypePtr new = GetLineMemory (Destination); r_delete_entry (Source->line_tree, (BoxTypePtr) Line); /* copy the data and remove it from the former layer */ *new = *Line; *Line = Source->Line[--Source->LineN]; r_substitute (Source->line_tree, (BoxType *) & Source->Line[Source->LineN], (BoxType *) Line); memset (&Source->Line[Source->LineN], 0, sizeof (LineType)); if (!Destination->line_tree) Destination->line_tree = r_create_tree (NULL, 0, 0); r_insert_entry (Destination->line_tree, (BoxTypePtr) new, 0); return (new); } /* --------------------------------------------------------------------------- * moves an arc between layers; lowlevel routines */ void * MoveArcToLayerLowLevel (LayerTypePtr Source, ArcTypePtr Arc, LayerTypePtr Destination) { ArcTypePtr new = GetArcMemory (Destination); r_delete_entry (Source->arc_tree, (BoxTypePtr) Arc); /* copy the data and remove it from the former layer */ *new = *Arc; *Arc = Source->Arc[--Source->ArcN]; r_substitute (Source->arc_tree, (BoxType *) & Source->Arc[Source->ArcN], (BoxType *) Arc); memset (&Source->Arc[Source->ArcN], 0, sizeof (ArcType)); if (!Destination->arc_tree) Destination->arc_tree = r_create_tree (NULL, 0, 0); r_insert_entry (Destination->arc_tree, (BoxTypePtr) new, 0); return (new); } /* --------------------------------------------------------------------------- * moves an arc between layers */ static void * MoveArcToLayer (LayerTypePtr Layer, ArcTypePtr Arc) { ArcTypePtr new; if (TEST_FLAG (LOCKFLAG, Arc)) { Message (_("Sorry, the object is locked\n")); return NULL; } if (Dest == Layer && Layer->On) { DrawArc (Layer, Arc, 0); Draw (); } if (((long int) Dest == -1) || Dest == Layer) return (Arc); AddObjectToMoveToLayerUndoList (ARC_TYPE, Layer, Arc, Arc); if (Layer->On) EraseArc (Arc); new = MoveArcToLayerLowLevel (Layer, Arc, Dest); if (Dest->On) DrawArc (Dest, new, 0); Draw (); return (new); } /* --------------------------------------------------------------------------- * moves a line between layers */ static void * MoveRatToLayer (RatTypePtr Rat) { LineTypePtr new; new = CreateNewLineOnLayer (Dest, Rat->Point1.X, Rat->Point1.Y, Rat->Point2.X, Rat->Point2.Y, Settings.LineThickness, 2 * Settings.Keepaway, Rat->Flags); if (TEST_FLAG (CLEARNEWFLAG, PCB)) SET_FLAG (CLEARLINEFLAG, new); if (!new) return (NULL); AddObjectToCreateUndoList (LINE_TYPE, Dest, new, new); if (PCB->RatOn) EraseRat (Rat); MoveObjectToRemoveUndoList (RATLINE_TYPE, Rat, Rat, Rat); DrawLine (Dest, new, 0); Draw (); return (new); } /* --------------------------------------------------------------------------- * moves a line between layers */ struct via_info { LocationType X, Y; jmp_buf env; }; static int moveline_callback (const BoxType * b, void *cl) { struct via_info *i = (struct via_info *) cl; PinTypePtr via; if ((via = CreateNewVia (PCB->Data, i->X, i->Y, Settings.ViaThickness, 2 * Settings.Keepaway, NOFLAG, Settings.ViaDrillingHole, NULL, NoFlags())) != NULL) { UpdatePIPFlags (via, (ElementTypePtr) via, NULL, False); AddObjectToCreateUndoList (VIA_TYPE, via, via, via); DrawVia (via, 0); } longjmp (i->env, 1); } static void * MoveLineToLayer (LayerTypePtr Layer, LineTypePtr Line) { struct via_info info; BoxType sb; LineTypePtr new; void *ptr1, *ptr2, *ptr3; if (TEST_FLAG (LOCKFLAG, Line)) { Message (_("Sorry, the object is locked\n")); return NULL; } if (Dest == Layer && Layer->On) { DrawLine (Layer, Line, 0); Draw (); } if (((long int) Dest == -1) || Dest == Layer) return (Line); AddObjectToMoveToLayerUndoList (LINE_TYPE, Layer, Line, Line); if (Layer->On) EraseLine (Line); new = MoveLineToLayerLowLevel (Layer, Line, Dest); if (Dest->On) DrawLine (Dest, new, 0); Draw (); if (!PCB->ViaOn || MoreToCome || GetLayerGroupNumberByPointer (Layer) == GetLayerGroupNumberByPointer (Dest)) return (new); /* consider via at Point1 */ sb.X1 = new->Point1.X - new->Thickness / 2; sb.X2 = new->Point1.X + new->Thickness / 2; sb.Y1 = new->Point1.Y - new->Thickness / 2; sb.Y2 = new->Point1.Y + new->Thickness / 2; if ((SearchObjectByLocation (PIN_TYPES, &ptr1, &ptr2, &ptr3, new->Point1.X, new->Point1.Y, Settings.ViaThickness / 2) == NO_TYPE)) { info.X = new->Point1.X; info.Y = new->Point1.Y; if (setjmp (info.env) == 0) r_search (Layer->line_tree, &sb, NULL, moveline_callback, &info); } /* consider via at Point2 */ sb.X1 = new->Point2.X - new->Thickness / 2; sb.X2 = new->Point2.X + new->Thickness / 2; sb.Y1 = new->Point2.Y - new->Thickness / 2; sb.Y2 = new->Point2.Y + new->Thickness / 2; if ((SearchObjectByLocation (PIN_TYPES, &ptr1, &ptr2, &ptr3, new->Point2.X, new->Point2.Y, Settings.ViaThickness / 2) == NO_TYPE)) { info.X = new->Point2.X; info.Y = new->Point2.Y; if (setjmp (info.env) == 0) r_search (Layer->line_tree, &sb, NULL, moveline_callback, &info); } Draw (); return (new); } /* --------------------------------------------------------------------------- * moves a text object between layers; lowlevel routines */ void * MoveTextToLayerLowLevel (LayerTypePtr Source, TextTypePtr Text, LayerTypePtr Destination) { TextTypePtr new = GetTextMemory (Destination); r_delete_entry (Source->text_tree, (BoxTypePtr) Text); /* copy the data and remove it from the former layer */ *new = *Text; *Text = Source->Text[--Source->TextN]; r_substitute (Source->text_tree, (BoxType *) & Source->Text[Source->TextN], (BoxType *) Text); memset (&Source->Text[Source->TextN], 0, sizeof (TextType)); if (GetLayerGroupNumberByNumber (MAX_LAYER + SOLDER_LAYER) == GetLayerGroupNumberByPointer (Destination)) SET_FLAG (ONSOLDERFLAG, new); else CLEAR_FLAG (ONSOLDERFLAG, new); /* re-calculate the bounding box (it could be mirrored now) */ SetTextBoundingBox (&PCB->Font, new); if (!Destination->text_tree) Destination->text_tree = r_create_tree (NULL, 0, 0); r_insert_entry (Destination->text_tree, (BoxTypePtr) new, 0); return (new); } /* --------------------------------------------------------------------------- * moves a text object between layers */ static void * MoveTextToLayer (LayerTypePtr Layer, TextTypePtr Text) { TextTypePtr new; if (TEST_FLAG (LOCKFLAG, Text)) { Message (_("Sorry, the object is locked\n")); return NULL; } if (Dest != Layer) { AddObjectToMoveToLayerUndoList (TEXT_TYPE, Layer, Text, Text); if (Layer->On) EraseText (Text); new = MoveTextToLayerLowLevel (Layer, Text, Dest); if (Dest->On) DrawText (Dest, new, 0); if (Layer->On || Dest->On) Draw (); return (new); } return (Text); } /* --------------------------------------------------------------------------- * moves a polygon between layers; lowlevel routines */ void * MovePolygonToLayerLowLevel (LayerTypePtr Source, PolygonTypePtr Polygon, LayerTypePtr Destination) { PolygonTypePtr new = GetPolygonMemory (Destination); r_delete_entry (Source->polygon_tree, (BoxType *) Polygon); /* copy the data and remove it from the former layer */ *new = *Polygon; *Polygon = Source->Polygon[--Source->PolygonN]; r_substitute (Source->polygon_tree, (BoxType *) & Source->Polygon[Source->PolygonN], (BoxType *) Polygon); memset (&Source->Polygon[Source->PolygonN], 0, sizeof (PolygonType)); if (!Destination->polygon_tree) Destination->polygon_tree = r_create_tree (NULL, 0, 0); r_insert_entry (Destination->polygon_tree, (BoxType *) new, 0); return (new); } /* --------------------------------------------------------------------------- * moves a polygon between layers */ static void * MovePolygonToLayer (LayerTypePtr Layer, PolygonTypePtr Polygon) { PolygonTypePtr new; if (TEST_FLAG (LOCKFLAG, Polygon)) { Message (_("Sorry, the object is locked\n")); return NULL; } if (((long int) Dest == -1) || (Layer == Dest)) return (Polygon); AddObjectToMoveToLayerUndoList (POLYGON_TYPE, Layer, Polygon, Polygon); if (Layer->On) ErasePolygon (Polygon); /* Move all of the thermals with the polygon */ ALLPIN_LOOP (PCB->Data); { if (TEST_THERM (GetLayerNumber (PCB->Data, Layer), pin) && IsPointInPolygon (pin->X, pin->Y, 0, Polygon)) { AddObjectToFlagUndoList (PIN_TYPE, Layer, pin, pin); CLEAR_THERM (GetLayerNumber (PCB->Data, Layer), pin); SET_THERM (GetLayerNumber (PCB->Data, Dest), pin); } } ENDALL_LOOP; VIA_LOOP (PCB->Data); { if (TEST_THERM (GetLayerNumber (PCB->Data, Layer), via) && IsPointInPolygon (via->X, via->Y, 0, Polygon)) { AddObjectToFlagUndoList (VIA_TYPE, Layer, via, via); CLEAR_THERM (GetLayerNumber (PCB->Data, Layer), via); SET_THERM (GetLayerNumber (PCB->Data, Dest), via); } } END_LOOP; new = MovePolygonToLayerLowLevel (Layer, Polygon, Dest); UpdatePIPFlags (NULL, NULL, Layer, True); UpdatePIPFlags (NULL, NULL, Dest, True); if (Dest->On) { DrawPolygon (Dest, new, 0); Draw (); } return (new); } /* --------------------------------------------------------------------------- * moves the object identified by its data pointers and the type * not we don't bump the undo serial number */ void * MoveObject (int Type, void *Ptr1, void *Ptr2, void *Ptr3, LocationType DX, LocationType DY) { void *result; /* setup offset */ DeltaX = DX; DeltaY = DY; AddObjectToMoveUndoList (Type, Ptr1, Ptr2, Ptr3, DX, DY); result = ObjectOperation (&MoveFunctions, Type, Ptr1, Ptr2, Ptr3); return (result); } /* --------------------------------------------------------------------------- * moves the object identified by its data pointers and the type * as well as all attached rubberband lines */ void * MoveObjectAndRubberband (int Type, void *Ptr1, void *Ptr2, void *Ptr3, LocationType DX, LocationType DY) { RubberbandTypePtr ptr; void *ptr2; /* setup offset */ DeltaX = DX; DeltaY = DY; if (DX == 0 && DY == 0) return (NULL); /* move all the lines... and reset the counter */ ptr = Crosshair.AttachedObject.Rubberband; while (Crosshair.AttachedObject.RubberbandN) { /* first clear any marks that we made in the line flags */ CLEAR_FLAG (RUBBERENDFLAG, ptr->Line); AddObjectToMoveUndoList (LINEPOINT_TYPE, ptr->Layer, ptr->Line, ptr->MovedPoint, DX, DY); MoveLinePoint (ptr->Layer, ptr->Line, ptr->MovedPoint); Crosshair.AttachedObject.RubberbandN--; ptr++; } AddObjectToMoveUndoList (Type, Ptr1, Ptr2, Ptr3, DX, DY); ptr2 = ObjectOperation (&MoveFunctions, Type, Ptr1, Ptr2, Ptr3); IncrementUndoSerialNumber (); return (ptr2); } /* --------------------------------------------------------------------------- * moves the object identified by its data pointers and the type * to a new layer without changing it's position */ void * MoveObjectToLayer (int Type, void *Ptr1, void *Ptr2, void *Ptr3, LayerTypePtr Target, Boolean enmasse) { void *result; /* setup global identifiers */ Dest = Target; MoreToCome = enmasse; result = ObjectOperation (&MoveToLayerFunctions, Type, Ptr1, Ptr2, Ptr3); IncrementUndoSerialNumber (); return (result); } /* --------------------------------------------------------------------------- * moves the selected objects to a new layer without changing their * positions */ Boolean MoveSelectedObjectsToLayer (LayerTypePtr Target) { Boolean changed; /* setup global identifiers */ Dest = Target; MoreToCome = True; changed = SelectedOperation (&MoveToLayerFunctions, True, ALL_TYPES); /* passing True to above operation causes Undoserial to auto-increment */ return (changed); }