Esempio n. 1
0
void selectRat(int idx) {
	/*
	type = SearchScreen (Crosshair.X, Crosshair.Y, SELECT_TYPES,
		       &ptr1, &ptr2, &ptr3);
	 */
	/* FIXME is ptr1 a layer? */
	RatType *rat = &(PCB->Data)->Rat[idx];
	/* TODO: add undo FIXME: how? */
	/* AddObjectToFlagUndoList (RATLINE_TYPE, ptr1, ptr1, ptr1); */
	TOGGLE_FLAG (SELECTEDFLAG, rat);
	DrawRat (rat);
}
Esempio n. 2
0
void
DrawObject (int type, void *ptr1, void *ptr2)
{
  switch (type)
    {
    case VIA_TYPE:
      if (PCB->ViaOn)
	DrawVia ((PinType *) ptr2);
      break;
    case LINE_TYPE:
      if (((LayerType *) ptr1)->On)
	DrawLine ((LayerType *) ptr1, (LineType *) ptr2);
      break;
    case ARC_TYPE:
      if (((LayerType *) ptr1)->On)
	DrawArc ((LayerType *) ptr1, (ArcType *) ptr2);
      break;
    case TEXT_TYPE:
      if (((LayerType *) ptr1)->On)
	DrawText ((LayerType *) ptr1, (TextType *) ptr2);
      break;
    case POLYGON_TYPE:
      if (((LayerType *) ptr1)->On)
	DrawPolygon ((LayerType *) ptr1, (PolygonType *) ptr2);
      break;
    case ELEMENT_TYPE:
      if (PCB->ElementOn &&
	  (FRONT ((ElementType *) ptr2) || PCB->InvisibleObjectsOn))
	DrawElement ((ElementType *) ptr2);
      break;
    case RATLINE_TYPE:
      if (PCB->RatOn)
	DrawRat ((RatType *) ptr2);
      break;
    case PIN_TYPE:
      if (PCB->PinOn)
	DrawPin ((PinType *) ptr2);
      break;
    case PAD_TYPE:
      if (PCB->PinOn)
	DrawPad ((PadType *) ptr2);
      break;
    case ELEMENTNAME_TYPE:
      if (PCB->ElementOn &&
	  (FRONT ((ElementType *) ptr2) || PCB->InvisibleObjectsOn))
	DrawElementName ((ElementType *) ptr1);
      break;
    }
}
Esempio n. 3
0
/* ---------------------------------------------------------------------------
 * moves one end of a line
 */
static void *
MoveLinePoint (LayerTypePtr Layer, LineTypePtr Line, PointTypePtr Point)
{
  if (Layer)
    {
      if (Layer->On)
	EraseLine (Line);
      RestoreToPolygon (PCB->Data, LINE_TYPE, Layer, 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);
      ClearFromPolygon (PCB->Data, LINE_TYPE, Layer, Line);
      if (Layer->On)
	{
	  DrawLine (Layer, Line);
	  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);
	  Draw ();
	}
      return (Line);
    }
}
Esempio n. 4
0
File: rats.c Progetto: rlutz/pcb
/*!
 * \brief Draw a rat net (tree) having the shortest lines.
 *
 * This also frees the subnet memory as they are consumed.
 *
 * \note The \c Netl we are passed is NOT the main netlist - it's the
 * connectivity for ONE net.
 * It represents the CURRENT connectivity state for the net, with each
 * Netl->Net[N] representing one copper-connected subset of the net.
 *
 * Everything inside the NetList Netl should be connected together.
 *
 * Each Net in \c Netl is a group of Connections which are already
 * connected together somehow, either by real wires or by rats we've
 * already drawn.
 *
 * Each Connection is a vertex within that blob of connected items.
 *
 * This loop finds the closest vertex pairs between each blob and draws
 * rats that merge the blobs until there's just one big blob.
 *
 * Just to clarify, with some examples:
 *
 * Each \c Netl is one full net from a netlist, like from gnetlist.
 *
 * Each Netl->Net[N] is a subset of that net that's already
 * physically connected on the pcb.
 *
 * So a new design with no traces yet, would have a huge list of Net[N],
 * each with one pin in it.
 *
 * A fully routed design would have one Net[N] with all the pins
 * (for that net) in it.
 */
