Package ketUI.panel

Source Code of ketUI.panel.ListDisplay

/*
* 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 ket.treeDiff.Step;
import ket.treeDiff.TreeDiff;
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 ListDisplay implements Display {

  static final double ANIMATION_TIME = 250.0; // ms

  final MathCollection mathCollection;

  final Top top;
  final Middle middle;
  final Bottom bottom;

  Align align;
  Box afterRootBox;
  Box equationBox;
  Box labelBox;
  Position equationTopLeft;
  volatile Set<BoxEquation> boxSet;
  Vector<Transition> transitions;
  boolean animate;
  boolean repaint;
  int bottomBoxIndex;
  int initialBoxIndex;
  int middleBoxIndex;
  long initialTime;

  public ListDisplay(MathCollection mathCollection) {
    this.mathCollection = mathCollection;
    top = new Top(this);
    middle = new Middle(this);
    bottom = new Bottom(this);
    align = top;
    boxSet = null;
    initialTime = 0L;
    transitions = null;
    repaint = true;
    animate = false;
    initialBoxIndex = 0;
    middleBoxIndex = 0;
    bottomBoxIndex = 0;
  }

  /**
   * 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 (BoxEquation next : boxSet) {
      Box box = next.getEquationBox();
      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 (BoxEquation next : boxSet) {
      Box match = next.findDeepestBox(p);
      if (match!=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 (BoxEquation 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 (BoxEquation next : boxSet) {
      //?- if (animate) continue;
      //? if (equationBox.getArgument()!=null && next.getEquation()==equationBox.getArgument().getEquation()) continue;
      Box equationPart = next.getEquationBox();
      if (equationPart==null) {
        Ket.out.println("[pointToEquation::null box-set element]");
        continue;
      }
      Argument argument = equationPart.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;
  }

  /**
   * 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()) {
    boxSet = align.paint(g2D, colourScheme, fontSize, panelRectangle);
    Equation equation = mathCollection.getCursor().getEquation(); //q
    if (equation==null) { System.out.print(" #2187 "); return false; } // BUG?
    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; } // BUG? // <-- (1)
    labelBox.setup(fontSize, equationRectangle);
    if (equationBox.getInnerRectangle()==null) { System.out.print(" #0391 "); return false; } // BUG?    // <-- (2)
    Offset windowWithoutLabel = calcWindowWithoutLabel(equationRectangle);
    if (windowWithoutLabel==null) { System.out.print(" #9104 "); return false; } // BUG?
    equationBox.setupOuterRectangle(windowWithoutLabel);
    equationBox.calcRootOffset();
    }
    return true;
  }

  @Override
  public void paint(
      Graphics2D g2D,
      ColourScheme colourScheme,
      int fontSize,
      Offset panelRectangle) {

    Position position = null; // <--- Locally repurpose (q) version.
    if (boxSet!=null) {
      for (BoxEquation boxEquation : boxSet) {
        if (animate && boxEquation.getEquation()==equationBox.getArgument().getEquation()) {
          position = boxEquation.getTopLeft();
        } else {
          boxEquation.paint(g2D, colourScheme);
        }
      }
    }
    if (equationBox!=null && position!=null) {
      double fractionalTime = (System.currentTimeMillis()-initialTime) / ANIMATION_TIME;
      if (transitions!=null && fractionalTime<1.0) {
        repaint = true;
        labelBox.paint(g2D, position, colourScheme);
        // Draw the next frame.
        for (Transition t : transitions) {
          t.animate(g2D, colourScheme, fractionalTime, position);
        }
      } else {
        repaint = false;
        initialTime = 0L;
        labelBox.paint(g2D, position, colourScheme);
        equationBox.paint(g2D, position, colourScheme);
        transitions = null;
      }
    }
  }

  public Align getAlign() {
    return align;
  }

  public void fromTop(int initialBoxIndex) {
    align = top;
    this.initialBoxIndex = initialBoxIndex;
  }

  public void fromMiddle(int middleBoxIndex) {
    align = middle;
    this.middleBoxIndex = middleBoxIndex;
  }

  public void fromBottom(int bottomBoxIndex) {
    align = bottom;
    this.bottomBoxIndex = bottomBoxIndex;
  }

  public void moveViewUp() {
    align.moveViewUp();
  }

  public void moveViewDown() {
    align.moveViewDown();
  }

  @Override
  public boolean isArgumentVisible(Argument argument) {
    if (boxSet==null) {
      System.out.println("[null box set]");
      return false;
    }
    for (BoxEquation boxEquation : boxSet) {
      Box box = boxEquation.getEquationBox();
      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 = getLogicalIndex();
    if (currentIndex<0) {
      currentIndex = 0;
    }
    if (currentIndex>=equationList.size()) {
      currentIndex = equationList.size() - 1;
    }
    Equation e = equationList.getEquations().get(currentIndex);
    cursor.setCurrent(e.getVisibleRoot());
  }

  private int getLogicalIndex() {
    if (align==top) {
      return initialBoxIndex;
    } else if (align==middle) {
      return middleBoxIndex;
    } else {
      return bottomBoxIndex;
    }
  }

  public void viewEquation(int index) {
    if (align==top) {
      this.initialBoxIndex = bound(index, 0, getNumberOfEquations());
    } else if (align==middle) {
      this.middleBoxIndex = bound(index, 0, getNumberOfEquations());
    } else if (align==bottom) {
      this.bottomBoxIndex = bound(index, 0, getNumberOfEquations());
    }
  }

  @Override
  public boolean requiresRepaint() {
    return animate && 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 ( !animate || !isSingleSelectionSet() || before.subBranchEquals(after) || afterEquation.isText()) { //+ Did the equation change?
      transitions = null;
      afterRootBox = null;
      return;
    }
    afterRootBox = after.toBox(0L, colourScheme);
    labelSetup(afterEquation, colourScheme);
    Offset windowWithoutLabel = afterBoxSetup(fontSize, panelRectangle);
    Box beforeRootBox = beforeBoxSetup(g2D, colourScheme, before, fontSize, windowWithoutLabel);
    initialTime = System.currentTimeMillis();
    TreeDiff treeDiff = new TreeDiff(before, after);
    transitions = treeDiff.getTransitions(beforeRootBox, afterRootBox);
  }

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

  /**
   * Setup the box that represents the previous state.
   */
  private Box beforeBoxSetup(Graphics2D g2D, ColourScheme colourScheme, Argument before, int fontSize, Offset windowWithoutLabel) {
    Box beforeRootBox = before.toBox(0L, colourScheme);
    beforeRootBox.setupInnerRectangle(fontSize);
    beforeRootBox.setupOuterRectangle(windowWithoutLabel);
    beforeRootBox.calcRootOffset();
    return beforeRootBox;
  }

  /**
   * 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();
    //- topLeft = new Position(KetPanel.LEFT_BORDER_SIZE, getBoxHeight(afterRootBox, panelRectangle));
    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) {
    if (align==top) {
      return KetPanel.TOP_BORDER_SIZE;
    } else if (align==middle) {
      double centre = (panelRectangle.height-KetPanel.BORDER_OFFSET.height) / 2.0;
      double heightAboveCentre = box.getOuterRectangle().height / 2.0;
      return centre - heightAboveCentre;
    } else {
      double bottom = panelRectangle.height - KetPanel.BORDER_OFFSET.height;
      double heightAboveBottom = box.getOuterRectangle().height;
      return bottom - heightAboveBottom;
    }
  }

  /**
   * 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 int getNumberOfEquations() {
    Selection selection = mathCollection.getSelection();
    return selection.getEquationList().size();
  }

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

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

  public int getInitialBoxIndex() {
    return initialBoxIndex;
  }

  public int getMiddleBoxIndex() {
    return middleBoxIndex;
  }

  public int getFinalBoxIndex() {
    return bottomBoxIndex;
  }

  public MathCollection getMathCollection() {
    return mathCollection;
  }

}
TOP

Related Classes of ketUI.panel.ListDisplay

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.