Package ketUI.panel

Source Code of ketUI.panel.ScatterDisplay

/*
* Copyright (C) 2011  Alasdair C. Hamilton
*
* 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 3 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, see <http://www.gnu.org/licenses/>
*/

package ketUI.panel;


import java.awt.image.*;
import java.util.Vector;
import java.util.*;
import java.awt.Graphics2D;

import geom.Position;
import geom.Offset;

import ket.*;
import ket.display.*;
import ket.display.Transition;
import ket.display.box.Box;
import ket.display.box.BoxText;
import ket.math.*;
import ketUI.Ket;

/**
* A list of equations may be displayed by this class which organizes and draws
* them relative to the top, centre or bottom of the screen.
*/
public class ScatterDisplay implements Display {

  static final int LIMIT = 30;
  static final double ANIMATION_TIME = 250.0; // ms
  static final double BOX_GAP = 10;
  static final Vector<Double> T_COL = positiveIntegers();

  public static Vector<Double> positiveIntegers() {
    Vector<Double> tCol = new Vector<Double>();
    for (int i=0; i<LIMIT; i++) {
      tCol.add(new Double(i));
    }
    return tCol;
  }

  boolean update; //?

  final MathCollection mathCollection;
  final PanelDecoration panelDecoration;

  volatile IdentityHashMap<Box, Equation> boxToEquation = new IdentityHashMap<Box, Equation>();
  volatile IdentityHashMap<Equation, Position> equationToPosition = new IdentityHashMap<Equation, Position>();


  Box afterRootBox;
  Box equationBox;
  Box labelBox;
  Position equationTopLeft;
  volatile Set<Box> boxSet;
  boolean repaint;
  int bottomBoxIndex;
  int initialBoxIndex;
  int middleBoxIndex;

  public ScatterDisplay(MathCollection mathCollection, PanelDecoration panelDecoration) {
    this.mathCollection = mathCollection;
    this.panelDecoration = panelDecoration;
    boxSet = null;
    repaint = true;
    initialBoxIndex = 0;
    middleBoxIndex = 0;
    bottomBoxIndex = 0;
    update = false;
  }

  /**
   * Find the equation that is closest to the given point on the
   * ketPanel.
   */
  @Override
  public Equation pointToEquation(Position p) {
    Equation e = null;
    Double bestTop = null;
    for (Box box : boxSet) {
      if (box==null) continue;
      if (box.getTopLeft()==null) continue;
      double top = box.getTopLeft().y;
      if (top<p.y && (bestTop==null || bestTop<top)) {
        e = box.getArgument().getEquation();
        Ket.out.println(e);
        bestTop = top;
      }
    }
    return e;
  }

  /*
   * Look through boxSet and while a box contains the location within its
   * inner rectangle, return that box.
   */
  @Override
  public Box findDeepestBox(Position p) {
    for (Box next : boxSet) {
      Box match = next.findDeepestBox(p);
      if (match!=null && match.getArgument()!=null) {
        return match;
      }
    }
    return null;
  }

  /*
   * Look through boxSet and while a box contains the location within its
   * inner rectangle, return that box.
   */
  @Override
  public Argument findDeepestArgument(Position p) {
    for (Box next : boxSet) {
      Argument match = next.findDeepestArgument(p);
      if (match!=null) {
        return match;
      }
    }
    return null;
  }

  @Override
  public Vector<Integer> findVisibleEquationIndices() {
    Vector<Integer> indices = new Vector<Integer>();
    if (boxSet==null) {
      Ket.out.println("[findVisibleEquationIndices::null box-set]");
      return indices;
    }
    for (Box next : boxSet) {
      if (next==null) {
        Ket.out.println("[pointToEquation::null box-set element]");
        continue;
      }
      Argument argument = next.getArgument();
      if (argument==null) {
        Ket.out.println("[pointToEquation::null box-set argument]");
        continue;
      }
      Integer index = argument.getEquationIndex(); //NOTE: Integer, not int
      if (index==null) {
        Ket.out.println("[pointToEquation::null box-set index]");
        continue;
      }
      indices.add(index);
    }
    return indices;
  }

