Package ket.display.box

Source Code of ket.display.box.BoxList

/*
* 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 ket.display.box;

import geom.Offset;
import geom.Position;

import java.awt.*;
import java.util.*;

import ket.display.ColourScheme;
import ket.math.*;
import ketUI.Ket;

/*
* Boxes can be organized within other boxes.  This class allows such
* hierarchical constructions by providing a parent class in which other Boxes
* can be added and aligned.
*/
public class BoxList extends Box {
  Vector<Box> children;
  Vector<Vector<Box>> xAxis;
  Vector<Vector<Box>> yAxis;

  @Override
  public Box cloneBox() {
    BoxList clone = new BoxList(getArgument(), getSettings());
    IdentityHashMap<Box, Box> map = new IdentityHashMap<Box, Box>();
    for (Box child : children) {
      Box childClone = child.cloneBox();
      map.put(child, childClone);
    }
    for (Vector<Box> path : xAxis) {
      Vector<Box> pathClone = new Vector<Box>();
      for (Box step : path) {
        pathClone.add(map.get(step));
      }
      clone.addHorizontalPath(pathClone);
    }
    for (Vector<Box> path : yAxis) {
      Vector<Box> pathClone = new Vector<Box>();
      for (Box step : path) {
        pathClone.add(map.get(step));
      }
      clone.addVerticalPath(pathClone);
    }
    return clone;
  }

  public BoxList(Argument argument, long settings) {
    super(argument, settings);
    children = new Vector<Box>();
    xAxis = new Vector<Vector<Box>>();
    yAxis = new Vector<Vector<Box>>();
  }

  public Vector<Box> getChildren() {
    return new Vector<Box>(children);
  }

  public void addHorizontalPath(Vector<Box> path) {
    xAxis.add(path);
    for (Box child : path) {
      assert child!=null : "Can't add a null child.";
      if ( ! children.contains(child) ) {
        children.add(child);
      }
    }
  }

  public void addVerticalPath(Vector<Box> path) {
    yAxis.add(path);
    for (Box child : path) {
      assert child!=null : "Can't add a null child.";
      if ( ! children.contains(child) ) {
        children.add(child);
      }
    }
  }

