public void repaint() {
   text = tf.getText();
   Graphics g = getGraphics();
   if (g != null) {
     recalcPositions(g);
     g.dispose();
   }
   super.repaint();
 }
 public void paint(Graphics g) { // ^^^
   if (g instanceof PrintGraphics) return;
   if (MesquiteWindow.checkDoomed(this)) return;
   /**/
   if (getParent() == null) {
     MesquiteWindow.uncheckDoomed(this);
     return;
   }
   if (neverCalculated) {
     if (recalcPositions(g)) {
       MesquiteWindow.uncheckDoomed(this);
       neverCalculated = false;
       return;
     }
   }
   /**/
   /* This stuff below seems unnecessary, but for some reason on MacOS 8.1/MRJ 2.0 it was leaving garbage around; likewise for components*/
   g.setColor(getBackground());
   g.fillRect(getBounds().x, getBounds().y, getBounds().width, getBounds().height);
   g.setColor(Color.black);
   // tf.repaint();
   MesquiteWindow.uncheckDoomed(this);
 }
  /*.................................................................................................................*/
  public Object doCommand(String commandName, String arguments, CommandChecker checker) {
    Tree trt = treeDisplay.getTree();
    MesquiteTree t = null;
    if (trt instanceof MesquiteTree) t = (MesquiteTree) trt;
    if (checker.compare(
        this.getClass(),
        "Adjust tool has touched branch",
        "[branch number][x coordinate touched][y coordinate touched][modifiers]",
        commandName,
        "touchedPositionAdjust")) {
      if (t == null) return null;
      MesquiteInteger io = new MesquiteInteger(0);
      int node = MesquiteInteger.fromString(arguments, io);
      int x = MesquiteInteger.fromString(arguments, io);
      int y = MesquiteInteger.fromString(arguments, io);
      String mod = ParseUtil.getRemaining(arguments, io);

      Point newOnLine = treeDisplay.getTreeDrawing().projectionOnLine(node, x, y);
      originalX = newOnLine.x;
      originalY = newOnLine.y;
      // lastX= newOnLine.x;
      // lastY = newOnLine.y;
      Graphics g = null;
      if (GraphicsUtil.useXORMode(null, false)) {
        g = treeDisplay.getGraphics();
        g.setXORMode(Color.white);
        g.setColor(Color.red);
      }
      // double bX = treeDisplay.getTreeDrawing().lineBaseX[node];
      // double bY = treeDisplay.getTreeDrawing().lineBaseY[node];
      // Math.sqrt((originalY-bY)*(originalY-bY) + (originalX-bX)*(originalX-bX));
      lastBL = tree.getBranchLength(node);
      double shortestAbove = MesquiteDouble.unassigned;
      for (int daughter = t.firstDaughterOfNode(node);
          t.nodeExists(daughter);
          daughter = t.nextSisterOfNode(daughter))
        shortestAbove = MesquiteDouble.minimum(shortestAbove, tree.getBranchLength(daughter));
      if (shortestAbove == MesquiteDouble.unassigned) upperLimit = MesquiteDouble.infinite;
      else if (MesquiteDouble.isCombinable(lastBL)) upperLimit = shortestAbove + lastBL;
      else upperLimit = shortestAbove + 1.0;
      int ibX = treeDisplay.getTreeDrawing().lineBaseX[node];
      int ibY = treeDisplay.getTreeDrawing().lineBaseY[node];
      lastX = treeDisplay.getTreeDrawing().lineTipX[node];
      lastY = treeDisplay.getTreeDrawing().lineTipY[node];
      if (GraphicsUtil.useXORMode(null, false)) {
        drawThickLine(g, ibX, ibY, lastX, lastY);
        for (int daughter = t.firstDaughterOfNode(node);
            t.nodeExists(daughter);
            daughter = t.nextSisterOfNode(daughter))
          drawThickLine(
              g,
              treeDisplay.getTreeDrawing().lineTipX[daughter],
              treeDisplay.getTreeDrawing().lineTipY[daughter],
              lastX,
              lastY);
        g.fillOval(
            lastX - ovalRadius,
            lastY - ovalRadius,
            ovalRadius + ovalRadius,
            ovalRadius + ovalRadius);
        try {
          g.drawString(MesquiteDouble.toString(lastBL), lastX + 10, lastY);
        } catch (InternalError e) { // workaround for bug on windows java 1.7.
        } catch (Throwable e) {
        }
        lineOn = true;
        g.dispose();
      }
    } else if (checker.compare(
        this.getClass(),
        "Adjust tool has been dropped",
        "[branch number][x coordinate dropped][y coordinate dropped]",
        commandName,
        "droppedPositionAdjust")) {
      if (t == null) return null;
      if (editorOn) return null;
      MesquiteInteger io = new MesquiteInteger(0);
      int node = MesquiteInteger.fromString(arguments, io);
      int x = MesquiteInteger.fromString(arguments, io);
      int y = MesquiteInteger.fromString(arguments, io);
      if (lineOn) {
        Point newOnLine = treeDisplay.getTreeDrawing().projectionOnLine(node, x, y);
        double bX = treeDisplay.getTreeDrawing().lineBaseX[node];
        double bY = treeDisplay.getTreeDrawing().lineBaseY[node];
        double tX = treeDisplay.getTreeDrawing().lineTipX[node];
        double tY = treeDisplay.getTreeDrawing().lineTipY[node];
        double lengthLine =
            Math.sqrt((originalY - bY) * (originalY - bY) + (originalX - bX) * (originalX - bX));
        double bL;
        if (lengthLine != 0) {
          double extension =
              Math.sqrt(
                      (newOnLine.y - bY) * (newOnLine.y - bY)
                          + (newOnLine.x - bX) * (newOnLine.x - bX))
                  / lengthLine;
          if (t.getBranchLength(node) == 0 || t.branchLengthUnassigned(node)) bL = extension;
          else bL = t.getBranchLength(node) * extension;
        } else bL = 1;

        if (bL > upperLimit) bL = upperLimit;
        else if (bL < lowerLimit) bL = lowerLimit;
        double oldBL = t.getBranchLength(node);
        if (!MesquiteDouble.isCombinable(oldBL)) oldBL = 1.0;
        t.setBranchLength(node, bL, false);
        double difference = oldBL - t.getBranchLength(node);
        for (int daughter = t.firstDaughterOfNode(node);
            t.nodeExists(daughter);
            daughter = t.nextSisterOfNode(daughter))
          if (MesquiteDouble.isCombinable(t.getBranchLength(daughter)))
            t.setBranchLength(daughter, t.getBranchLength(daughter) + difference, false);
        t.notifyListeners(this, new Notification(MesquiteListener.BRANCHLENGTHS_CHANGED));
        Graphics g = treeDisplay.getGraphics();
        g.setPaintMode();
        g.dispose();
        treeDisplay.pleaseUpdate(true);
        lineOn = false;
      }
    } else if (checker.compare(
        this.getClass(),
        "Adjust tool is being dragged",
        "[branch number][x coordinate][y coordinate]",
        commandName,
        "draggedPositionAdjust")) {
      if (t == null) return null;
      if (editorOn) return null;
      MesquiteInteger io = new MesquiteInteger(0);
      int node = MesquiteInteger.fromString(arguments, io);
      int x = MesquiteInteger.fromString(arguments, io);
      int y = MesquiteInteger.fromString(arguments, io);
      if (lineOn) {
        Point newOnLine = treeDisplay.getTreeDrawing().projectionOnLine(node, x, y);
        // WARNING":  This shouldn't result in length increase if simple click and release with no
        // drag; must subtract original X, Y
        Graphics g = null;
        if (GraphicsUtil.useXORMode(null, false)) {
          g = treeDisplay.getGraphics();
          g.setXORMode(Color.white);
          g.setColor(Color.red);
        }
        // g.fillOval(lastX-ovalRadius, lastY-ovalRadius, ovalRadius + ovalRadius, ovalRadius +
        // ovalRadius);
        // g.fillOval(newOnLine.x-ovalRadius, newOnLine.y -ovalRadius, ovalRadius + ovalRadius,
        // ovalRadius + ovalRadius);

        // g.drawLine(originalX, originalY, lastX, lastY);
        // g.drawLine(originalX, originalY, newOnLine.x, newOnLine.y);

        //				if decreasing, & unassigned involved: push unassigned down and assign values to
        // unassigned above; if increasing, push unassigne up
        int ibX = treeDisplay.getTreeDrawing().lineBaseX[node];
        int ibY = treeDisplay.getTreeDrawing().lineBaseY[node];
        int itX = treeDisplay.getTreeDrawing().lineTipX[node];
        int itY = treeDisplay.getTreeDrawing().lineTipY[node];

        double bX = ibX;
        double bY = ibY;
        double tX = itX;
        double tY = itY;
        double lengthLine =
            Math.sqrt((originalY - bY) * (originalY - bY) + (originalX - bX) * (originalX - bX));
        if (lengthLine != 0) {
          if (GraphicsUtil.useXORMode(null, false)) {
            if (MesquiteTrunk.isMacOSX()
                && MesquiteTrunk.getJavaVersionAsDouble() >= 1.5
                && MesquiteTrunk.getJavaVersionAsDouble() < 1.6) // due to a JVM bug
            g.fillRect(lastX, lastY - 20, 100, 20);
            g.drawString(MesquiteDouble.toString(lastBL), lastX + 10, lastY);
            if (MesquiteTrunk.isMacOSX()
                && MesquiteTrunk.getJavaVersionAsDouble() >= 1.5
                && MesquiteTrunk.getJavaVersionAsDouble() < 1.6) // due to a JVM bug
            g.fillRect(lastX, lastY - 20, 100, 20);
          }
          double extension =
              Math.sqrt(
                      (newOnLine.y - bY) * (newOnLine.y - bY)
                          + (newOnLine.x - bX) * (newOnLine.x - bX))
                  / lengthLine;
          double bL;
          if (t.getBranchLength(node) == 0 || t.branchLengthUnassigned(node)) bL = extension;
          else bL = t.getBranchLength(node) * extension;
          if (bL > upperLimit) {
            bL = upperLimit;
            if (t.getBranchLength(node) == 0 || t.branchLengthUnassigned(node))
              extension = upperLimit;
            else extension = upperLimit / t.getBranchLength(node);
          } else if (bL < lowerLimit) {
            bL = lowerLimit;
            if (t.getBranchLength(node) == 0 || t.branchLengthUnassigned(node))
              extension = lowerLimit;
            else extension = lowerLimit / t.getBranchLength(node);
          }
          lastBL = bL;
          if (GraphicsUtil.useXORMode(null, false)) {
            drawThickLine(g, ibX, ibY, lastX, lastY);
            for (int daughter = t.firstDaughterOfNode(node);
                t.nodeExists(daughter);
                daughter = t.nextSisterOfNode(daughter))
              drawThickLine(
                  g,
                  treeDisplay.getTreeDrawing().lineTipX[daughter],
                  treeDisplay.getTreeDrawing().lineTipY[daughter],
                  lastX,
                  lastY);
            g.fillOval(
                lastX - ovalRadius,
                lastY - ovalRadius,
                ovalRadius + ovalRadius,
                ovalRadius + ovalRadius);
          }
          int newX = ibX + (int) (extension * (tX - bX));
          int newY = ibY + (int) (extension * (tY - bY));
          if (GraphicsUtil.useXORMode(null, false)) {
            g.drawString(MesquiteDouble.toString(bL), newX + 10, newY);
            drawThickLine(g, ibX, ibY, newX, newY);
            for (int daughter = t.firstDaughterOfNode(node);
                t.nodeExists(daughter);
                daughter = t.nextSisterOfNode(daughter))
              drawThickLine(
                  g,
                  treeDisplay.getTreeDrawing().lineTipX[daughter],
                  treeDisplay.getTreeDrawing().lineTipY[daughter],
                  newX,
                  newY);
            g.fillOval(
                newX - ovalRadius,
                newY - ovalRadius,
                ovalRadius + ovalRadius,
                ovalRadius + ovalRadius);
          }
          lastX = newX;
          lastY = newY;
        }

        // lastX= newOnLine.x;
        // lastY = newOnLine.y;
      }
    }
    return null;
  }
 public void drawThickLine(Graphics g, int fromX, int fromY, int toX, int toY) {
   g.drawLine(fromX, fromY, toX, toY);
   g.drawLine(fromX + 1, fromY, toX + 1, toY);
   g.drawLine(fromX + 2, fromY, toX + 2, toY);
 }
  private boolean recalcPositions(Graphics g) {
    Font f = g.getFont();
    if (f != oldFont || !(StringUtil.stringsEqual(oldText, text))) {
      FontMetrics fm = g.getFontMetrics(f);
      sw = MesquiteInteger.maximum(fm.stringWidth("888"), fm.stringWidth(tf.getText()));
      sh = fm.getMaxAscent() + fm.getMaxDescent();
    }
    oldText = text;
    oldFont = f;
    if (oldTextBoxWidth < sw + MesquiteModule.textEdgeCompensationWidth - 1
        || oldTextBoxHeight < sh + MesquiteModule.textEdgeCompensationHeight - 1) {
      textBoxWidth = sw + MesquiteModule.textEdgeCompensationWidth; // 34
      textBoxHeight = sh + MesquiteModule.textEdgeCompensationHeight; // 18
      oldTextBoxWidth = textBoxWidth;
      oldTextBoxHeight = textBoxHeight;
      if (horizontal) {
        if (stacked) {
          totalWidth = textBoxWidth + EnterButton.MIN_DIMENSION + 2;
          totalHeight = textBoxHeight + 20;
          setSize(totalWidth, totalHeight);
          tf.setSize(textBoxWidth, textBoxHeight);
          tf.setLocation(0, 0);
          decrementButton.setLocation(2, textBoxHeight + 4);
          incrementButton.setLocation(totalWidth - 20, textBoxHeight + 4);
        } else {
          totalWidth = textBoxWidth + 36 + EnterButton.MIN_DIMENSION + 2;
          totalHeight = textBoxHeight + 4;
          setSize(totalWidth, totalHeight);
          tf.setSize(textBoxWidth, textBoxHeight);
          decrementButton.setLocation(0, 2);
          tf.setLocation(
              decrementButton.getBounds().x + decrementButton.getBounds().width + 1,
              0); // 1 added to x
          incrementButton.setLocation(
              tf.getBounds().x + tf.getBounds().width + EnterButton.MIN_DIMENSION + 2,
              2); // 1 added to x
        }
        enterButton.setLocation(tf.getBounds().x + tf.getBounds().width + 1, 2);
      } else {
        if (stacked) {
          totalWidth = textBoxWidth + EnterButton.MIN_DIMENSION + 2;
          totalHeight = textBoxHeight + 20;
          setSize(totalWidth, totalHeight);
          tf.setSize(textBoxWidth, textBoxHeight);
          tf.setLocation(0, 0);
          decrementButton.setLocation(2, textBoxHeight + 4);
          incrementButton.setLocation(totalWidth - 22, textBoxHeight + 4);
          enterButton.setLocation(tf.getBounds().x + tf.getBounds().width + 1, 2);
        } else {
          totalWidth = textBoxWidth; // should be 0
          totalHeight = textBoxHeight + 36 + EnterButton.MIN_DIMENSION + 2;

          setSize(totalWidth, totalHeight);
          tf.setSize(textBoxWidth, textBoxHeight);
          incrementButton.setLocation(1, 2);
          tf.setLocation(0, incrementButton.getBounds().height + 3);
          decrementButton.setLocation(
              1, tf.getBounds().y + tf.getBounds().height + EnterButton.MIN_DIMENSION + 2);
          enterButton.setLocation(1, tf.getBounds().y + tf.getBounds().height + 1);
        }
      }
      incrementButton.repaint();
      decrementButton.repaint();
      enterButton.repaint();
      repaint();
      getParent().repaint();
      return true;
    }
    if (checkBackground()) {
      repaint();
      return true;
    }
    /*	if (!getBackground().equals(getParent().getBackground())) {
    	bg =getParent().getBackground();
    	setBackground(bg);
    	//setBackground(Color.green);
    	tf.setBackground(bg);
    	decrementButton.setBackground(bg);
    	incrementButton.setBackground(bg);
    	enterButton.setBackground(bg);
    	repaint();
    	return true;
    }*/
    return false;
  }