  public void dragTo(Equation e, Position p) {
    if (equationToPosition.containsKey(e)) {
      // Find the centre of the equation's box
      for (Box b : boxToEquation.keySet()) {
        if (boxToEquation.get(b)!=e) continue;
        Offset inner = b.getInnerRectangle();
        if (inner==null) continue;
        Position q = p.minus(inner.getCentre());
        equationToPosition.put(e, q);
        return;
      }
    }
    equationToPosition.put(e, p);
  }

  public void clear() {
    boxToEquation.clear();
    equationToPosition.clear();
  }

  /**
   * This is called every time the user interacts with the box model, either changing or selecting.
   */
  @Override
  public synchronized boolean generateBoxes(Graphics2D g2D, ColourScheme colourScheme, int fontSize, Offset panelRectangle) {
    synchronized (mathCollection.getSelection()) {
      boxToEquation.clear();
      boxSet = createBox(colourScheme, fontSize, panelRectangle);
      Equation equation = mathCollection.getCursor().getEquation(); //q
      if (equation==null) { System.out.print(" #2187 "); return false; }
      equationBox = equation.toBox(colourScheme);
      labelBox = equation.getLabelBox(colourScheme);
      labelBox.setProperty(Box.RIGHT_ALIGN);
      equationBox.setupInnerRectangle(fontSize);
      Offset equationRectangle = calcEquationRectangle(panelRectangle);
      if (equationRectangle==null) { System.out.print(" #9862 "); return false; }
      labelBox.setup(fontSize, equationRectangle);
      if (equationBox.getInnerRectangle()==null) { System.out.print(" #0391 "); return false; }
      Offset windowWithoutLabel = calcWindowWithoutLabel(equationRectangle);
      if (windowWithoutLabel==null) { System.out.print(" #9104 "); return false; }
      equationBox.setupOuterRectangle(windowWithoutLabel);
      equationBox.calcRootOffset();
    }
    if (update) {
      repaint = true;
      synchronized (e2ps) {
      for (Vector<Position> v : e2ps.values()) {
        v.clear();
      }
      }
    }
    return true;
  }

  static final double ADDITIONAL_EQUATION_GAP = 10.0;

  public boolean hasOverlap(Offset panelRectangle) {
    boolean changed = false;
    // If any of the boxes are now too big for the window, shift them inwards. 
    double cx = KetPanel.LEFT_BORDER_SIZE;
    double cy = KetPanel.TOP_BORDER_SIZE;
    for (Box b : boxSet) { // Move boxes away from edges.
      Equation e = boxToEquation.get(b);
      if (e==null) continue;
      Position p = equationToPosition.get(e);
      if (p==null) continue;
      Offset inner = b.getInnerRectangle();
      double mx = panelRectangle.width-KetPanel.LEFT_BORDER_SIZE-KetPanel.RIGHT_BORDER_SIZE - inner.width;
      double my = panelRectangle.height-KetPanel.TOP_BORDER_SIZE-KetPanel.BOTTOM_BORDER_SIZE - inner.height - panelDecoration.getModeBoxHeight();
      //- p.x = bound(p.x, KetPanel.LEFT_BORDER_SIZE, mx);
      if (p.x<KetPanel.LEFT_BORDER_SIZE) {
        return true;
      } else if (p.x>mx) {
        return true;
      }
      //- p.y = bound(p.y, KetPanel.TOP_BORDER_SIZE, my);
      if (p.y<KetPanel.TOP_BORDER_SIZE) {
        return true;
      } else if (p.y>my) {
        return true;
      }
    }

    Vector<Box> bs = new Vector<Box>(boxSet);
    for (int i=0; i<bs.size(); i++) { // Move boxses apart.
      Box bA = bs.get(i);
      Equation eA = boxToEquation.get(bA);
      if (eA==null) continue;
      Position pA = equationToPosition.get(eA);
      if (pA==null) continue;
      Offset innerA = bA.getInnerRectangle();
      for (int j=i+1; j<bs.size(); j++) { // Move boxses apart.
        Box bB = bs.get(j);
        Equation eB = boxToEquation.get(bB);
        if (eB==null) continue;
        Position pB = equationToPosition.get(eB);
        if (pB==null) continue;
        Offset innerB = bB.getInnerRectangle();

        Position rA = bA.getPosition(pA);
        Position rB = bB.getPosition(pB);
        Offset iA = bA.getInnerRectangle();
        Offset iB = bB.getInnerRectangle();

        // Positive overlap values are errors.
        boolean overlap1 = rB.x + iB.width + ADDITIONAL_EQUATION_GAP > rA.x;
        boolean overlap2 = rA.x + iA.width + ADDITIONAL_EQUATION_GAP > rB.x;
        boolean overlap3 = rB.y + iB.height + ADDITIONAL_EQUATION_GAP > rA.y;
        boolean overlap4 = rA.y + iA.height + ADDITIONAL_EQUATION_GAP > rB.y;

        if (overlap1 && overlap2 && overlap3 && overlap4) {
          return true;
        }
      }
    }
    return changed;
  }