static bool
DrawShortestRats (NetListType *Netl, void (*funcp) (register ConnectionType *, register ConnectionType *, register RouteStyleType *))
{
  RatType *line;
  register float distance, temp;
  register ConnectionType *conn1, *conn2, *firstpoint, *secondpoint;
  PolygonType *polygon;
  bool changed = false;
  bool havepoints;
  Cardinal n, m, j;
  NetType *next, *subnet, *theSubnet = NULL;

  /* This is just a sanity check, to make sure we're passed
   * *something*.
   */
  if (!Netl || Netl->NetN < 1)
    return false;

  /*
   * We keep doing this do/while loop until everything's connected.
   * I.e. once per rat we add.
   */
  distance = 0.0;
  havepoints = true; /* so we run the loop at least once */
  while (Netl->NetN > 1 && havepoints)
    {
      /* This is the top of the "find one rat" logic.  */
      havepoints = false;
      firstpoint = secondpoint = NULL;

      /* Test Net[0] vs Net[N] for N=1..max.  Find the shortest
	 distance between any two points in different blobs.  */
      subnet = &Netl->Net[0];
      for (j = 1; j < Netl->NetN; j++)
	{
	  /*
	   * Scan between Net[0] blob (subnet) and Net[N] blob (next).
	   * Note the shortest distance we find.
	   */
	  next = &Netl->Net[j];
	  for (n = subnet->ConnectionN - 1; n != -1; n--)
	    {
	      conn1 = &subnet->Connection[n];
	      for (m = next->ConnectionN - 1; m != -1; m--)
		{
		  conn2 = &next->Connection[m];
		  /*
		   * At this point, conn1 and conn2 are two pins in
		   * different blobs of the same net.  See how far
		   * apart they are, and if they're "closer" than what
		   * we already have.
		   */

		  /*
		   * Prefer to connect Connections over polygons to the
		   * polygons (ie assume the user wants a via to a plane,
		   * not a daisy chain).  Further prefer to pick an existing
		   * via in the Net to make that connection.
		   */
		  if (conn1->type == POLYGON_TYPE &&
		      (polygon = (PolygonType *)conn1->ptr2) &&
		      !(distance == 0 &&
		        firstpoint && firstpoint->type == VIA_TYPE) &&
		      IsPointInPolygonIgnoreHoles (conn2->X, conn2->Y, polygon))
		    {
		      distance = 0;
		      firstpoint = conn2;
		      secondpoint = conn1;
		      theSubnet = next;
		      havepoints = true;
		    }
		  else if (conn2->type == POLYGON_TYPE &&
		      (polygon = (PolygonType *)conn2->ptr2) &&
		      !(distance == 0 &&
		        firstpoint && firstpoint->type == VIA_TYPE) &&
		      IsPointInPolygonIgnoreHoles (conn1->X, conn1->Y, polygon))
		    {
		      distance = 0;
		      firstpoint = conn1;
		      secondpoint = conn2;
		      theSubnet = next;
		      havepoints = true;
		    }
		  else if ((temp = SQUARE (conn1->X - conn2->X) +
		       SQUARE (conn1->Y - conn2->Y)) < distance || !firstpoint)
		    {
		      distance = temp;
		      firstpoint = conn1;
		      secondpoint = conn2;
		      theSubnet = next;
		      havepoints = true;
		    }
		}
	    }
	}

      /*
       * If HAVEPOINTS is true, we've found a pair of points in two
       * separate blobs of the net, and need to connect them together.
       */
      if (havepoints)
	{
	  if (funcp)
	    {
	      (*funcp) (firstpoint, secondpoint, subnet->Style);
	    }
	  else
	    {
	      /* found the shortest distance subnet, draw the rat */
	      if ((line = CreateNewRat (PCB->Data,
					firstpoint->X, firstpoint->Y,
					secondpoint->X, secondpoint->Y,
					firstpoint->group, secondpoint->group,
					Settings.RatThickness,
					NoFlags ())) != NULL)
		{
		  if (distance == 0)
		    SET_FLAG (VIAFLAG, line);
		  AddObjectToCreateUndoList (RATLINE_TYPE, line, line, line);
		  DrawRat (line);
		  changed = true;
		}
	    }

	  /* copy theSubnet into the current subnet */
	  TransferNet (Netl, theSubnet, subnet);
	}
    }

  /* presently nothing to do with the new subnet */
  /* so we throw it away and free the space */
  FreeNetMemory (&Netl->Net[--(Netl->NetN)]);
  /* Sadly adding a rat line messes up the sorted arrays in connection finder */
  /* hace: perhaps not necessarily now that they aren't stored in normal layers */
  if (changed)
    {
      FreeConnectionLookupMemory ();
      InitConnectionLookup ();
    }
  return (changed);
}
Esempio n. 5
0
/* ----------------------------------------------------------------------
 * selects/unselects all objects which were found during a connection scan
 * Flag determines if they are to be selected or unselected
 * returns true if the state of any object has changed
 *
 * text objects and elements cannot be selected by this routine
 */
