Package ketUI.panel

Source Code of ketUI.panel.ScrollBar

/*
* 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.Color;
import java.awt.Graphics2D;
import java.util.*;
import java.awt.image.BufferedImage;
import java.awt.geom.AffineTransform;
import java.awt.Image;
import java.awt.AlphaComposite;

import geom.Position;
import ket.Cursor; // TODO: Check that this is the correct package location.
import ket.display.ColourScheme;
import ket.math.Equation;
import ketUI.Document;

/**
* Display information analogous to that of a scrollbar summarizing the visible
* and selected equations within the entire list.  This is displayed in the
* bottom left corner in a minimalistic style of coloured icons.
*/
public class ScrollBar {

  private static final int TEXT = -1;
  private static final int BLANK = -2;

  private static final int ALPHA = 85;
  private static final int MAX_FIGS = 30; // ish
  private static final int ICON_WIDTH = 50; // ish
  private static final int ICON_HEIGHT = 40;

  final Document document;

  final Vector<Integer> selected;
  final Vector<Integer> args;
  final Vector<Integer> invisibleArgs;
  final Vector<Integer> invisibleText;
  final Vector<Integer> text;
  final Vector<Integer> sizes; // The recursiveSize() of every equation.

  final Vector<BufferedImage> figs;

  int n;

  public ScrollBar(Document document) {
    this.document = document;
    selected = new Vector<Integer>();
    args = new Vector<Integer>();
    invisibleArgs = new Vector<Integer>();
    invisibleText = new Vector<Integer>();
    text = new Vector<Integer>();
    sizes = new Vector<Integer>();

    figs = new Vector<BufferedImage>();

    n = 0;
  }

  private ColourScheme getColourScheme() {
    return document.getColourScheme();
  }

  private Vector<Equation> getSelectedEquations() {
    return document.getSelection().getSelectedEquations();
  }

  private Vector<Equation> getEquations() {
    return document.getCursor().getEquationList().getEquations();
  }

  private Vector<Integer> findVisibleEquationIndices() {
    return document.getKetPanel().findVisibleEquationIndices();
  }

  private void update() { // text? {visible?} {selected?} -> selected args invisibleArgs invisibleText text
    selected.clear();
    invisibleArgs.clear();
    invisibleText.clear();
    args.clear();
    text.clear();
    sizes.clear();
    Vector<Equation> equations = getEquations();

    figs.clear();
    ColourScheme colourScheme = getColourScheme();

    n = equations.size();
    Vector<Integer> visible = findVisibleEquationIndices();
    for (int i=0; i<n; i++) {
      Equation e = equations.get(i);
      if (e.isText()) {
        if (e.isBlankLine()) {
          sizes.add(BLANK);
        } else {
          invisibleText.add(i);
          text.add(i);
          sizes.add(TEXT);
        }
        figs.add(null);
      } else {
        args.add(i);
        invisibleArgs.add(i);
        sizes.add(e.getVisibleRoot().recursiveSize());

        // TODO: Expensive: Only evaluate for small numbers of equations.
        //> if (equations.size()<MAX_DRAW_SIZE) {
        //- figs.add(e.toBox(colourScheme).toBufferedImage(width, height, colourScheme));
        figs.add(e.toBox(colourScheme).toBufferedImage(ICON_WIDTH, ICON_HEIGHT, colourScheme, false));
        //> }
      }
    }
    invisibleArgs.removeAll(visible);
    invisibleText.removeAll(visible);
    args.retainAll(visible);
    text.retainAll(visible);
    for (Equation e : getSelectedEquations()) {
      if (e==null) continue; //?
      int v = e.getEquationIndex();
      selected.add(v);
    }
    invisibleArgs.removeAll(selected);
    invisibleText.removeAll(selected);
    args.removeAll(selected);
    text.removeAll(selected);
  }

  public void paint(Graphics2D g2D) {
    update();
    Color argColour = getColourScheme().getArgColour(0);
    Color hightlightColour = getColourScheme().getHighlightedColour(0);
    Color plainTextColour = getColourScheme().getPlainTextColour();
    Color faintArgColour = faint(argColour);
    Color faintTextColour = faint(plainTextColour);
    boolean big = figs.size()>MAX_FIGS;
    haze(g2D, faintTextColour, invisibleText, true, big);
    haze(g2D, plainTextColour, text, true, big);
    haze(g2D, hightlightColour, selected, false, big);

    if (big) {
      haze(g2D, faintArgColour, invisibleArgs, true, big)// errors? Blame ListDisplay.findVisibleEquationIndices().
      haze(g2D, argColour, args, true, big);
    } else {
      hazeFigs(g2D);
    }

  }

  private Color faint(Color colour) {
    int red = colour.getRed();
    int green = colour.getGreen();
    int blue = colour.getBlue();
    return new Color(red, green, blue, ALPHA);
  }

  private float getFraction() {
    switch (n) {
      case 0return 0.0f;
      case 1return 1.0f/32.0f;
      case 2return 1.0f/16.0f;
      case 3return 1.0f/12.0f;
      case 4return 1.0f/8.0f;
      case 5return 1.0f/6.0f;
      case 6return 1.0f/4.5f;
      default: return 1.0f/3.0f;
    }
  }