  public synchronized Vector<Map.Entry<Box,Equation>> getEs() {
    try {
      return new Vector<Map.Entry<Box,Equation>>(boxToEquation.entrySet());
    } catch (ConcurrentModificationException e) { //? Why
      System.out.print(".");
      return null;
    } catch (NoSuchElementException e) { //? Why
      System.out.print(".");
      return null;
    }
  }

  public synchronized void perturbLoop(double scale, Offset panelRectangle, int n) {
    // All perturbations are judged by sum of square of costs:
    synchronized (mathCollection.getSelection()) {
    double x0 = KetPanel.LEFT_BORDER_SIZE;
    double y0 = KetPanel.TOP_BORDER_SIZE;
    // BUG? Why isn't RIGHT_BORDER_SIZE and BOTTOM_BORDER_SIZE not used here:
    double dx = panelRectangle.width - KetPanel.LEFT_BORDER_SIZE - KetPanel.RIGHT_BORDER_SIZE;
    double dy = panelRectangle.height - KetPanel.TOP_BORDER_SIZE - KetPanel.BOTTOM_BORDER_SIZE - panelDecoration.getModeBoxHeight();
    Position centre = new Position(x0+dx/2.0, y0+dy/2.0);
    EquationList el = getMathCollection().getSelection().getEquationList();
    Vector<Map.Entry<Box,Equation>> es = getEs();
    if (es==null) return;
    Vector<Position> ends = calcEnds(es, el);
    Vector<Box> theBoxes = new Vector<Box>();
    Vector<Equation> theEquations = new Vector<Equation>();
    Vector<Position> thePositions = new Vector<Position>();
    for (Map.Entry<Box,Equation> entry : es) {
      Box box = entry.getKey();
      Equation e = entry.getValue();
      if (e==null) {
        System.out.print("null");
        boxToEquation.remove(box);
        continue;
      }
      if (e.getEquationList()!=el) {
        System.out.print("e");
        boxToEquation.remove(box);
        continue;
      }
      Position p = equationToPosition.get(e);
      if (p==null) {
        System.out.print("p");
        boxToEquation.remove(box);
        continue;
      }
      theBoxes.add(box);
      theEquations.add(e);
      thePositions.add(p);
    }
    for (int loop=0; loop<n; loop++) {
      Vector<Position> allPs = new Vector<Position>();
      Vector<Position> allQs = new Vector<Position>();
      for (int i=0; i<theBoxes.size(); i++) {
        Box box = theBoxes.get(i);
        Equation e = theEquations.get(i);
        Position p = thePositions.get(i);
        Offset inner = box.getInnerRectangle();
        Position q = shift(p, scale);
        double costQ = calcCost(q, centre, ends, dx, dy, inner);
        double costP = calcCost(p, centre, ends, dx, dy, inner);
        if (costQ <= costP) {
          allPs.add(p);
          allQs.add(q);
        }
      }
      for (int i=0; i<allPs.size(); i++) {
        Position p = allPs.get(i);
        Position q = allQs.get(i);
        p.x = (1.0*q.x+2.0*p.x) / 3.0;
        p.y = (1.0*q.y+2.0*p.y) / 3.0;
      }
    }

    if (true) { //D
    for (Map.Entry<Box,Equation> entry : es) {
      Box box = entry.getKey();
      Equation e = entry.getValue();
      if (e==null) continue;
      Position p = equationToPosition.get(e);
      if (p==null) continue;
      Vector<Position> ps = e2ps.get(e);
      if (ps==null) {
        ps = new Vector<Position>();
        e2ps.put(e, ps);
      }
      ps.add(new Position(p));
      if (ps.size()>HISTORY) {
        ps.removeElementAt(0);
      }

      //D System.out.println(e.getEquationIndex() + "\t" + p.x + "\t" + p.y); //D
    }
    }
  }
  }
  static final int HISTORY = 20;