bool
SelectConnection (bool Flag)
{
  bool changed = false;

  if (PCB->RatOn)
    RAT_LOOP (PCB->Data);
  {
    if (TEST_FLAG (FOUNDFLAG, line))
      {
	AddObjectToFlagUndoList (RATLINE_TYPE, line, line, line);
	ASSIGN_FLAG (SELECTEDFLAG, Flag, line);
	DrawRat (line, 0);
	changed = true;
      }
  }
  END_LOOP;

  VISIBLELINE_LOOP (PCB->Data);
  {
    if (TEST_FLAG (FOUNDFLAG, line) && !TEST_FLAG (LOCKFLAG, line))
      {
	AddObjectToFlagUndoList (LINE_TYPE, layer, line, line);
	ASSIGN_FLAG (SELECTEDFLAG, Flag, line);
	DrawLine (layer, line, 0);
	changed = true;
      }
  }
  ENDALL_LOOP;
  VISIBLEARC_LOOP (PCB->Data);
  {
    if (TEST_FLAG (FOUNDFLAG, arc) && !TEST_FLAG (LOCKFLAG, arc))
      {
	AddObjectToFlagUndoList (ARC_TYPE, layer, arc, arc);
	ASSIGN_FLAG (SELECTEDFLAG, Flag, arc);
	DrawArc (layer, arc, 0);
	changed = true;
      }
  }
  ENDALL_LOOP;
  VISIBLEPOLYGON_LOOP (PCB->Data);
  {
    if (TEST_FLAG (FOUNDFLAG, polygon) && !TEST_FLAG (LOCKFLAG, polygon))
      {
	AddObjectToFlagUndoList (POLYGON_TYPE, layer, polygon, polygon);
	ASSIGN_FLAG (SELECTEDFLAG, Flag, polygon);
	DrawPolygon (layer, polygon, 0);
	changed = true;
      }
  }
  ENDALL_LOOP;

  if (PCB->PinOn && PCB->ElementOn)
    {
      ALLPIN_LOOP (PCB->Data);
      {
	if (!TEST_FLAG (LOCKFLAG, element) && TEST_FLAG (FOUNDFLAG, pin))
	  {
	    AddObjectToFlagUndoList (PIN_TYPE, element, pin, pin);
	    ASSIGN_FLAG (SELECTEDFLAG, Flag, pin);
	    DrawPin (pin, 0);
	    changed = true;
	  }
      }
      ENDALL_LOOP;
      ALLPAD_LOOP (PCB->Data);
      {
	if (!TEST_FLAG (LOCKFLAG, element) && TEST_FLAG (FOUNDFLAG, pad))
	  {
	    AddObjectToFlagUndoList (PAD_TYPE, element, pad, pad);
	    ASSIGN_FLAG (SELECTEDFLAG, Flag, pad);
	    DrawPad (pad, 0);
	    changed = true;
	  }
      }
      ENDALL_LOOP;
    }

  if (PCB->ViaOn)
    VIA_LOOP (PCB->Data);
  {
    if (TEST_FLAG (FOUNDFLAG, via) && !TEST_FLAG (LOCKFLAG, via))
      {
	AddObjectToFlagUndoList (VIA_TYPE, via, via, via);
	ASSIGN_FLAG (SELECTEDFLAG, Flag, via);
	DrawVia (via, 0);
	changed = true;
      }
  }
  END_LOOP;
  Draw ();
  return (changed);
}
Esempio n. 6
0
/* ----------------------------------------------------------------------
 * selects/unselects all visible objects within the passed box
 * Flag determines if the block is to be selected or unselected
 * returns true if the state of any object has changed
 */