  @Override
  protected void fontSetup(int parentFontSize) {
    // Insure that fontSize has been appropriately set.
    super.fontSetup(parentFontSize);
    for (Box child : children) {
      child.fontSetup(fontSize);
   
  }

  /**
   * Determine the smallest size of this component from the largest
   * horizontal and vertical paths through the bounds of its child
   * components.  In order to do so, the minimal sizes of the child
   * components is also evaluated.  The innerRectangle component
   * shouldn't change after this.
   */
  @Override
  protected void calcMinimumSize() {
    for (Box box : children) {
      box.calcMinimumSize();
    }
    setupActualChildBounds();
    alignChildren();
  }
 
  /**
   * Determine the actual sizes of child components.
   */
  private void setupActualChildBounds() {
    for (Vector<Box> path : yAxis) {
      double width = 0.0;
      for (Box child : path) {
        width = Math.max(child.innerRectangle.width, width);
      }
      for (Box child : path) {
        child.setActualWidth(width);
      }
    }
    for (Vector<Box> path : xAxis) {
      double height = 0.0;
      for (Box child : path) {
        height = Math.max(child.innerRectangle.height, height);
      }
      for (Box child : path) {
        child.setActualHeight(height);
      }
    }
  }

  private void alignChildren() {
    for (Box child : children) {
      child.setupOuterRectangle(child.outerRectangle);
      child.parentalShift = new Offset(0.0, 0.0);
    }
    innerRectangle = new Offset(0, 0);
    for (Vector<Box> path : yAxis) {
      double x = 0;
      for (Box child : path) {
        x = Math.max(x, child.outerRectangle.width);
        child.parentalShift.width = innerRectangle.width;
      }
      innerRectangle.width += x;
    }
    for (Vector<Box> path : xAxis) {
      double y = 0;
      for (Box child : path) {
        y = Math.max(y, child.outerRectangle.height);
        child.parentalShift.height = innerRectangle.height;
      }
      innerRectangle.height += y;
    }
  }

  /**
   * Recursively set the current offset relative to that of its parent.
   */
  @Override
  protected void calcRootOffset(Offset parentOffset) {
    super.calcRootOffset(parentOffset);
    for (Box child: children) {
      child.calcRootOffset(getRootOffset());
    }
  }

  protected boolean isBand(Box child) {
    return child.getArgument()==this.getArgument() || child.getArgument()==null;
  }

  @Override
  public void addAllDescendants(Vector<Box> descendents) {
    descendents.add(this);
    for (Box child: children) {
      child.addAllDescendants(descendents);
    }
  }

  @Override
  public void drawBand(Graphics2D g2D, Position topLeft, ColourScheme colourScheme) {
    ColourScheme localCS = getLocalColourScheme(colourScheme);
    for (Box child: children) {
      if (isBand(child)) {
        child.paint(g2D, getPosition(topLeft), localCS);
      }
    }
  }

  @Override
  public void draw(Graphics2D g2D, Position topLeft, ColourScheme colourScheme) {
    ColourScheme localCS = getLocalColourScheme(colourScheme);
    //- drawCross(topLeft, g2D);
    for (Box child: children) {
      child.paint(g2D, getPosition(topLeft), localCS);
    }
  }

  /*-
  public void drawCross(Position topLeft, Graphics2D g2D) {
    int x = (int) getXPosition(topLeft);
    int y = (int) getYPosition(topLeft);
    g2D.drawLine(x, y, x+(int) innerRectangle.width, y+(int) innerRectangle.height);
    g2D.drawLine(x+(int) innerRectangle.width, y, x, y+(int) innerRectangle.height);
  }
  */

  public Band boxesByDepth(Argument a, TreeMap<Integer, Vector<Band>> map, Position topLeft, ColourScheme colourScheme) {
    Band band = super.boxesByDepth(a, map, topLeft, colourScheme);
    ColourScheme localCS = getLocalColourScheme(colourScheme);
    Argument local = getArgument();
    if (local==null) {
      local = a;
    }
    Position childTopLeft = getPosition(topLeft);
    for (Box child : children) {
      if (!isBand(child)) {
        Band b = child.boxesByDepth(local, map, childTopLeft, localCS);
      }
    }
    return band;
  }



  ////////////////////
  // HELPER METHODS //
  ////////////////////

  public void nextHorizontalPath(Vector<Box> path) {
    Vector<Box> pathVector = new Vector<Box>(path);
    this.addHorizontalPath(pathVector);
  }

  public void nextHorizontalPath(Box[] path) {
    Vector<Box> pathVector = new Vector<Box>(Arrays.asList(path));
    this.addHorizontalPath(pathVector);
  }

  public void nextVerticalPath(Vector<Box> path) {
    Vector<Box> pathVector = new Vector<Box>(path);
    this.addVerticalPath(pathVector);
  }

  public void nextVerticalPath(Box[] path) {
    Vector<Box> pathVector = new Vector<Box>(Arrays.asList(path));
    this.addVerticalPath(pathVector);
  }

  public String toString() {
    String string = "\nBoxList:\n";
    string += "\tchildren("+children.size()+"):\n";
    if (children!=null && children.size()>0) {
      for (Box child : children) {
        string += "\t\t" + child.toString() + "\n";
      }
    } else {
      string += "[null children]";
    }
    string += "x axis:\n";
    if (xAxis!=null) {
      for (Vector<Box> path : xAxis) {
        string += "\tPath:\n";
        for (Box child : path) {
          string += "\t\t" + child.toString() + "\n";
        }
      }
    } else {
      Ket.out.println("[null x-axis]")
    }

    string += "y axis:\n";
    if (yAxis!=null) {
      for (Vector<Box> path : yAxis) {
        string += "\tPath:\n";
        for (Box child : path) {
          string += "\t\t" + child.toString() + "\n";
        }
      }
    } else {
      Ket.out.println("[null y-axis]");
    }
    string += "box attributes:\n";
    string += super.toString();
    string += "\n";
    return string;
  }

  public Vector<Box> getRecursiveBoxVector() {
    Vector<Box> boxVector = new Vector<Box>();
    boxVector.add(this);
    appendChildrenToBoxVector(boxVector);
    return boxVector;
  }

  private void appendChildrenToBoxVector(Vector<Box> boxVector) {
    for (Box box : children) {
      boxVector.add(box);
      if (box instanceof BoxList) {
        BoxList boxList = (BoxList) box;
        boxList.appendChildrenToBoxVector(boxVector);
      }
    }
  }

  @Override
  public double getNetArea() {
    double area = getArea();
    for (Box child : children) {
      area -= child.getArea();
    }
    return area;
  }

  @Override
  public Argument findDeepestArgument(Position p) {
    if (!this.withinInnerRectangle(p)) return null;
    for (Box child : children) {
      Argument childArgument = child.findDeepestArgument(p);
      if (childArgument!=null) {
        return childArgument;
      }
    }
    return this.getArgument();
  }

  @Override
  public Box findDeepestBox(Position p) {
    if (!this.withinInnerRectangle(p)) return null;
    for (Box child : children) {
      Box box = child.findDeepestBox(p);
      if (box==null) continue;
      Argument childArgument = box.getArgument();
      if (childArgument==null) continue;
      if (getArgument()==childArgument) continue; // <--- Deeper boxes with the same argument are considered part of this one.
      return box;
    }
    return this;
  }

  @Override
  protected void addAllArguments(Vector<Argument> args) {
    if (getArgument()!=null) {
      args.add(getArgument());
    }
    for (Box child : children) {
      child.addAllArguments(args);
    }
  }


  /**
   * Find the box that contains the given argument.
   */
  @Override
  public Box findBoxByArgument(Argument target) {
    if (target==getArgument()) {
      return this;
   
    for (Box child : children) {
      Box match = child.findBoxByArgument(target);
      if (match!=null) {
        return match;
      }
    }
    return null;
  }

  /**
   * Step through the current box's argument and its descendants to find
   * the given argument.
   */
  @Override
  public boolean containsArgument(Argument argument) {
    if (getArgument()==argument) {
      return true;
    }
    for (Box child : children) {
      boolean visible = child.containsArgument(argument);
      if (visible) {
        return true;
      }
    }
    return false;
  }

  @Override
  public void setBackground(boolean background) {
    this.background = background;
    for (Box box : children) {
      box.setBackground(background);
    }
  }

  boolean wrap = false;
  public void setWrap() {
    wrap = true;
  }

  private int sign(double x) {
    if (x>0) {
      return +1;
    } else if (x==0) {
      return 0;
    } else {
      return -1;
    }
  }

  /*
  // Comparator methods:
  @Override
  public int compare(Box a, Box b) { // wrong: if the top or bottom of a box is in the range of a box, and to the left of it then it.
    double heightA = a.getParentalShift().height + a.getAlignmentShift().height;
    double heightB = b.getParentalShift().height + b.getAlignmentShift().height;
    double dh = heightA - heightB;
    if (dh != 0) {
      return sign(dh);
    }
    double widthA = a.getParentalShift().width + a.getAlignmentShift().width;
    double widthB = b.getParentalShift().width + b.getAlignmentShift().width;
    return sign(heightA - heightB);
  }

  @Override
  public boolean equals(Object obj) {
    return false;
  }
  */

  @Override
  public void setupOuterRectangle(Offset actualSize) {
    // Find where everything would be.
    super.setupOuterRectangle(actualSize);
    if (!wrap) return;
    for (int i=0; i<children.size(); i++) {
      Box box = children.get(i);
      double width = box.getParentalShift().width + box.getAlignmentShift().width;
      double height = box.getParentalShift().height + box.getAlignmentShift().height;
      double rightWidth = width + box.getInnerRectangle().width;
      if (rightWidth < actualSize.width) continue;
      double widthShift = width;
      double heightShift = box.getInnerRectangle().height; // The maximum height of this and all boxes to its left.
      // Move the whole mass down by heightShift and to the left by widthShift
      for (int j=i; j<children.size(); j++) { // only move down?
        Box child = children.get(j);
        child.getAlignmentShift().width -= widthShift;
        child.getAlignmentShift().height += heightShift;
      }
    }
    // The actual outer box size is to the bottom right point on the last child box.
    Box last = children.lastElement();
    double horizontalOffset = last.getParentalShift().width + last.getAlignmentShift().width + last.getInnerRectangle().width;
    double verticalOffset = last.getParentalShift().height + last.getAlignmentShift().height + last.getInnerRectangle().height;
    this.outerRectangle = new Offset(horizontalOffset, verticalOffset);
  }

  /**
   * Recursively remove all arguments.
   */
  @Override
  public void clearArgument() {
    super.clearArgument();
    for (Box box : children) {
      box.clearArgument();
    }
  }

  @Override
  public Vector<Pair> getPairs(Position topLeft) {
    Vector<Pair> pairs = super.getPairs(topLeft);
    Position recursiveTopLeft = getPosition(topLeft);
    for (Box b : children) {
      pairs.addAll(b.getPairs(recursiveTopLeft));
    }
    return pairs;
  }
}
TOP

Related Classes of ket.display.box.BoxList

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.