  IdentityHashMap<Equation, Vector<Position>> e2ps = new IdentityHashMap<Equation, Vector<Position>>();

  public static double calcMean(List<Double> changes) {
    double sum = 0.0;
    for (double x : changes) {
      sum += x;
    }
    return sum / changes.size();
  }

  public static double calcStdev(List<Double> changes) {
    double mean = calcMean(changes);
    double err = 0.0;
    for (double x : changes) {
      err += sq(x - mean);
    }
    err /= changes.size();
    err = Math.sqrt(err);
    return err;
  }

  public Vector<Position> calcEnds(Vector<Map.Entry<Box,Equation>> es, EquationList el) {
    Vector<Position> ends = new Vector<Position>();
    for (Map.Entry<Box,Equation> entry : es) {
      Box box = entry.getKey();
      Equation e = entry.getValue();
      if (e==null) continue;
      if (e.getEquationList()!=el) continue;
      Position p = equationToPosition.get(e);
      if (p==null) continue;
      Offset inner = box.getInnerRectangle();
      ends.add(new Position(p.x + inner.width/2.0, p.y + inner.height/2.0));
    }
    return ends;
  }

  public Position shift(Position p, double scale) {
    double deltaX = scale * (Math.random()-0.5);
    double deltaY = scale * (Math.random()-0.5);
    return new Position(p.x+deltaX, p.y+deltaY);
  }

  public double calcCost(Position p, Position centre, Vector<Position> ends, double dx, double dy, Offset inner) {
    Position pMid = new Position(p.x+inner.width/2.0, p.y+inner.height/2.0);
    double costP = sq(Position.length(centre, pMid)) / 100000.0;
    double fpX = (p.x-KetPanel.LEFT_BORDER_SIZE)/(dx-inner.width - KetPanel.LEFT_BORDER_SIZE - KetPanel.RIGHT_BORDER_SIZE);
    double fpY = (p.y-KetPanel.TOP_BORDER_SIZE)/(dy-inner.height - KetPanel.TOP_BORDER_SIZE - KetPanel.BOTTOM_BORDER_SIZE);
    if (fpX<0.0 || fpX>1.0) costP += 1.0e4 * sq(Math.abs(fpX-0.5));
    if (fpY<0.0 || fpY>1.0) costP += 1.0e4 * sq(Math.abs(fpY-0.5));
    for (Position end : ends) {
      double lenP = Position.length(end, pMid);
      costP += 10000.0*Math.min(1000.0 , 1.0/sq(lenP));
    }
    return costP;
  }

  public static double sq(double x) {
    return x*x;
  }

