/*
* 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 ket.math.Branch;
import ket.math.Token;
import ket.math.Function;
import geom.Offset;
import geom.Position;
import java.awt.*;
import java.util.*;
import ket.display.ColourScheme;
import ket.display.ColourSchemeDecorator;
import ket.math.Argument;
import ket.math.ArgumentFactory;
/**
* Create boxes according to pre-defined patterns and provide helper methods to
* simplify constructions of common patterns.
*/
public class BoxFactory {
// Don't create Box instances.
private BoxFactory() {}
public static Box verticalContainer(Argument argument, ColourScheme colourScheme) {
Function function = argument.getFunction();
if (argument instanceof Branch) {
String name = function!=null ? function.getName() : "?" ;
Vector<Argument> args = ((Branch) argument).getChildren();
return verticalContainer((Branch) argument, name, args, colourScheme, true);
} else {
String text = argument.toPrefixNotation();
return new BoxWord(argument, text, 0L);
}
}
private static Vector<Box> toBoxArgs(Vector<Argument> args, Branch branch, ColourScheme colourScheme) {
Vector<Box> boxArgs = new Vector<Box>();
boolean interpose = false;
for (Argument child : args) {
if (interpose) {
boxArgs.add(new BoxWord(branch, " ", 0L));
}
interpose = true;
boxArgs.add(verticalContainer(child, colourScheme));
}
return boxArgs;
}
// (+Argument argument
public static Box verticalContainer(Branch branch, String label, Vector<Argument> args, ColourScheme colourScheme, boolean borders) {
Box left = new BoxGraphic(branch, 0L, BoxGraphic.VERTICAL_LINE);
Box right = new BoxGraphic(branch, 0L, BoxGraphic.VERTICAL_LINE);
Box top = new BoxGraphic(branch, 0L, BoxGraphic.HORIZONTAL_LINE);
Box bottom = new BoxGraphic(branch, 0L, BoxGraphic.HORIZONTAL_LINE);
Vector<Box> boxArgs = toBoxArgs(args, branch, colourScheme);
Box row = BoxTools.centredHorizontalBoxList(branch, 0L, boxArgs); // null -> argument, 0L, boxArgs
Vector<Box> columnVector = new Vector<Box>();
if (borders) columnVector.add(top);
if (label!=null) {
Box word = new BoxWord(branch, label, 0L);
columnVector.add(word);
}
columnVector.add(row);
if (borders) columnVector.add(bottom);
Box column = BoxTools.centredVerticalBoxList(branch, 0L, columnVector);
if (borders) {
Box list = BoxTools.centredHorizontalBoxList(branch, 0L, left, column, right);
list.setArgument(branch);
return list;
} else {
column.setArgument(branch);
return column;
}
}
public static Box horizontalContainer(Argument argument, ColourScheme colourScheme) {
if (argument instanceof Branch) {
Function function = argument.getFunction();
String name = function!=null ? function.getName() : "?" ;
Vector<Argument> args = ((Branch) argument).getChildren();
return horizontalContainer((Branch) argument, name, args, colourScheme, true);
} else {
return new BoxWord(argument, argument.toPrefixNotation(), 0L);
}
}
public static Box horizontalContainer(Branch branch, String label, Vector<Argument> args, ColourScheme colourScheme, boolean borders) {
Box left = new BoxGraphic(branch, 0L, BoxGraphic.VERTICAL_LINE);
Box right = new BoxGraphic(branch, 0L, BoxGraphic.VERTICAL_LINE);
Box top = new BoxGraphic(branch, 0L, BoxGraphic.HORIZONTAL_LINE);
Box bottom = new BoxGraphic(branch, 0L, BoxGraphic.HORIZONTAL_LINE);
Vector<Box> boxArgs = new Vector<Box>();
for (Argument child : args) {
boxArgs.add(verticalContainer(child, colourScheme));
}
Box column = BoxTools.centredVerticalBoxList(branch, 0L, boxArgs);
Vector<Box> rowVector = new Vector<Box>();
if (borders) rowVector.add(left);
if (label!=null) {
Box word = new BoxWord(branch, label, 0L);
rowVector.add(word);
}
rowVector.add(column);
if (borders) rowVector.add(right);
Box row = BoxTools.centredHorizontalBoxList(branch, 0L, rowVector);
if (borders) {
Box list = BoxTools.centredVerticalBoxList(branch, 0L, top, row, bottom);
list.setArgument(branch);
return list;
} else {
row.setArgument(branch);
return row;
}
}
public static Box derivative(Argument argument, Box dBox, int argsUpperLimit, Vector<Argument> args, long settings, ColourScheme colourScheme) {
int lowestDerivativeIndex = (args.size()<2) ? 0 : 1;
Argument orderArgument = ArgumentFactory.getOrderArgument(lowestDerivativeIndex, args);
Box topD = dBox.cloneBox();
topD.setArgument(argument);
Vector<Box> boxArgs = BoxTools.padArgs(args, 1, colourScheme);
Box topRowBox;
Box orderBox;
if (orderArgument!=null) {
orderBox = orderArgument.toBox(settings, colourScheme);
orderBox.clearArgument();
if (1<args.size()) { // multiple
topRowBox = BoxTools.centredHorizontalBoxList(argument, 0L, topD, orderBox, boxArgs.firstElement()); // d ^n x
} else {
topRowBox = BoxTools.centredHorizontalBoxList(argument, 0L, topD, orderBox);
}
} else {
orderBox = null;
if (1<args.size()) { // multiple
topRowBox = BoxTools.centredHorizontalBoxList(argument, 0L, topD, boxArgs.firstElement());
} else {
topRowBox = topD;
}
}
BoxGraphic bar = new BoxGraphic(argument, 0L, BoxGraphic.HORIZONTAL_LINE);
Box box;
if (boxArgs.size()<=2) { // Cases: '?, 'x, f'x.
Box bottomD = dBox.cloneBox();
Box bottomRowBox = BoxTools.centredHorizontalBoxList(argument, 0L, bottomD, boxArgs.lastElement());
box = BoxTools.centredVerticalBoxList(argument, settings, topRowBox, bar, bottomRowBox);
bottomD.setProperty(Box.PLAIN_FONT);
} else {
Vector<Box> denomonatorVector = new Vector<Box>();
for (int i=1; i<boxArgs.size(); i++) {
if (i>1) {
denomonatorVector.add(new BoxWord(argument, " ", 0L));
}
Box bottomD = dBox.cloneBox();
denomonatorVector.add(bottomD);
bottomD.setProperty(Box.PLAIN_FONT);
denomonatorVector.add(boxArgs.get(i));
}
Box bottomRowBox = BoxTools.centredHorizontalBoxList(argument, 0L, denomonatorVector);
box = BoxTools.centredVerticalBoxList(argument, settings, topRowBox, bar, bottomRowBox);
for (int i=0; i+3<denomonatorVector.size(); i+=3) {
denomonatorVector.get(i).setProperty(Box.PLAIN_FONT);
denomonatorVector.get(i+2).setProperty(Box.SMALL_FONT);
}
}
box.setProperty(settings);
bar.setProperties(Box.HORIZONTAL_STRETCH, Box.TOP_ALIGN);
topD.setProperty(Box.PLAIN_FONT);
if (orderBox!=null) {
orderBox.setProperties(Box.TOP_ALIGN, Box.SMALL_FONT, Box.PLAIN_FONT);
}
return box;
}
/**
* Display an integral where null arguments are ignored.
*/
public static Box integral(Argument argument, int shape, Box from, Box to, Box arg, Box x) {
/*
if (from!=null && from.getArgument()==null) {
from.setArgument(argument);
}
if (to!=null && to.getArgument()==null) {
to.setArgument(argument);
}
if (arg!=null && arg.getArgument()==null) {
arg.setArgument(argument);
}
if (x!=null && x.getArgument()==null) {
x.setArgument(argument);
}*/
long settings = Box.X_CENTRE_ALIGN|Box.Y_CENTRE_ALIGN|Box.LARGE_FONT|Box.PLAIN_FONT;
Box integral = new BoxGraphic(argument, settings, shape);
BoxList list = new BoxList(argument, Box.X_CENTRE_ALIGN|Box.Y_CENTRE_ALIGN);
BoxWord gap = new BoxWord(argument, " ", Box.X_CENTRE_ALIGN|Box.Y_CENTRE_ALIGN);
BoxWord d = new BoxWord(argument, "d", Box.LEFT_ALIGN|Box.Y_CENTRE_ALIGN|Box.PLAIN_FONT);
if (arg==null) {
list.nextHorizontalPath(new Box[]{integral, d, x});
list.nextVerticalPath(new Box[]{integral});
list.nextVerticalPath(new Box[]{d});
list.nextVerticalPath(new Box[]{x});
integral.setProperty(Box.X_CENTRE_ALIGN|Box.Y_CENTRE_ALIGN|Box.LARGE_FONT|Box.PLAIN_FONT);
} else if (from==null) {
list.nextHorizontalPath(new Box[]{integral, arg, gap, d, x});
list.nextVerticalPath(new Box[]{integral});
list.nextVerticalPath(new Box[]{arg});
list.nextVerticalPath(new Box[]{gap});
list.nextVerticalPath(new Box[]{d});
list.nextVerticalPath(new Box[]{x});
} else if (to==null) {
list.nextHorizontalPath(new Box[]{integral, arg, gap, d, x});
list.nextHorizontalPath(new Box[]{from});
list.nextVerticalPath(new Box[]{integral, from});
list.nextVerticalPath(new Box[]{arg});
list.nextVerticalPath(new Box[]{gap});
list.nextVerticalPath(new Box[]{d});
list.nextVerticalPath(new Box[]{x});
from.setProperty(Box.X_CENTRE_ALIGN|Box.TOP_ALIGN|Box.SMALL_FONT);
} else {
list.nextHorizontalPath(new Box[]{to});
list.nextHorizontalPath(new Box[]{integral, arg, gap, d, x});
list.nextHorizontalPath(new Box[]{from});
list.nextVerticalPath(new Box[]{to, integral, from});
list.nextVerticalPath(new Box[]{arg});
list.nextVerticalPath(new Box[]{gap});
list.nextVerticalPath(new Box[]{d});
list.nextVerticalPath(new Box[]{x});
from.setProperty(Box.X_CENTRE_ALIGN|Box.TOP_ALIGN|Box.SMALL_FONT);
to.setProperty(Box.X_CENTRE_ALIGN|Box.BOTTOM_ALIGN|Box.SMALL_FONT);
}
integral.setProperty(Box.X_CENTRE_ALIGN|Box.Y_CENTRE_ALIGN|Box.LARGE_FONT|Box.PLAIN_FONT);
list.setProperty(Box.X_CENTRE_ALIGN|Box.Y_CENTRE_ALIGN);
d.setProperty(Box.LEFT_ALIGN|Box.Y_CENTRE_ALIGN|Box.PLAIN_FONT);
gap.setProperty(Box.X_CENTRE_ALIGN|Box.Y_CENTRE_ALIGN);
return list;
}
}