bool
SelectBlock (BoxTypePtr Box, bool Flag)
{
  bool changed = false;

  if (PCB->RatOn || !Flag)
    RAT_LOOP (PCB->Data);
  {
    if (LINE_IN_BOX ((LineTypePtr) line, Box) &&
	!TEST_FLAG (LOCKFLAG, line) && TEST_FLAG (SELECTEDFLAG, line) != Flag)
      {
	AddObjectToFlagUndoList (RATLINE_TYPE, line, line, line);
	ASSIGN_FLAG (SELECTEDFLAG, Flag, line);
	if (PCB->RatOn)
	  DrawRat (line, 0);
	changed = true;
      }
  }
  END_LOOP;

  /* check layers */
  LAYER_LOOP(PCB->Data, max_copper_layer + 2);
  {
    if (layer == & PCB->Data->SILKLAYER)
      {
	if (! (PCB->ElementOn || !Flag))
	  continue;
      }
    else if (layer == & PCB->Data->BACKSILKLAYER)
      {
	if (! (PCB->InvisibleObjectsOn || !Flag))
	  continue;
      }
    else
      if (! (layer->On || !Flag))
	continue;

    LINE_LOOP (layer);
    {
      if (LINE_IN_BOX (line, Box)
	  && !TEST_FLAG (LOCKFLAG, line)
	  && TEST_FLAG (SELECTEDFLAG, line) != Flag)
	{
	  AddObjectToFlagUndoList (LINE_TYPE, layer, line, line);
	  ASSIGN_FLAG (SELECTEDFLAG, Flag, line);
	  if (layer->On)
	    DrawLine (layer, line, 0);
	  changed = true;
	}
    }
    END_LOOP;
    ARC_LOOP (layer);
    {
      if (ARC_IN_BOX (arc, Box)
	  && !TEST_FLAG (LOCKFLAG, arc)
	  && TEST_FLAG (SELECTEDFLAG, arc) != Flag)
	{
	  AddObjectToFlagUndoList (ARC_TYPE, layer, arc, arc);
	  ASSIGN_FLAG (SELECTEDFLAG, Flag, arc);
	  if (layer->On)
	    DrawArc (layer, arc, 0);
	  changed = true;
	}
    }
    END_LOOP;
    TEXT_LOOP (layer);
    {
      if (!Flag || TEXT_IS_VISIBLE(PCB, layer, text))
	{
	  if (TEXT_IN_BOX (text, Box)
	      && !TEST_FLAG (LOCKFLAG, text)
	      && TEST_FLAG (SELECTEDFLAG, text) != Flag)
	    {
	      AddObjectToFlagUndoList (TEXT_TYPE, layer, text, text);
	      ASSIGN_FLAG (SELECTEDFLAG, Flag, text);
	      if (TEXT_IS_VISIBLE(PCB, layer, text))
		DrawText (layer, text, 0);
	      changed = true;
	    }
	}
    }
    END_LOOP;
    POLYGON_LOOP (layer);
    {
      if (POLYGON_IN_BOX (polygon, Box)
	  && !TEST_FLAG (LOCKFLAG, polygon)
	  && TEST_FLAG (SELECTEDFLAG, polygon) != Flag)
	{
	  AddObjectToFlagUndoList (POLYGON_TYPE, layer, polygon, polygon);
	  ASSIGN_FLAG (SELECTEDFLAG, Flag, polygon);
	  if (layer->On)
	    DrawPolygon (layer, polygon, 0);
	  changed = true;
	}
    }
    END_LOOP;
  }
  END_LOOP;

  /* elements */
  ELEMENT_LOOP (PCB->Data);
  {
    {
      bool gotElement = false;
      if ((PCB->ElementOn || !Flag)
	  && !TEST_FLAG (LOCKFLAG, element)
	  && ((TEST_FLAG (ONSOLDERFLAG, element) != 0) == SWAP_IDENT
	      || PCB->InvisibleObjectsOn))
	{
	  if (BOX_IN_BOX
	      (&ELEMENT_TEXT (PCB, element).BoundingBox, Box)
	      && !TEST_FLAG (LOCKFLAG, &ELEMENT_TEXT (PCB, element))
	      && TEST_FLAG (SELECTEDFLAG,
			    &ELEMENT_TEXT (PCB, element)) != Flag)
	    {
	      /* select all names of element */
	      ELEMENTTEXT_LOOP (element);
	      {
		AddObjectToFlagUndoList (ELEMENTNAME_TYPE,
					 element, text, text);
		ASSIGN_FLAG (SELECTEDFLAG, Flag, text);
	      }
	      END_LOOP;
	      if (PCB->ElementOn)
		DrawElementName (element, 0);
	      changed = true;
	    }
	  if ((PCB->PinOn || !Flag) && ELEMENT_IN_BOX (element, Box))
	    if (TEST_FLAG (SELECTEDFLAG, element) != Flag)
	      {
		AddObjectToFlagUndoList (ELEMENT_TYPE,
					 element, element, element);
		ASSIGN_FLAG (SELECTEDFLAG, Flag, element);
		PIN_LOOP (element);
		{
		  if (TEST_FLAG (SELECTEDFLAG, pin) != Flag)
		    {
		      AddObjectToFlagUndoList (PIN_TYPE, element, pin, pin);
		      ASSIGN_FLAG (SELECTEDFLAG, Flag, pin);
		      if (PCB->PinOn)
			DrawPin (pin, 0);
		      changed = true;
		    }
		}
		END_LOOP;
		PAD_LOOP (element);
		{
		  if (TEST_FLAG (SELECTEDFLAG, pad) != Flag)
		    {
		      AddObjectToFlagUndoList (PAD_TYPE, element, pad, pad);
		      ASSIGN_FLAG (SELECTEDFLAG, Flag, pad);
		      if (PCB->PinOn)
			DrawPad (pad, 0);
		      changed = true;
		    }
		}
		END_LOOP;
		if (PCB->PinOn)
		  DrawElement (element, 0);
		changed = true;
		gotElement = true;
	      }
	}
      if ((PCB->PinOn || !Flag) && !TEST_FLAG (LOCKFLAG, element) && !gotElement)
	{
	  PIN_LOOP (element);
	  {
	    if ((VIA_OR_PIN_IN_BOX (pin, Box)
		 && TEST_FLAG (SELECTEDFLAG, pin) != Flag))
	      {
		AddObjectToFlagUndoList (PIN_TYPE, element, pin, pin);
		ASSIGN_FLAG (SELECTEDFLAG, Flag, pin);
		if (PCB->PinOn)
		  DrawPin (pin, 0);
		changed = true;
	      }
	  }
	  END_LOOP;
	  PAD_LOOP (element);
	  {
	    if (PAD_IN_BOX (pad, Box)
		&& TEST_FLAG (SELECTEDFLAG, pad) != Flag)
	      {
		AddObjectToFlagUndoList (PAD_TYPE, element, pad, pad);
		ASSIGN_FLAG (SELECTEDFLAG, Flag, pad);
		if (PCB->PinOn)
		  DrawPad (pad, 0);
		changed = true;
	      }
	  }
	  END_LOOP;
	}
    }
  }
  END_LOOP;
  /* end with vias */
  if (PCB->ViaOn || !Flag)
    VIA_LOOP (PCB->Data);
  {
    if (VIA_OR_PIN_IN_BOX (via, Box)
	&& !TEST_FLAG (LOCKFLAG, via)
	&& TEST_FLAG (SELECTEDFLAG, via) != Flag)
      {
	AddObjectToFlagUndoList (VIA_TYPE, via, via, via);
	ASSIGN_FLAG (SELECTEDFLAG, Flag, via);
	if (PCB->ViaOn)
	  DrawVia (via, 0);
	changed = true;
      }
  }
  END_LOOP;
  if (changed)
    {
      Draw ();
      IncrementUndoSerialNumber ();
    }
  return (changed);
}
Esempio n. 7
0
/* ---------------------------------------------------------------------------
 * toggles the selection of any kind of object
 * the different types are defined by search.h
 */