  public Set<Box> createBox(ColourScheme colourScheme, int fontSize, Offset panelRectangle) {
    Set<Box> set = Collections.synchronizedSet(new HashSet<Box>());
    for (int boxIndex=0; boxIndex<getNumberOfEquations(); boxIndex++) {
      Equation equation = getEquation(boxIndex);
      if (equation==null) continue;
      Box box = equation.toBox(colourScheme);
      box.setupInnerRectangle(fontSize);
      Offset equationRectangle = box.getInnerRectangle();
      box.setupOuterRectangle(equationRectangle);
      set.add(box);
      if (box==null) continue;
      if (!equationToPosition.containsKey(equation)) {
        Position p = suitableVoid(box, boxIndex, panelRectangle, set);
        equationToPosition.put(equation,  p);
      }
      boxToEquation.put(box, equation);
    }
    return Collections.unmodifiableSet(set);
  }

  public Position suitableVoid(Box box, int boxIndex, Offset panelRectangle, Set<Box> set) {
    Offset inner = box.getInnerRectangle();
    if (inner==null) { // Never called, but just in case.
      inner = new Offset(0.0, 0.0);
    }
    double cx = KetPanel.LEFT_BORDER_SIZE;
    double mx = panelRectangle.width-KetPanel.LEFT_BORDER_SIZE-KetPanel.RIGHT_BORDER_SIZE-inner.width;
    //- double cy = KetPanel.TOP_BORDER_SIZE + inner.height;
    double cy = KetPanel.TOP_BORDER_SIZE;
    double my = panelRectangle.height-KetPanel.TOP_BORDER_SIZE-KetPanel.BOTTOM_BORDER_SIZE-inner.height - panelDecoration.getModeBoxHeight();
    //! double dy = panelRectangle.height - KetPanel.TOP_BORDER_SIZE - KetPanel.BOTTOM_BORDER_SIZE - panelDecoration.getModeBoxHeight();
    if (set==null) {
      return new Position(mx/2.0+cx, my/2.0+cy); // fail
    }
    Vector<Box> oldAndNewBoxes = new Vector<Box>();
    if (boxSet!=null) {
      oldAndNewBoxes.addAll(boxSet);
    }
    oldAndNewBoxes.addAll(set);
    double bestDistance = 0.0;
    Position bestPosition = new Position(Math.random()*mx+cx, Math.random()*my+cy);
    Equation equation = boxToEquation.get(box);
    Position topLeft = equationToPosition.get(equation);
    for (int i=0; i<20; i++) { // Filter for non-overlapping locations, returning the one furthest from existing boxes.
      Position p = new Position(Math.random()*mx+cx, Math.random()*my+cy);
      boolean outside = true;
      // For the given position and box, find the nearest existing box.
      double distance = 0.0;
      for (Box b : oldAndNewBoxes) {
        if (b==box) continue;
        if (b.innerBoxesOverlap(box)) {
          outside = false;
          break;
        }
        Equation e = boxToEquation.get(b);
        Position tl = equationToPosition.get(e);
        double d = Position.length(box.getCentre(topLeft), b.getCentre(tl));
        distance = Math.min(distance, d);
      }
      if (outside && distance > bestDistance) {
        bestDistance = distance;
        bestPosition = p;
      }
    }
    //- return new Position(Math.random()*mx+cx, Math.random()*my+cy); // fail
    return bestPosition;
  }

  protected Equation getEquation(int index) { //< Align
    Selection selection = getMathCollection().getSelection();
    return selection.getEquationList().getEquation(index);
  }

  // Linear regression of x and y to find gradient, m, in y=m*x+c.
  public double regressGradient(Vector<Double> xCol, Vector<Double> yCol) {
    double xySum = 0.0;
    double xSum = 0.0;
    double ySum = 0.0;
    double xSqSum = 0.0;
    int n = Math.min(xCol.size(), yCol.size());
    for (int i=0; i<n; i++) {
      double x = xCol.get(i);
      double y = yCol.get(i);
      xySum += x*y;
      xSum += x;
      ySum += y;
      xSqSum += x*x;
    }
    double numerator = xySum - xSum*ySum/n;
    double denominator = xSqSum - xSum*xSum/n;
    return numerator/denominator;
  }

