Package ketUI.panel

Source Code of ketUI.panel.AnimatedDisplay

/*
* 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.*;
import javax.swing.*;
import geom.Offset;
import java.awt.image.*;
import java.util.Vector;

import ket.*;
import ket.math.*;
import ket.display.*;
import geom.Position;
import ket.treeDiff.Step;
import ket.display.box.Box;
import ket.treeDiff.TreeDiff;
import ket.display.Transition;
import ket.display.box.BoxText;

/**
* Animate the transitions during argument editing.
*/
public class AnimatedDisplay implements Display {

  static final double ANIMATION_TIME = 250.0; // ms

  static final int TOP = 0x1;
  static final int CENTRE = 0x2;
  static final int BOTTOM = 0x3;

  final MathCollection mathCollection;
 
  /**
   * When the equation is drawn, record its box from which the arguments
   * associated with a mouse click may be determined.
   */
  Box afterRootBox;
  Box equationBox;
  Box labelBox;

  Position equationTopLeft;
  Position topLeft;

  Vector<Transition> transitions;
  boolean repaint;
  long initialTime;
  int view;


  public AnimatedDisplay(MathCollection mathCollection) {
    this.mathCollection = mathCollection;
    initialTime = 0L;
    transitions = null;
    repaint = true;
    view = TOP;
  }

  public void fromTop() {
    view = TOP;
  }

  public void fromMiddle() {
    view = CENTRE;
  }

  public void fromBottom() {
    view = BOTTOM;
  }

  @Override
  public Box findDeepestBox(Position p) {
    return equationBox!=null ? equationBox.findDeepestBox(p) : null;
  }

  @Override
  public Vector<Integer> findVisibleEquationIndices() {
    Vector<Integer> indices = new Vector<Integer>();
    if (equationBox==null) return indices;
    Argument a = equationBox.getArgument();
    if (a==null) return indices;
    Integer index = a.getEquationIndex();
    if (index==null) return indices;
    indices.add(index);
    return indices;
  }

  @Override
  public Argument findDeepestArgument(Position p) {
    return equationBox!=null ? equationBox.findDeepestArgument(p) : null;
  }

  @Override
  public Equation pointToEquation(Position p) {
    Argument argument = equationBox.getArgument();
    return argument!=null ? argument.getEquation() : null;
  }

  public void noteChange(Graphics2D g2D, ColourScheme colourScheme, Argument before, Equation afterEquation, int fontSize, Offset panelRectangle) {
    Argument after = afterEquation.getRoot();
    if (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;
  }

  /**
   * This is called every time the user interacts with the box model, either changing or selecting.
   */
  @Override
  public boolean generateBoxes(Graphics2D g2D, ColourScheme colourScheme, int fontSize, Offset panelRectangle) {
    Equation equation = mathCollection.getCursor().getEquation();
    equationBox = equation.toBox(colourScheme);
    labelBox = equation.getLabelBox(colourScheme);
    labelBox.setProperty(Box.RIGHT_ALIGN);
    equationBox.setupInnerRectangle(fontSize);
    Offset equationRectangle = calcEquationRectangle(panelRectangle);
    labelBox.setup(fontSize, equationRectangle);
    Offset windowWithoutLabel = calcWindowWithoutLabel(equationRectangle);
    equationBox.setupOuterRectangle(windowWithoutLabel);
    equationBox.calcRootOffset();
    double boxHeight = getBoxHeight(equationBox, panelRectangle);
    equationTopLeft = new Position(KetPanel.LEFT_BORDER_SIZE, boxHeight);
    return true;
  }

  private Offset calcEquationRectangle(Offset panelRectangle) {
    double shapeWidth = panelRectangle.width - KetPanel.BORDER_OFFSET.width;
    double minimumHeight = equationBox.getInnerRectangle().height;
    return new Offset(shapeWidth, minimumHeight);
  }

  private Offset calcWindowWithoutLabel(Offset equationRectangle) {
    return new Offset(equationRectangle.width-labelBox.getInnerRectangle().width, equationRectangle.height);
  }

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

  /**
   * Draw a single equation in the centre of the screen or text to the
   * top left.  In either case a label is also displayed.
   */
  @Override
  public void paint(Graphics2D g2D, ColourScheme colourScheme, int fontSize, Offset panelRectangle) {
    if (equationBox==null) {
      // Nothing to paint yet: this is called before an equation was specified.
      return;
    }
    double fractionalTime = (System.currentTimeMillis()-initialTime) / ANIMATION_TIME;
    if (animate(fractionalTime)) {
      repaint = true;
      labelBox.paint(g2D, topLeft, colourScheme);
      // Draw the next frame.
      for (Transition t : transitions) {
        t.animate(g2D, colourScheme, fractionalTime, topLeft);
      }
    } else {
      repaint = false;
      initialTime = 0L;
      labelBox.paint(g2D, equationTopLeft, colourScheme);
      equationBox.paint(g2D, equationTopLeft, colourScheme);
      transitions = null;
    }
  }

  public void processPairs() {
    if (equationBox==null) {
      System.out.println(" !!! null equation box !!! ");
      return;
    }
    TPanel.gui(equationBox);
  }

  private boolean animate(double fractionalTime) {
    if (transitions==null) {
      return false;
    }
    return fractionalTime < 1.0;
  }

  private double getBoxHeight(Box box, Offset panelRectangle) {
    switch (view) {
      case TOP:
        return KetPanel.TOP_BORDER_SIZE;
      case CENTRE:
        double centre = (panelRectangle.height-KetPanel.BORDER_OFFSET.height) / 2.0;
        double heightAboveCentre = box.getOuterRectangle().height / 2.0;
        return centre - heightAboveCentre;
      case BOTTOM:
        double bottom = panelRectangle.height - KetPanel.BORDER_OFFSET.height;
        double heightAboveBottom = box.getOuterRectangle().height;
        return bottom - heightAboveBottom;
      default:
        throw new RuntimeException("Illegal display state.");
    }
  }

  @Override
  public boolean isArgumentVisible(Argument argument) {
    return equationBox.containsArgument(argument);
  }
}
TOP

Related Classes of ketUI.panel.AnimatedDisplay

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.