bool
SelectObject (void)
{
  void *ptr1, *ptr2, *ptr3;
  LayerTypePtr layer;
  int type;

  bool changed = true;

  type = SearchScreen (Crosshair.X, Crosshair.Y, SELECT_TYPES,
		       &ptr1, &ptr2, &ptr3);
  if (type == NO_TYPE || TEST_FLAG (LOCKFLAG, (PinTypePtr) ptr2))
    return (false);
  switch (type)
    {
    case VIA_TYPE:
      AddObjectToFlagUndoList (VIA_TYPE, ptr1, ptr1, ptr1);
      TOGGLE_FLAG (SELECTEDFLAG, (PinTypePtr) ptr1);
      DrawVia ((PinTypePtr) ptr1, 0);
      break;

    case LINE_TYPE:
      {
	LineType *line = (LineTypePtr) ptr2;

	layer = (LayerTypePtr) ptr1;
	AddObjectToFlagUndoList (LINE_TYPE, ptr1, ptr2, ptr2);
	TOGGLE_FLAG (SELECTEDFLAG, line);
	DrawLine (layer, line, 0);
	break;
      }

    case RATLINE_TYPE:
      {
	RatTypePtr rat = (RatTypePtr) ptr2;

	AddObjectToFlagUndoList (RATLINE_TYPE, ptr1, ptr1, ptr1);
	TOGGLE_FLAG (SELECTEDFLAG, rat);
	DrawRat (rat, 0);
	break;
      }

    case ARC_TYPE:
      {
	ArcType *arc = (ArcTypePtr) ptr2;

	layer = (LayerTypePtr) ptr1;
	AddObjectToFlagUndoList (ARC_TYPE, ptr1, ptr2, ptr2);
	TOGGLE_FLAG (SELECTEDFLAG, arc);
	DrawArc (layer, arc, 0);
	break;
      }

    case TEXT_TYPE:
      {
	TextType *text = (TextTypePtr) ptr2;

	layer = (LayerTypePtr) ptr1;
	AddObjectToFlagUndoList (TEXT_TYPE, ptr1, ptr2, ptr2);
	TOGGLE_FLAG (SELECTEDFLAG, text);
	DrawText (layer, text, 0);
	break;
      }

    case POLYGON_TYPE:
      {
	PolygonType *poly = (PolygonTypePtr) ptr2;

	layer = (LayerTypePtr) ptr1;
	AddObjectToFlagUndoList (POLYGON_TYPE, ptr1, ptr2, ptr2);
	TOGGLE_FLAG (SELECTEDFLAG, poly);
	DrawPolygon (layer, poly, 0);
	/* changing memory order no longer effects draw order */
	break;
      }

    case PIN_TYPE:
      AddObjectToFlagUndoList (PIN_TYPE, ptr1, ptr2, ptr2);
      TOGGLE_FLAG (SELECTEDFLAG, (PinTypePtr) ptr2);
      DrawPin ((PinTypePtr) ptr2, 0);
      break;

    case PAD_TYPE:
      AddObjectToFlagUndoList (PAD_TYPE, ptr1, ptr2, ptr2);
      TOGGLE_FLAG (SELECTEDFLAG, (PadTypePtr) ptr2);
      DrawPad ((PadTypePtr) ptr2, 0);
      break;

    case ELEMENTNAME_TYPE:
      {
	ElementTypePtr element = (ElementTypePtr) ptr1;

	/* select all names of the element */
	ELEMENTTEXT_LOOP (element);
	{
	  AddObjectToFlagUndoList (ELEMENTNAME_TYPE, element, text, text);
	  TOGGLE_FLAG (SELECTEDFLAG, text);
	}
	END_LOOP;
	DrawElementName (element, 0);
	break;
      }

    case ELEMENT_TYPE:
      {
	ElementTypePtr element = (ElementTypePtr) ptr1;

	/* select all pins and names of the element */
	PIN_LOOP (element);
	{
	  AddObjectToFlagUndoList (PIN_TYPE, element, pin, pin);
	  TOGGLE_FLAG (SELECTEDFLAG, pin);
	}
	END_LOOP;
	PAD_LOOP (element);
	{
	  AddObjectToFlagUndoList (PAD_TYPE, element, pad, pad);
	  TOGGLE_FLAG (SELECTEDFLAG, pad);
	}
	END_LOOP;
	ELEMENTTEXT_LOOP (element);
	{
	  AddObjectToFlagUndoList (ELEMENTNAME_TYPE, element, text, text);
	  TOGGLE_FLAG (SELECTEDFLAG, text);
	}
	END_LOOP;
	AddObjectToFlagUndoList (ELEMENT_TYPE, element, element, element);
	TOGGLE_FLAG (SELECTEDFLAG, element);
	if (PCB->ElementOn &&
	    ((TEST_FLAG (ONSOLDERFLAG, element) != 0) == SWAP_IDENT ||
	     PCB->InvisibleObjectsOn))
	  if (PCB->ElementOn)
	    {
	      DrawElementName (element, 0);
	      DrawElementPackage (element, 0);
	    }
	if (PCB->PinOn)
	  DrawElementPinsAndPads (element, 0);
	break;
      }
    }
  Draw ();
  IncrementUndoSerialNumber ();
  return (changed);
}