package nodebox.graphics;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
public abstract class AbstractGraphicsContext implements GraphicsContext {
// TODO: Support output mode
protected Color.Mode colorMode;
protected double colorRange;
protected Color fillColor;
protected Color strokeColor;
protected double strokeWidth;
protected Path path;
protected boolean autoClosePath;
protected boolean pathClosed;
protected Transform.Mode transformMode;
protected Transform transform = new Transform();
protected ArrayList<Transform> transformStack;
protected String fontName;
protected double fontSize;
protected double lineHeight;
protected Text.Align align;
protected GraphicsContext.RectMode rectMode = GraphicsContext.RectMode.CORNER;
protected GraphicsContext.EllipseMode ellipseMode = GraphicsContext.EllipseMode.CORNER;
public void resetContext() {
colorMode = Color.Mode.RGB;
colorRange = 1;
fillColor = new Color();
strokeColor = null;
strokeWidth = 1;
path = null;
autoClosePath = true;
transformMode = Transform.Mode.CENTER;
transform = new Transform();
transformStack = new ArrayList<Transform>();
fontName = "Helvetica";
fontSize = 24;
lineHeight = 1.2;
align = Text.Align.LEFT;
}
//// Primitives ////
// TODO: Support rect modes.
public RectMode rectmode() {
return rectMode;
}
public RectMode rectmode(RectMode m) {
return rectMode = m;
}
public RectMode rectmode(String m) {
try {
RectMode newMode = RectMode.valueOf(m.toUpperCase(Locale.US));
return rectMode = newMode;
} catch (IllegalArgumentException e) {
throw new NodeBoxError("rectmode: available types for rectmode() are CORNER, CENTER, CORNERS and RADIUS\\n\"");
}
}
public RectMode rectmode(int m) {
try {
RectMode newMode = RectMode.values()[m];
return rectMode = newMode;
} catch (ArrayIndexOutOfBoundsException e) {
throw new NodeBoxError("rectmode: available types for rectmode() are CORNER, CENTER, CORNERS and RADIUS\\n\"");
}
}
private Path createPath() {
Path p = new Path();
p.setTransformDelegate(new ContextTransformDelegate(this));
return p;
}
public Path Path() {
return createPath();
}
public Path BezierPath() {
return createPath();
}
public Path rect(Rect r) {
return rect(r.getX(), r.getY(), r.getWidth(), r.getHeight(), true);
}
public Path rect(Rect r, boolean draw) {
return rect(r.getX(), r.getY(), r.getWidth(), r.getHeight(), draw);
}
public Path rect(double x, double y, double width, double height) {
return rect(x, y, width, height, true);
}
public Path rect(double x, double y, double width, double height, boolean draw) {
Path p = createPath();
switch (rectMode) {
case CENTER:
p.rect(x, y, width, height);
break;
case CORNER:
p.cornerRect(x, y, width, height);
break;
}
inheritFromContext(p);
if (draw)
addPath(p);
return p;
}
public Path rect(Rect r, double roundness) {
return rect(r.getX(), r.getY(), r.getWidth(), r.getHeight(), roundness, roundness, true);
}
public Path rect(Rect r, double roundness, boolean draw) {
return rect(r.getX(), r.getY(), r.getWidth(), r.getHeight(), roundness, roundness, draw);
}
public Path rect(double x, double y, double width, double height, double roundness) {
return rect(x, y, width, height, roundness, roundness, true);
}
public Path rect(double x, double y, double width, double height, double roundness, boolean draw) {
return rect(x, y, width, height, roundness, roundness, draw);
}
public Path rect(double x, double y, double width, double height, double rx, double ry) {
return rect(x, y, width, height, rx, ry, true);
}
public Path rect(double x, double y, double width, double height, double rx, double ry, boolean draw) {
Path p = createPath();
switch (rectMode) {
case CENTER:
p.rect(x, y, width, height, rx, ry);
break;
case CORNER:
p.cornerRect(x, y, width, height, rx, ry);
break;
}
inheritFromContext(p);
if (draw)
addPath(p);
return p;
}
public EllipseMode ellipsemode() {
return ellipseMode;
}
public EllipseMode ellipsemode(EllipseMode m) {
return ellipseMode = m;
}
public EllipseMode ellipsemode(String m) {
try {
EllipseMode newMode = EllipseMode.valueOf(m.toUpperCase(Locale.US));
return ellipseMode = newMode;
} catch (IllegalArgumentException e) {
throw new NodeBoxError("ellipsemode: available types for ellipsemode() are CORNER, CENTER, CORNERS and RADIUS\\n\"");
}
}
public EllipseMode ellipsemode(int m) {
try {
EllipseMode newMode = EllipseMode.values()[m];
return ellipseMode = newMode;
} catch (ArrayIndexOutOfBoundsException e) {
throw new NodeBoxError("ellipsemode: available types for ellipsemode() are CORNER, CENTER, CORNERS and RADIUS\\n\"");
}
}
public Path oval(double x, double y, double width, double height) {
// TODO: Deprecation warning
return ellipse(x, y, width, height, true);
}
public Path oval(double x, double y, double width, double height, boolean draw) {
// TODO: Deprecation warning
return ellipse(x, y, width, height, draw);
}
public Path ellipse(double x, double y, double width, double height) {
return ellipse(x, y, width, height, true);
}
public Path ellipse(double x, double y, double width, double height, boolean draw) {
Path p = createPath();
switch (ellipseMode) {
case CENTER:
p.ellipse(x, y, width, height);
break;
case CORNER:
p.cornerEllipse(x, y, width, height);
break;
}
inheritFromContext(p);
if (draw)
addPath(p);
return p;
}
public Path line(double x1, double y1, double x2, double y2) {
return line(x1, y1, x2, y2, true);
}
public Path line(double x1, double y1, double x2, double y2, boolean draw) {
Path p = createPath();
p.line(x1, y1, x2, y2);
inheritFromContext(p);
if (draw)
addPath(p);
return p;
}
public Path star(double cx, double cy) {
return star(cx, cy, 20, 100, 50, true);
}
public Path star(double cx, double cy, int points) {
return star(cx, cy, points, 100, 50, true);
}
public Path star(double cx, double cy, int points, double outer) {
return star(cx, cy, points, outer, 50, true);
}
public Path star(double cx, double cy, int points, double outer, double inner) {
return star(cx, cy, points, outer, inner, true);
}
public Path star(double cx, double cy, int points, double outer, double inner, boolean draw) {
double PI = (double) Math.PI;
Path p = createPath();
p.moveto(cx, cy + outer);
for (int i = 1; i < points * 2; i++) {
double angle = i * PI / points;
double x = (double) Math.sin(angle);
double y = (double) Math.cos(angle);
double radius = i % 2 == 0 ? outer : inner;
x += cx + radius * x;
y += cy + radius * y;
p.lineto(x, y);
}
p.close();
inheritFromContext(p);
if (draw)
addPath(p);
return p;
}
public Path arrow(double x, double y) {
return arrow(x, y, 100, ArrowType.NORMAL, true);
}
public Path arrow(double x, double y, ArrowType type) {
return arrow(x, y, 100, type, true);
}
public Path arrow(double x, double y, String type) {
return arrow(x, y, 100, type, true);
}
public Path arrow(double x, double y, int type) {
return arrow(x, y, 100, type, true);
}
public Path arrow(double x, double y, double width) {
return arrow(x, y, width, NORMAL, true);
}
public Path arrow(double x, double y, double width, boolean draw) {
return arrow(x, y, width, NORMAL, draw);
}
public Path arrow(double x, double y, double width, ArrowType type) {
return arrow(x, y, width, type, true);
}
public Path arrow(double x, double y, double width, String type) {
return arrow(x, y, width, type, true);
}
public Path arrow(double x, double y, double width, int type) {
return arrow(x, y, width, type, true);
}
public Path arrow(double x, double y, double width, String type, boolean draw) {
try {
ArrowType arrowType = ArrowType.valueOf(type.toUpperCase(Locale.US));
return arrow(x, y, width, arrowType, draw);
} catch (IllegalArgumentException e) {
throw new NodeBoxError("arrow: available types for arrow() are NORMAL and FORTYFIVE\\n\"");
}
}
public Path arrow(double x, double y, double width, int type, boolean draw) {
try {
ArrowType arrowType = ArrowType.values()[type];
return arrow(x, y, width, arrowType, draw);
} catch (ArrayIndexOutOfBoundsException e) {
throw new NodeBoxError("arrow: available types for arrow() are NORMAL and FORTYFIVE\\n\"");
}
}
public Path arrow(double x, double y, double width, ArrowType type, boolean draw) {
if (type == ArrowType.NORMAL)
return arrowNormal(x, y, width, draw);
else
return arrowFortyFive(x, y, width, draw);
}
private Path arrowNormal(double x, double y, double width, boolean draw) {
double head = width * .4;
double tail = width * .2;
Path p = createPath();
p.moveto(x, y);
p.lineto(x - head, y + head);
p.lineto(x - head, y + tail);
p.lineto(x - width, y + tail);
p.lineto(x - width, y - tail);
p.lineto(x - head, y - tail);
p.lineto(x - head, y - head);
p.lineto(x, y);
p.close();
inheritFromContext(p);
if (draw)
addPath(p);
return p;
}
private Path arrowFortyFive(double x, double y, double width, boolean draw) {
double head = .3;
double tail = 1 + head;
Path p = createPath();
p.moveto(x, y);
p.lineto(x, y + width * (1 - head));
p.lineto(x - width * head, y + width);
p.lineto(x - width * head, y + width * tail * .4);
p.lineto(x - width * tail * .6, y + width);
p.lineto(x - width, y + width * tail * .6);
p.lineto(x - width * tail * .4, y + width * head);
p.lineto(x - width, y + width * head);
p.lineto(x - width * (1 - head), y);
p.lineto(x, y);
p.close();
inheritFromContext(p);
if (draw)
addPath(p);
return p;
}
//// Path commands ////
public void beginpath() {
path = createPath();
pathClosed = false;
}
public void beginpath(double x, double y) {
beginpath();
moveto(x, y);
}
public void moveto(double x, double y) {
if (path == null)
throw new NodeBoxError("No current path. Use beginpath() first.");
path.moveto(x, y);
}
public void lineto(double x, double y) {
if (path == null)
throw new NodeBoxError("No current path. Use beginpath() first.");
path.lineto(x, y);
}
public void curveto(double x1, double y1, double x2, double y2, double x3, double y3) {
if (path == null)
throw new NodeBoxError("No current path. Use beginPath() first.");
path.curveto(x1, y1, x2, y2, x3, y3);
}
public void closepath() {
if (path == null)
throw new NodeBoxError("No current path. Use beginpath() first.");
if (!pathClosed) {
path.close();
pathClosed = true;
}
}
public Path endpath() {
return endpath(true);
}
public Path endpath(boolean draw) {
if (path == null)
throw new NodeBoxError("No current path. Use beginpath() first.");
if (autoClosePath)
closepath();
Path p = path;
inheritFromContext(p);
if (draw)
addPath(p);
// Initialize a new path
path = null;
pathClosed = false;
return p;
}
public void drawpath(Path path) {
inheritFromContext(path);
addPath(path);
}
public void drawpath(Iterable<Point> points) {
Path path = createPath();
for (Point pt : points) {
path.addPoint(pt);
}
inheritFromContext(path);
addPath(path);
}
public boolean autoclosepath() {
return autoClosePath;
}
public boolean autoclosepath(boolean c) {
return autoClosePath = c;
}
public Path findpath(List<Point> points) {
return findpath(points, 1);
}
public Path findpath(List<Point> points, double curvature) {
Path path = Path.findPath(points, curvature);
inheritFromContext(path);
addPath(path);
return path;
}
//// Clipping ////
// TODO: implement clipping
public void beginclip(Path p) {
throw new RuntimeException("beginclip is not implemented yet.");
}
public void endclip() {
throw new RuntimeException("endclip is not implemented yet.");
}
//// Transformation commands ////
public Transform.Mode transform() {
return transformMode;
}
public Transform.Mode transform(Transform.Mode mode) {
return transformMode = mode;
}
public Transform.Mode transform(String mode) {
try {
Transform.Mode newMode = Transform.Mode.valueOf(mode.toUpperCase(Locale.US));
return transformMode = newMode;
} catch (IllegalArgumentException e) {
throw new NodeBoxError("transform: available types for transform() are CORNER and CENTER\\n\"");
}
}
public Transform.Mode transform(int mode) {
try {
Transform.Mode newMode = Transform.Mode.values()[mode];
return transformMode = newMode;
} catch (ArrayIndexOutOfBoundsException e) {
throw new NodeBoxError("transform: available types for transform() are CORNER and CENTER\\n\"");
}
}
public void push() {
transformStack.add(0, transform.clone());
}
public void pop() {
if (transformStack.isEmpty())
throw new NodeBoxError("Pop: too many pops!");
transform = transformStack.get(0);
transformStack.remove(0);
}
public void reset() {
transformStack.clear();
transform = new Transform();
}
public void translate(double tx, double ty) {
transform.translate(tx, ty);
}
public void rotate(double r) {
transform.rotate(r);
}
public void scale(double scale) {
transform.scale(scale);
}
public void scale(double sx, double sy) {
transform.scale(sx, sy);
}
public void skew(double skew) {
transform.skew(skew);
}
public void skew(double kx, double ky) {
transform.skew(kx, ky);
}
//// Color commands ////
public String outputmode() {
throw new RuntimeException("outputmode is not implemented yet.");
}
public String outputmode(String mode) {
throw new RuntimeException("outputmode is not implemented yet.");
}
public Color.Mode colormode() {
return colorMode;
}
public Color.Mode colormode(Color.Mode mode) {
return colorMode = mode;
}
public Color.Mode colormode(Color.Mode mode, double range) {
colorRange = range;
return colorMode = mode;
}
public Color.Mode colormode(String mode) {
return colormode(mode, colorRange);
}
public Color.Mode colormode(String mode, double range) {
try {
Color.Mode newMode = Color.Mode.valueOf(mode.toUpperCase(Locale.US));
return colormode(newMode, range);
} catch (IllegalArgumentException e) {
throw new NodeBoxError("colormode: available types for colormode() are RGB, HSB and CMYK\\n\"");
}
}
public Color.Mode colormode(int mode) {
return colormode(mode, colorRange);
}
public Color.Mode colormode(int mode, double range) {
try {
Color.Mode newMode = Color.Mode.values()[mode];
return colormode(newMode, range);
} catch (ArrayIndexOutOfBoundsException e) {
throw new NodeBoxError("colormode: available types for colormode() are RGB, HSB and CMYK\\n\"");
}
}
public double colorrange() {
return colorRange;
}
public double colorrange(double range) {
return colorRange = range;
}
/**
* Create an empty (black) color object.
*
* @return the new color.
*/
public Color color() {
return new Color();
}
/**
* Create a new color with the given grayscale value.
*
* @param x the gray component.
* @return the new color.
*/
public Color color(double x) {
double nx = normalize(x);
return new Color(nx, nx, nx);
}
/**
* Create a new color with the given grayscale and alpha value.
*
* @param x the grayscale value.
* @param y the alpha value.
* @return the new color.
*/
public Color color(double x, double y) {
double nx = normalize(x);
return new Color(nx, nx, nx, normalize(y));
}
/**
* Create a new color with the the given R/G/B or H/S/B value.
*
* @param x the red or hue component.
* @param y the green or saturation component.
* @param z the blue or brightness component.
* @return the new color.
*/
public Color color(double x, double y, double z) {
return new Color(normalize(x), normalize(y), normalize(z), colormode());
}
/**
* Create a new color with the the given R/G/B/A or H/S/B/A value.
*
* @param x the red or hue component.
* @param y the green or saturation component.
* @param z the blue or brightness component.
* @param a the alpha component.
* @return the new color.
*/
public Color color(double x, double y, double z, double a) {
return new Color(normalize(x), normalize(y), normalize(z), normalize(a), colormode());
}
/**
* Create a new color with the the given color.
* <p/>
* The color object is cloned; you can change the original afterwards.
* If the color object is null, the new color is turned off (same as nocolor).
*
* @param c the color object.
* @return the new color.
*/
public Color color(Color c) {
return c == null ? new Color(0, 0, 0, 0) : c.clone();
}
/**
* Get the current fill color.
*
* @return the current fill color.
*/
public Color fill() {
return fillColor;
}
/**
* Set the current fill color to given grayscale value.
*
* @param x the gray component.
* @return the current fill color.
*/
public Color fill(double x) {
double nx = normalize(x);
return fillColor = new Color(nx, nx, nx);
}
/**
* Set the current fill color to given grayscale and alpha value.
*
* @param x the grayscale value.
* @param y the alpha value.
* @return the current fill color.
*/
public Color fill(double x, double y) {
double nx = normalize(x);
return fillColor = new Color(nx, nx, nx, normalize(y));
}
/**
* Set the current fill color to the given R/G/B or H/S/B value.
*
* @param x the red or hue component.
* @param y the green or saturation component.
* @param z the blue or brightness component.
* @return the current fill color.
*/
public Color fill(double x, double y, double z) {
return fillColor = new Color(normalize(x), normalize(y), normalize(z), colormode());
}
/**
* Set the current fill color to the given R/G/B/A or H/S/B/A value.
*
* @param x the red or hue component.
* @param y the green or saturation component.
* @param z the blue or brightness component.
* @param a the alpha component.
* @return the current fill color.
*/
public Color fill(double x, double y, double z, double a) {
return fillColor = new Color(normalize(x), normalize(y), normalize(z), normalize(a), colormode());
}
/**
* Set the current fill color to the given color.
* <p/>
* The color object is cloned; you can change the original afterwards.
* If the color object is null, the current fill color is turned off (same as nofill).
*
* @param c the color object.
* @return the current fill color.
*/
public Color fill(Color c) {
return fillColor = c == null ? null : c.clone();
}
public void nofill() {
fillColor = null;
}
/**
* Get the current stroke color.
*
* @return the current stroke color.
*/
public Color stroke() {
return strokeColor;
}
/**
* Set the current stroke color to given grayscale value.
*
* @param x the gray component.
* @return the current stroke color.
*/
public Color stroke(double x) {
double nx = normalize(x);
return strokeColor = new Color(nx, nx, nx);
}
/**
* Set the current stroke color to given grayscale and alpha value.
*
* @param x the grayscale value.
* @param y the alpha value.
* @return the current stroke color.
*/
public Color stroke(double x, double y) {
double nx = normalize(x);
return strokeColor = new Color(nx, nx, nx, normalize(y));
}
/**
* Set the current stroke color to the given R/G/B or H/S/B value.
*
* @param x the red or hue component.
* @param y the green or saturation component.
* @param z the blue or brightness component.
* @return the current stroke color.
*/
public Color stroke(double x, double y, double z) {
return strokeColor = new Color(normalize(x), normalize(y), normalize(z), colormode());
}
/**
* Set the current stroke color to the given R/G/B/A or H/S/B/A value.
*
* @param x the red or hue component.
* @param y the green or saturation component.
* @param z the blue or brightness component.
* @param a the alpha component.
* @return the current stroke color.
*/
public Color stroke(double x, double y, double z, double a) {
return strokeColor = new Color(normalize(x), normalize(y), normalize(z), normalize(a), colormode());
}
/**
* Set the current stroke color to the given color.
* <p/>
* The color object is cloned; you can change the original afterwards.
* If the color object is null, the current stroke color is turned off (same as nostroke).
*
* @param c the color object.
* @return the current stroke color.
*/
public Color stroke(Color c) {
return strokeColor = c == null ? null : c.clone();
}
public void nostroke() {
strokeColor = null;
}
public double strokewidth() {
return strokeWidth;
}
public double strokewidth(double w) {
return strokeWidth = w;
}
//// Image commands ////
public Image image(String path, double x, double y) {
throw new RuntimeException("'image' is not applicable to this type of GraphicsContext.");
}
public Image image(String path, double x, double y, double width) {
throw new RuntimeException("'image' is not applicable to this type of GraphicsContext.");
}
public Image image(String path, double x, double y, double width, double height) {
throw new RuntimeException("'image' is not applicable to this type of GraphicsContext.");
}
public Image image(String path, double x, double y, double width, double height, double alpha) {
throw new RuntimeException("'image' is not applicable to this type of GraphicsContext.");
}
public Image image(String path, double x, double y, double width, double height, boolean draw) {
throw new RuntimeException("'image' is not applicable to this type of GraphicsContext.");
}
public Image image(String path, double x, double y, double width, double height, double alpha, boolean draw) {
throw new RuntimeException("'image' is not applicable to this type of GraphicsContext.");
}
public Image image(Image img, double x, double y, double width, double height, double alpha, boolean draw) {
throw new RuntimeException("'image' is not applicable to this type of GraphicsContext.");
}
public Image image(BufferedImage img, double x, double y, double width, double height, double alpha, boolean draw) {
throw new RuntimeException("'image' is not applicable to this type of GraphicsContext.");
}
public Size imagesize(String path) {
throw new RuntimeException("'imagesize' is not applicable to this type of GraphicsContext.");
}
public Size imagesize(Image img) {
throw new RuntimeException("'imagesize' is not applicable to this type of GraphicsContext.");
}
public Size imagesize(BufferedImage img) {
throw new RuntimeException("'imagesize' is not applicable to this type of GraphicsContext.");
}
//// Font commands ////
public String font() {
return fontName;
}
public String font(String fontName) {
if (!Text.fontExists(fontName))
throw new NodeBoxError("Font '" + fontName + "' does not exist.");
return this.fontName = fontName;
}
public String font(String fontName, double fontSize) {
font(fontName);
fontsize(fontSize);
return fontName;
}
public double fontsize() {
return fontSize;
}
public double fontsize(double s) {
return fontSize = s;
}
public double lineheight() {
return lineHeight;
}
public double lineheight(double lineHeight) {
return this.lineHeight = lineHeight;
}
public Text.Align align() {
return align;
}
public Text.Align align(Text.Align align) {
return this.align = align;
}
public Text.Align align(String align) {
try {
Text.Align newAlign = Text.Align.valueOf(align.toUpperCase(Locale.US));
return this.align = newAlign;
} catch (IllegalArgumentException e) {
throw new NodeBoxError("align: available types for align() are LEFT, RIGHT, CENTER and JUSTIFY\\n\"");
}
}
public Text.Align align(int align) {
try {
Text.Align newAlign = Text.Align.values()[align];
return this.align = newAlign;
} catch (ArrayIndexOutOfBoundsException e) {
throw new NodeBoxError("align: available types for align() are LEFT, RIGHT, CENTER and JUSTIFY\\n\"");
}
}
public Text text(String text, double x, double y) {
return text(text, x, y, 0, 0, true);
}
public Text text(String text, double x, double y, double width) {
return text(text, x, y, width, 0, true);
}
public Text text(String text, double x, double y, double width, double height) {
return text(text, x, y, width, height, true);
}
public Text text(String text, double x, double y, double width, double height, boolean draw) {
Text t = new Text(text, x, y, width, height);
t.setTransformDelegate(new ContextTransformDelegate(this));
inheritFromContext(t);
if (draw)
addText(t);
return t;
}
public Path textpath(String text, double x, double y) {
return textpath(text, x, y, 0, 0);
}
public Path textpath(String text, double x, double y, double width) {
return textpath(text, x, y, width, 0);
}
public Path textpath(String text, double x, double y, double width, double height) {
Text t = new Text(text, x, y, width, height);
inheritFontAttributesFromContext(t);
Path path = t.getPath();
path.setTransformDelegate(new ContextTransformDelegate(this));
inheritFromContext(path);
return path;
}
public Rect textmetrics(String text) {
return textmetrics(text, 0, 0);
}
public Rect textmetrics(String text, double width) {
return textmetrics(text, width, 0);
}
public Rect textmetrics(String text, double width, double height) {
Text t = new Text(text, 0, 0, width, height);
inheritFromContext(t);
return t.getMetrics();
}
public double textwidth(String text) {
return textmetrics(text, 0, 0).getWidth();
}
public double textwidth(String text, double width) {
return textmetrics(text, width).getWidth();
}
public double textheight(String text) {
return textmetrics(text, 0, 0).getHeight();
}
public double textheight(String text, double width) {
return textmetrics(text, width).getHeight();
}
//// Utility methods ////
public void var(String name, VarType type) {
var(name, type, null, 0, 1000);
}
public void var(String name, String type) {
var(name, type, null, 0, 1000);
}
public void var(String name, int type) {
var(name, type, 0, 0, 1000);
}
public void var(String name, VarType type, Object value) {
var(name, type, value, 0, 1000);
}
public void var(String name, String type, Object value) {
var(name, type, value, 0, 1000);
}
public void var(String name, int type, Object value) {
var(name, type, value, 0, 1000);
}
public void var(String name, String type, Object value, double min, double max) {
try {
var(name, VarType.valueOf(type.toUpperCase(Locale.US)), value, min, max);
} catch (IllegalArgumentException e) {
throw new NodeBoxError("var: available types for var() are NUMBER, TEXT, BOOLEAN and FONT \\n\"");
}
}
public void var(String name, int type, Object value, double min, double max) {
try {
var(name, VarType.values()[type], value, min, max);
} catch (ArrayIndexOutOfBoundsException e) {
throw new NodeBoxError("var: available types for var() are NUMBER, TEXT, BOOLEAN and FONT \\n\"");
}
}
public void var(String name, VarType type, Object value, double min, double max) {
// Node node = ProcessingContext.getCurrentContext().getNode();
// if (node == null) return;
// Parameter p = node.getInput(name);
// if (p != null) {
// if (p.getType() != type.type) {
// p.setType(type.type);
// }
// if (p.getWidget() != type.widget) {
// p.setWidget(type.widget);
// }
// if (p.getMinimumValue() != null && !p.getMinimumValue().equals(min)) {
// p.setMinimumValue(min);
// }
// if (p.getMaximumValue() != null && !p.getMaximumValue().equals(max)) {
// p.setMaximumValue(max);
// }
// } else {
// p = node.addPort(name, type.type);
// p.setWidget(type.widget);
// if (value != null) {
// p.setValue(value);
// }
// if (min != null || max != null) {
// p.setBoundingMethod(Parameter.BoundingMethod.HARD);
// p.setMinimumValue(min);
// p.setMaximumValue(max);
// }
// node.updateDependencies(ProcessingContext.getCurrentContext());
// }
}
public Object findVar(String name) {
// Node node = ProcessingContext.getCurrentContext().getNode();
// if (node == null) return null;
// return node.getInput(name);
return null;
}
protected double normalize(double v) {
// Bring the color into the 0-1 scale for the current colorrange
if (colorRange == 1) return v;
return v / colorRange;
}
public double random() {
return Math.random();
}
public long random(int max) {
return Math.round(Math.random() * max);
}
public long random(int min, int max) {
return Math.round(min + (Math.random() * (max - min)));
}
public double random(double max) {
return Math.random() * max;
}
public double random(double min, double max) {
return min + (Math.random() * (max - min));
}
public Object choice(List objects) {
if (objects == null || objects.isEmpty()) return null;
return objects.get((int) random(objects.size() - 1));
}
public Iterator<Point> grid(int columns, int rows) {
return grid(columns, rows, 1, 1);
}
public Iterator<Point> grid(double columns, double rows) {
return grid(Math.round(columns), Math.round(rows), 1, 1);
}
public Iterator<Point> grid(double columns, double rows, double columnSize, double rowSize) {
return grid(Math.round(columns), Math.round(rows), columnSize, rowSize);
}
public Iterator<Point> grid(final int columns, final int rows, final double columnSize, final double rowSize) {
return new Iterator<Point>() {
int x = 0;
int y = 0;
public boolean hasNext() {
return y < rows;
}
public Point next() {
Point pt = new Point((double) (x * columnSize), (double) (y * rowSize));
x++;
if (x >= columns) {
x = 0;
y++;
}
return pt;
}
public void remove() {
}
};
}
//// Context drawing /////
public void draw(Grob g) {
if (g instanceof Path) {
addPath((Path) g);
} else if (g instanceof Geometry) {
for (Path path : ((Geometry) g).getPaths()) {
addPath(path);
}
} else if (g instanceof Contour) {
addPath(((Contour) g).toPath());
} else if (g instanceof Text) {
addText((Text) g);
} else {
throw new IllegalArgumentException("Don't know how to add a " + g + " to the current context.");
}
}
protected abstract void addPath(Path p);
protected abstract void addText(Text t);
protected void inheritFromContext(Path p) {
p.setFillColor(fillColor == null ? null : fillColor.clone());
p.setStrokeColor(strokeColor == null ? null : strokeColor.clone());
p.setStrokeWidth(strokeWidth);
TransformDelegate d = p.getTransformDelegate();
d.transform(p, transform, true);
}
protected void inheritFromContext(Text t) {
t.setFillColor(fillColor == null ? null : fillColor.clone());
inheritFontAttributesFromContext(t);
// todo: check if this is sufficient.
TransformDelegate d = t.getTransformDelegate();
d.transform(t, transform, true);
/* Rect r = t.getBounds();
double dx = r.getX() + r.getWidth() / 2;
double dy = r.getY() + r.getHeight() / 2;
if (transformMode == Transform.Mode.CENTER) {
Transform trans = new Transform();
trans.translate(dx, dy);
trans.append(transform);
trans.translate(-dx, -dy);
t.setTransform(trans);
} else {
t.setTransform(transform);
} */
}
private void inheritFontAttributesFromContext(Text t) {
t.setFontName(fontName);
t.setFontSize(fontSize);
t.setLineHeight(lineHeight);
t.setAlign(align);
}
}