  // Find gradient, m, from sample points (x,y) on a line, y=m*x+c.  Note that c=mean(ys)-m*mean(xs).
  public static double linearRegression(Vector<Position> ps) { // Version II (testing purposes)
    double sumX = 0.0;
    double sumY = 0.0;
    double sumXY = 0.0;
    double sumX2 = 0.0;
    int n = ps.size();
    for (Position p : ps) {
      double x = p.x;
      double y = p.y;
      sumX += x;
      sumY += y;
      sumXY += x*y;
      sumX2 += x*x;
    }
    return (sumXY - sumX*sumY/n) / (sumX2 - sumX*sumX/n);
  }

  public boolean calcBiggest() {
    double biggest = 0.0;
    for (Box box : boxSet) {
      Equation e = boxToEquation.get(box);
      if (e==null) continue;
      Position p = equationToPosition.get(e);
      if (p==null) continue;
      Vector<Position> ps = e2ps.get(e);
      if (ps==null) return false;
      if (ps.size()<HISTORY) return false;
      int n = ps.size();

      double tSum = 0.0;
      double txSum = 0.0;
      double tySum = 0.0;
      double tSqSum = 0.0;
      double xSum = 0.0;
      double ySum = 0.0;
      for (int t=0; t<n; t++) {
        tSum += t;
        tSqSum += t*t;
        Position q = ps.get(t);
        double x = q.x;
        double y = q.y;
        txSum += t*x;
        tySum += t*y;
        xSum += x;
        ySum += y;
      }
      double denominator = tSqSum - tSum*tSum/n;
      double mX = (txSum - tSum*xSum/n)/denominator;
      double mY = (tySum - tSum*ySum/n)/denominator;

      double m2 = mX*mX + mY*mY;

      if (m2 > biggest) {
        biggest = m2;
      }
    }
    return biggest < 0.01; //D
  }

  @Override
  public void paint(Graphics2D g2D, ColourScheme colourScheme, int fontSize, Offset panelRectangle) {
    if (boxSet==null) return;
    for (Box box : boxSet) {
      Equation equation = boxToEquation.get(box);
      if (equation==null) continue;
      Position topLeft = equationToPosition.get(equation);
      if (topLeft==null) continue;
      box.paint(g2D, topLeft, colourScheme);
    }
    if (update) {
      if (calcBiggest()) {
        repaint = false;
        //- System.out.println("[pause]");
      } else {
        repaint = true;
        perturbLoop(0.01, panelRectangle, 1000);
      }
    } else if (hasOverlap(panelRectangle)) {
      repaint = true;
      perturbLoop(0.01, panelRectangle, 1000);
    } else {
      repaint = false;
    }
  }

  @Override
  public boolean isArgumentVisible(Argument argument) {
    if (boxSet==null) {
      System.out.println("[null box set]");
      return false;
    }
    for (Box box : boxSet) {
      if (box.containsArgument(argument)) {
        return true;
      }
    }
    return false;
  }

  /**
   * Set the current argument from the logically significant index of
   * visible equations.
   */
  public void selectByVisible(Cursor cursor, EquationList equationList) {
    int currentIndex = 0;
    if (currentIndex<0) {
      currentIndex = 0;
    }
    if (currentIndex>=equationList.size()) {
      currentIndex = equationList.size() - 1;
    }
    Equation e = equationList.getEquations().get(currentIndex);
    cursor.setCurrent(e.getVisibleRoot());
  }


  @Override
  public boolean requiresRepaint() {
    return repaint;
  }

  // --------------------
  // --- SIFTING, 'V' ---
  // --------------------

  Vector<Equation> equations = null;

