gt:                 Point point = this.getRelativeMouseTrackPoint();
context: ///////////////////////////////////////////////////////////////////////////////
  // For information as to what this class does, see the Javadoc, below.       //
  // Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,       //
  // 2007, 2008, 2009, 2010, 2014, 2015 by Peter Spirtes, Richard Scheines, Joseph   //
  // Ramsey, and Clark Glymour.                                                //
  //                                                                           //
  // 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA //
  ///////////////////////////////////////////////////////////////////////////////
  
  package edu.cmu.tetradapp.workbench;
  
  import edu.cmu.tetrad.graph.Edge;
  import edu.cmu.tetrad.graph.Endpoint;
  
  import javax.swing.*;
  import java.awt.*;
  import java.awt.event.ComponentAdapter;
  import java.awt.event.ComponentEvent;
  import java.beans.PropertyChangeEvent;
  import java.beans.PropertyChangeListener;
  
  /**
   * This component has three modes: <ul> <li> UNANCHORED <li> NORMAL <li>
   * SELECTED </ul> In the unanchored mode, it displays an edge in the the
   * workbench, one end of which is anchored to a workbench node and the other end
   * of which tracks a mouse point.  The edge in this mode is useful for
   * constructing new edges in the workbench.  In the normal and selected modes,
   * both ends are anchored to workbench nodes, and the edge will track these
   * workbench nodes if they are moved on the workbench.  The difference between
   * the normal and selected modes is that they display the edge in different
   * colors and when queried they respond differently as to whether the edge is
   * selected.  <p> The intended use for this workbench edge is as follows.  When
   * an edge on the screen is first being created, an instance of this workbench
   * edge is created anchored on one end to a workbench node.  As the mouse is
   * dragged, updates to its position are fed to the updateTrackPoint() method.
   * When the mouse is released, the tracking edge is removed from the workbench
   * and replaced with a new workbench edge which is anchored to two nodes--(1)
   * the original node from the tracking edge and (2) the node which is nearest to
   * the mouse release position.
   *
   * @author Joseph Ramsey
   * @author Willie Wheeler
   */
  public class DisplayEdge extends JComponent implements IDisplayEdge {
  
      /**
       * Indicates that one end of the edge is anchored to one component, but the
       * other half is tracking the mouse point.
       */
      protected static final int HALF_ANCHORED = 0;
  
      /**
       * Indicates that both ends of the edge are anchored to components.  The
       * edge will move when those components move.
       */
      protected static final int ANCHORED_UNSELECTED = 1;
  
      /**
       * Indicates that the edge is under construction, which is similar to the
       * normal mode except that it's displayed as selected and will identify
       * itself as selected upon request (for possible deletion, e.g.).
       */
      protected static final int ANCHORED_SELECTED = 2;
  
      /**
       * Represents the fact that this is a directed edge, A--&gt;B.
       */
      public static final int DIRECTED = 0;
  
      /**
       * Represents the fact that this is an nondirected edge, Ao-oB
       */
      public static final int NONDIRECTED = 1;
  
      /**
       * Represents the fact tha tthis is an undirected edge, A---B
       */
      private static final int UNDIRECTED = 2;
  
      /**
       * Represents the fact that this is a partially directed edge, Ao-&gt;B.
       */
      public static final int PARTIALLY_ORIENTED = 3;
  
      /**
       * Represents the fact that this is a bidirected edge, A&lt;-&gt;B.
       */
      public static final int BIDIRECTED = 4;
  
      /**
       * The model edge that this display is is portraying.
       */
      private Edge modelEdge;
  
      /**
       * The getModel mode of the edge--HALF_ANCHORED, ANCHORED_UNSELECTED, or
       * ANCHORED_SELECTED.
       */
      private int mode;
  
      /**
       * The type of the edge, one of DIRECTED, NONDIRECTED, UNDIRECTED,
       * PARTIALLY_ORIENTED, BIDIRECTED.
       */
      private int type = 0;
  
      /**
       * The node that this edge is linked "from."
       */
      private DisplayNode node1;
  
      /**
       * The node that this edge is linked "to."
       */
      private DisplayNode node2;
  
      /**
       * For HALF_ANCHORed edges, this is the mouse point they connect to.
       */
      private Point mouseTrackPoint = new Point();
  
      /**
       * This is the same mouse point, but relative to *this* edge component.
       */
      private Point relativeMouseTrackPoint = new Point();
  
      /**
       * If the user clicks in this region, the edge will select.
       */
      private Polygon clickRegion;
  
      /**
       * True iff only adacencies (and no endpoints) should be shown.
       */
      private boolean showAdjacenciesOnly = false;
  
      /**
       * The offset of this edge for multiple edges between node pairs.
       */
      private double offset = 0;
  
      /**
       * The pair of points that this edge connects, from the edge of one
       * component to the edge of the other.
       */
      private PointPair connectedPoints;
  
      /**
       * The color that unselected edges will be drawn in.
       */
      private Color lineColor = new Color(78, 117, 175);
  //    private Color lineColor = Color.black;
  
  
  //    public Color lineColor = new Color(99, 101, 188);
  //    public Color lineColor = new Color(0, 4, 255);
  //    public Color lineColor = new Color(52, 55, 217);
  
      /**
       * The color that selected edges will be drawn in.
       */
  
  
  //    private Color selectedColor = new Color(78, 117, 175).darker();
  //    private Color selectedColor = new Color(238, 180, 34); // Dark yellow
      private Color selectedColor = new Color(221, 66, 32);   // this one
  //    public Color selectedColor = new Color(255, 151, 0);
  //    public Color selectedColor = new Color(255, 123, 0);
  
      //    private Color highlightedColor = Color.red.darker().darker();
      private Color highlightedColor = new Color(238, 180, 34);
  
      /**
       * The width of the stroke.
       */
      private float strokeWidth = 1f;
  
      /**
       * True iff this edge is highlighted.
       */
      private boolean highlighted = false;
  
      /**
       * Handler for <code>ComponentEvent</code>s.
       */
      private final ComponentHandler compHandler = new ComponentHandler();
  
      /**
       * Handler for <code>PropertyChange</code>s.
       */
      private final PropertyChangeHandler propertyChangeHandler =
              new PropertyChangeHandler();
      private boolean dashed = false;
  
      //==========================CONSTRUCTORS============================//
  
      /**
       * Constructs a new DisplayEdge connecting two components, 'node1' and
       * 'node2', assuming that a reference to the model edge will not be needed.
       *
       * @param node1 the 'from' component.
       * @param node2 the 'to' component.
       * @param type  the type of the edge, either UNRANDOMIZED or RANDOMIZED.
       */
      protected DisplayEdge(DisplayNode node1, DisplayNode node2, int type) {
          this(node1, node2, type, null);
      }
  
      protected DisplayEdge(DisplayNode node1, DisplayNode node2, int type, Color color) {
          if (node1 == null) {
              throw new NullPointerException("Node1 must not be null.");
          }
  
          if (node2 == null) {
              throw new NullPointerException("Node2 must not be null.");
          }
  
          if (type < 0 || type > 4) {
              throw new IllegalArgumentException("Type must be one of " +
                      "DIRECTED, NONDIRECTED, " +
                      "UNDIRECTED, PARTIALLY_ORIENTED, " + " or BIDIRECTED.");
          }
  
          this.node1 = node1;
          this.node2 = node2;
          this.type = type;
  
          if (color != null) {
              this.lineColor = color;
          }
  
          this.mode = ANCHORED_UNSELECTED;
  
          node1.addComponentListener(compHandler);
          node2.addComponentListener(compHandler);
  
          node1.addPropertyChangeListener(propertyChangeHandler);
          node2.addPropertyChangeListener(propertyChangeHandler);
  
          resetBounds();
      }
  
      /**
       * Constructs a new DisplayEdge connecting two components, 'node1' and
       * 'node2', assuming that a reference to the model edge will be needed.
       *
       * @param node1 the 'from' component.
       * @param node2 the 'to' component.
       */
      public DisplayEdge(Edge modelEdge, DisplayNode node1, DisplayNode node2) {
          this(modelEdge, node1, node2, null);
      }
  
      public DisplayEdge(Edge modelEdge, DisplayNode node1, DisplayNode node2, Color color) {
  
          if (modelEdge == null) {
              throw new NullPointerException("Model edge must not be null.");
          }
  
          if (node1 == null) {
              throw new NullPointerException("Node1 must not be null.");
          }
  
          if (node2 == null) {
              throw new NullPointerException("Node2 must not be null.");
          }
  
          this.modelEdge = modelEdge;
          this.node1 = node1;
          this.node2 = node2;
  
          if (color != null) {
              this.lineColor = color;
          }
          this.mode = ANCHORED_UNSELECTED;
  
          node1.addComponentListener(compHandler);
          node2.addComponentListener(compHandler);
  
          node1.addPropertyChangeListener(propertyChangeHandler);
          node2.addPropertyChangeListener(propertyChangeHandler);
  
          resetBounds();
      }
  
      /**
       * Constructs a new unanchored session edge.  The end of the edge at 'node1'
       * isO anchored, but the other end tracks a mouse point. The mouse point
       * should be updated by the parent component using repeated calls to
       * 'updateTrackPoint'; this process is finished by finally anchoring the
       * second end of the of edge using 'anchorSecondEnd'.  Once this is done,
       * the edge is considered anchored and will not be able to track a mouse
       * point any longer.
       *
       * @param node1           the 'from' component.
       * @param mouseTrackPoint the initial value of the mouse track point.
       * @see #updateTrackPoint
       */
      public DisplayEdge(DisplayNode node1, Point mouseTrackPoint, int type) {
          this(node1, mouseTrackPoint, type, null);
      }
  
      public DisplayEdge(DisplayNode node1, Point mouseTrackPoint, int type, Color color) {
  
          if (node1 == null) {
              throw new NullPointerException("Node1 must not be null.");
          }
  
          if (mouseTrackPoint == null) {
              throw new NullPointerException(
                      "Mouse track point must not " + "be null.");
          }
  
          if (type < 0 || type > 4) {
              throw new IllegalArgumentException("Type must be one of " +
                      "DIRECTED, NONDIRECTED, " +
                      "UNDIRECTED, PARTIALLY_ORIENTED, " + " or BIDIRECTED.");
          }
  
          this.node1 = node1;
          this.mouseTrackPoint = mouseTrackPoint;
          this.type = type;
  
          if (color != null) {
              this.lineColor = color;
          }
  
          this.mode = HALF_ANCHORED;
  
          resetBounds();
      }
  
      /**
       * Paints the component.
       */
      public void paint(Graphics g) {
  
          // NOTE:  For this component, the resetBounds() methods should ALWAYS
          // be called before repaint().
          switch (this.mode) {
              case HALF_ANCHORED:
                  g.setColor(getLineColor());
                  Point point = this.getRelativeMouseTrackPoint();
                  setConnectedPoints(calculateEdge(getNode1(), point));
  
                  if (getConnectedPoints() != null) {
                      drawEdge(g);
                  }
  
                  break;
  
              case ANCHORED_UNSELECTED:
                  g.setColor(getLineColor());
                  setConnectedPoints(calculateEdge(getNode1(), getNode2()));
  
                  if (getConnectedPoints() != null) {
                      drawEdge(g);
                  }
  
                  break;
  
              case ANCHORED_SELECTED:
                  g.setColor(getSelectedColor());
                  setConnectedPoints(calculateEdge(getNode1(), getNode2()));
  
                  if (getConnectedPoints() != null) {
                      drawEdge(g);
                  }
  
                  break;
  
              default:
                  throw new IllegalStateException();
          }
      }
  
      /**
       * Draws the actual edge.
       *
       * @param g the graphics context.
       */
      private void drawEdge(Graphics g) {
          Graphics2D g2d = (Graphics2D) g;
  
          getConnectedPoints().getFrom().translate(-getLocation().x,
                  -getLocation().y);
          getConnectedPoints().getTo().translate(-getLocation().x,
                  -getLocation().y);
  
          setClickRegion(null);
  
          int x1 = getConnectedPoints().getFrom().x;
          int y1 = getConnectedPoints().getFrom().y;
          int x2 = getConnectedPoints().getTo().x;
          int y2 = getConnectedPoints().getTo().y;
  
  //        Endpoint endpointA = this.getModelEdge().getEndpoint1();
  //        Endpoint endpointB = this.getModelEdge().getEndpoint2();
  //
  //        if (endpointA == Endpoint.ARROW) {
  //            x1 += Math.signum(x2 - x1) * getStrokeWidth();
  //            y1 += Math.signum(x2 - x1) * getStrokeWidth();
  //        }
  //
  //        if (endpointB == Endpoint.ARROW) {
  //            x2 += Math.signum(x1 - x2) * getStrokeWidth();
  //            y2 += Math.signum(x1 - x2) * getStrokeWidth();
  //        }
  
          // This silly-looking next line is required to get around an annoying
          // bug that appears in Windows (but not Linux) in JDK
          // 1.4.2_08 and 1.5.0_02 at least. If you display an editor, then
          // select the "Save Screenshot" menu item, then do it again (or
          // select the "Save Graph Image" menu item), all of the lines drawn
          // by Graphics2D.drawLine in this class get atomized and distributed
          // across the entire dialog, and this atomization doesn't go away
          // even if you close the editor and reopen it. Must be some
          // undocumented interaction between the two graphics contexts
          // (the one drawing the image on screen and the other drawing it
          // in the Graphics2D from BufferedImage). In any case, any stroke
          // width <= 1.0 seems to cause the problem, so we pick a stroke
          // width slightly greater than 1.0. jdramsey 4/16/2005
  //        g2d.setStroke(new BasicStroke(1.000001f));
          BasicStroke s;
  
          if (dashed) {
              float dash1[] = {10.0f};
              s = new BasicStroke(1.0f,
                      BasicStroke.CAP_BUTT,
                      BasicStroke.JOIN_MITER,
                      10.0f, dash1, 0.0f);
          } else {
              s = new BasicStroke(getStrokeWidth() + 0.000001f);
          }
  
          g2d.setStroke(s);
  
          if (!isSelected()) {
              g2d.setColor(lineColor);
          }
  
          g2d.drawLine(x1, y1, x2, y2);
  
          if (!isShowAdjacenciesOnly()) {
              drawEndpoints(getConnectedPoints(), g);
          }
  
          firePropertyChange("newPointPair", null, getConnectedPoints());
      }
  
      //============================PUBLIC METHODS========================//
  
      /**
       * Overrides the parent's contains() method using the click region, so that
       * points not in the click region are passed through to components lying
       * beneath this one in the z-order. (Equates the effective shape of this
       * edge to its click region.)
       *
       * @param x the x value of the point to be tested.
       * @param y the y value of the point to be tested.
       * @return true of (x, y) is in the click region, false if not.
       */
      public boolean contains(int x, int y) {
          Polygon clickRegion = getClickRegion();
  
          if (clickRegion != null) {
              return clickRegion.contains(new Point(x, y));
          } else {
              return false;
          }
      }
  
      /**
       * Retrieves the getModel region where mouse clicks are responded to (as
       * opposed to passed on).
       *
       * @return the click region.
       */
      private Polygon getClickRegion() {
  
          if ((this.clickRegion == null) && (getConnectedPoints() != null)) {
              this.clickRegion = getSleeve(getConnectedPoints());
          }
  
          return this.clickRegion;
      }
  
      /**
       * Retrieves the currents point pair which defines the line segment of the
       * edge.
       *
       * @return the getModel point pair.
       */
      public final PointPair getPointPair() {
          switch (this.mode) {
              case HALF_ANCHORED:
  