  private int maxSize() {
    int max = 1;
    for (int i : sizes) {
      if (max<i) {
        max = i;
      }
    }
    return max;
  }

  private int getHeight() {
    return document.getKetPanel().getHeight();
  }

  private float getFractionalHeight() {
    int gap = KetPanel.BOTTOM_BORDER_SIZE-KetPanel.TOP_BORDER_SIZE;
    return (getHeight()-gap) / (float) n;
  }

  private float getYStep() {
    return getFraction()*getFractionalHeight();
  }

  private float getY0() {
    return (1.0f-getFraction())*n*getFractionalHeight();
  }

  private int getY(int i) {
    return (int) (i*getYStep() + getY0());
  }

  private boolean getText(int size, boolean sparse) {
    if (size==TEXT) {
      return true;
    } else if (size==BLANK) {
      return false;
    } else if ( ! sparse ) {
      return false;
    } else {
      return false;
    }
  }

  private boolean getBlank(int size, boolean sparse) {
    if (size==TEXT) {
      return false;
    } else if (size==BLANK) {
      return true;
    } else if ( ! sparse ) {
      return false;
    } else {
      return false;
    }
  }

  private int boundSize(int size, double top, boolean sparse) {
    if (size==TEXT) {
      return (int) top;
    } else if (size==BLANK) {
      return (int) top;
    } else if ( ! sparse ) {
      return (int) top;
    } else {
      return Math.max(size, 2); // size;
    }
  }

  private void hazeFigs(Graphics2D g2D) { // DRY: Evaluate variables repeated in this and the next method as separate methods.
    boolean sparse = false;
    int stride = (int) Math.ceil(n/85.0);
    double top = Math.max(maxSize(), 4.0)+1;
    for (int i=0; i<figs.size(); i++) {
      BufferedImage figure = figs.get(i);
      if (figure==null) continue;
      // x-dx .. x
      // y .. y+u
      int x = (int) (0.8f*KetPanel.LEFT_BORDER_SIZE);
      int y = getY(i);
      int size = sizes.get(i);
      double stretch = Math.log10(boundSize(size, top, sparse)+1) / Math.log10(top);
      int dx = (int) (0.7*KetPanel.LEFT_BORDER_SIZE * stretch);
      int dy = (int) (2.5f*KetPanel.TOP_BORDER_SIZE + 0.5f*getFraction());
      int u = (int) (2.0*Math.min(dx,dy)/5.0);
      Image scaled = figure.getScaledInstance(dx, dy, Image.SCALE_SMOOTH);
      boolean fade = invisibleArgs.contains(i);
      if (fade) {
        AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, ALPHA/256.0f);
        g2D.setComposite(ac);
      }
      g2D.drawImage(scaled, x-dx, y, null);
      if (fade) {
        //-? g2D.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR));
        AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f);
        g2D.setComposite(ac);
      }
    }
  }

  private void haze(Graphics2D g2D, Color colour, Vector<Integer> indices, boolean sparse, boolean big) {
    int stride = (int) Math.ceil(n/85.0);
    double top = Math.max(maxSize(), 4.0)+1;
    for (int i : indices) {
      if (sparse && i%stride!=0) continue;
      g2D.setColor(colour);
      int x = (int) (0.8f*KetPanel.LEFT_BORDER_SIZE);
      int y = getY(i);
      if (i>=sizes.size()) continue; // BUG!
      int size = sizes.get(i);
      double stretch = Math.log10(boundSize(size, top, sparse)+1) / Math.log10(top);
      int dx = (int) (0.7*KetPanel.LEFT_BORDER_SIZE * stretch);
      int dy = (int) (2.5f*KetPanel.TOP_BORDER_SIZE + 0.5f*getFraction());
      int u = (int) (2.0*Math.min(dx,dy)/5.0);
      if (getText(size, sparse)) {
        g2D.fillRect(x-dx, y, dx/2, u/4);
        g2D.fillRect(x+(-dx)+dx/4, y, dx/6, (15*u)/8);
      } else if (big) {
        int[] xs = new int[]{x, x-dx, x-u, x, x};
        int[] ys = new int[]{y, y, y+u, y+u, y};
        if (getBlank(size, sparse)) {
          g2D.drawPolygon(xs, ys, 4);
        } else if (big) {
          g2D.fillPolygon(xs, ys, 4);
        }
      }
    }
  }

  public Equation pointToEquation(Position p) {
    if (KetPanel.LEFT_BORDER_SIZE < p.x) return null;
    float y0 = getY0();
    float yStep = getYStep();
    int i = (int) Math.round(( p.y - y0 - yStep/2 ) / yStep);
    if (i==-1) i=0; // add a little margin for error.
    if (i<0) return null;
    Vector<Equation> equations = getEquations();
    if (equations.isEmpty()) return null;
    if (i>=n) return equations.lastElement();
    return i<equations.size() ? equations.get(i) : null;
  }

}
TOP

Related Classes of ketUI.panel.ScrollBar

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.