  /**
   * This provides a list of equations that are to be displayed (or all
   * if equations is null).
   */
  public void setVisibleEquations(Vector<Equation> equations) {
    this.equations = equations;
  }

  public Vector<Equation> getVisibleEquations() {
    return equations;
  }

  @Override
  public void noteChange(Graphics2D g2D, ColourScheme colourScheme, Argument before, Equation afterEquation, int fontSize, Offset panelRectangle) {
    Argument after = afterEquation.getRoot();
    if ( !isSingleSelectionSet() || before.subBranchEquals(after) || afterEquation.isText()) { //+ Did the equation change?
      afterRootBox = null;
      return;
    }
    afterRootBox = after.toBox(0L, colourScheme);
    labelSetup(afterEquation, colourScheme);
    afterBoxSetup(fontSize, panelRectangle);
  }

  private void labelSetup(Equation afterEquation, ColourScheme colourScheme) {
    labelBox = afterEquation.getLabelBox(colourScheme);
    labelBox.setProperty(Box.RIGHT_ALIGN);
    labelBox.setProperty(Box.Y_CENTRE_ALIGN);
  }

  /**
   * Animate the box that represents the new state.
   */
  private Offset afterBoxSetup(int fontSize, Offset panelRectangle) {
    double shapeWidth = panelRectangle.width - KetPanel.BORDER_OFFSET.width;
    afterRootBox.setupInnerRectangle(fontSize);
    double minimumHeight = afterRootBox.getInnerRectangle().height;
    Offset equationRectangle = new Offset(shapeWidth, minimumHeight);
    labelBox.setup(fontSize, equationRectangle);
    Offset windowWithoutLabel = calcWindowWithoutLabel(equationRectangle);
    afterRootBox.setupOuterRectangle(windowWithoutLabel);
    afterRootBox.calcRootOffset();
    return windowWithoutLabel;
  }

  private Offset calcEquationRectangle(Offset panelRectangle) {
    if (equationBox==null) { System.out.print(" #0291 "); return null; }
    double shapeWidth = panelRectangle.width - KetPanel.BORDER_OFFSET.width;
    if (equationBox.getInnerRectangle()==null) { System.out.print(" #4921 "); return null; } // <-- (1)
    double minimumHeight = equationBox.getInnerRectangle().height; // BUG: innterRectangle can be null!
    return new Offset(shapeWidth, minimumHeight);
  }

  private Offset calcWindowWithoutLabel(Offset equationRectangle) {
    if ( equationRectangle==null ) { System.out.print(" #1342 "); return null; } // BUG?
    if ( labelBox==null ) { System.out.print(" #4382 "); return null; } // BUG?
    if ( labelBox.getInnerRectangle()==null ) { System.out.print(" #9889 "); return null; } // BUG?
    return new Offset(equationRectangle.width-labelBox.getInnerRectangle().width, equationRectangle.height);
  }

  private double getBoxHeight(Box box, Offset panelRectangle) {
    return KetPanel.TOP_BORDER_SIZE;  //?
  }

  /**
   * Restrict the value of index within [min, max).
   */
  private int bound(int index, int min, int max) {
    if (index <= min) {
      return min; 
    } else if (max <= index) {
      return max;
    } else {
      return index;
    }
  }

  private double bound(double index, double min, double max) {
    return Math.min(Math.max(index, min), max);
  }

  private int getNumberOfEquations() {
    Selection selection = mathCollection.getSelection();
    return selection.getEquationList().size();
  }

  private Selection getSelection() {
    return mathCollection.getSelection();
  }

  private boolean isSingleSelectionSet() {
    return mathCollection.isSingleSelectionSet();
  }

  public MathCollection getMathCollection() {
    return mathCollection;
  }

  public void viewEquation(int index) { }
  public void moveViewUp() { }
  public void moveViewDown() { }

  public void toggleScatter() {
    update = ! update;
    if (update==false) {
      repaint = false;
    }
  }
}
TOP

Related Classes of ketUI.panel.ScatterDisplay

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.