/*
* MultiGauge.java - Copyright(c) 2013 Joe Pasqua
* Provided under the MIT License. See the LICENSE file for details.
* Created: Apr 19, 2014
*/
package org.noroomattheinn.fxextensions;
//package multigauge;
import javafx.geometry.Side;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.effect.DropShadow;
import javafx.scene.effect.Effect;
import javafx.scene.effect.Light.Distant;
import javafx.scene.effect.Lighting;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.paint.CycleMethod;
import javafx.scene.paint.Paint;
import javafx.scene.paint.RadialGradient;
import javafx.scene.paint.Stop;
import javafx.scene.shape.Arc;
import javafx.scene.shape.ArcType;
import javafx.scene.shape.Circle;
import javafx.scene.text.Font;
import javafx.scene.text.FontSmoothingType;
import javafx.scene.text.Text;
import javafx.scene.text.TextAlignment;
import javafx.scene.text.TextBoundsType;
/**
* A gauge that displays two radial values and gives a textual readout of one.
*
* @author Joe Pasqua <joe at NoRoomAtTheInn dot org>
*/
public class MultiGauge {
private static final String FontName = "digital-7.ttf";
private static final String ResourceDir = "org/noroomattheinn/TeslaResources/";
//private static final String ResourceDir = "multigauge/";
private Pane gaugePane;
private Group centerArea;
private Text readout;
private Side readoutSide = Side.LEFT;
private Gauge left, right;
private int radius, thickness;
public MultiGauge(int radius) {
this(radius, 10, 0, 100, 0, 100);
}
public MultiGauge(int radius, int thickness,
double leftMin, double leftMax,
double rightMin, double rightMax) {
if (thickness > radius) {
thickness = radius;
}
this.radius = radius; this.thickness = thickness;
gaugePane = new Pane();
gaugePane.setPrefSize(radius * 2, radius * 2);
left = new Gauge(Side.LEFT, radius, leftMin, leftMax, Color.DARKGREEN);
right = new Gauge(Side.RIGHT, radius, rightMin, rightMax, Color.ORANGERED);
Circle centerCircle = new Circle(radius, radius, radius - thickness);
centerCircle.setFill(Color.web("#404040"));
Lighting l = new Lighting(new Distant(-135.0f, 2*radius, Color.WHITE));
l.setSurfaceScale(5.0f);
centerCircle.setEffect(l);
Circle fullCircle = new Circle(radius, radius, radius);
fullCircle.setFill(Color.web("#f0f0f0"));
fullCircle.setStroke(Color.web("#d0d0d0"));
readout = new Text("000");
Font df = Font.loadFont(getClass().getClassLoader().getResource(
ResourceDir+FontName).toExternalForm(), 17);
readout.setFont(df);
//readout.setFont(Font.font("LucidaConsole", FontWeight.BOLD, 14));
//readout.setFont(Font.font("Digital-7", 17));
readout.setFontSmoothingType(FontSmoothingType.LCD);
readout.setFill(Color.web("#fff"));
readout.setTextAlignment(TextAlignment.CENTER);
// Center the text in the display
readout.setBoundsType(TextBoundsType.VISUAL);
double w = readout.getBoundsInLocal().getWidth();
double h = readout.getBoundsInLocal().getHeight();
readout.relocate(radius - w/2 - 2, radius - h/2);
readout.setWrappingWidth(w + 4);
readout.setEffect(genTextEffect());
centerArea = new Group(centerCircle, readout);
gaugePane.getChildren().addAll(fullCircle, left.getNode(), right.getNode(), centerArea);
}
public Node getContainer() { return gaugePane; }
public void setVal(Side s, double val) {
getGauge(s).setVal(val);
if (readoutSide == s) {
readout.setText(String.valueOf((int) val));
}
}
public void setRange(Side s, double min, double max) { }
public void setPaint(Side s, Paint paint, Paint altPaint) {
getGauge(s).setPaint(paint, altPaint);
}
public void setLogScale(Side s, boolean logScale) {
getGauge(s).setLogScale(logScale);
}
public void useGradient(Side s, Color baseColor, Color altBaseColor) {
getGauge(s).setPaint(gradientFromBase(baseColor), gradientFromBase(altBaseColor));
}
private RadialGradient gradientFromBase(Color c) {
double width = radius-thickness;
double firstStop = width / ((double)radius);
return new RadialGradient(
0, 0, radius, radius, radius, false, CycleMethod.NO_CYCLE,
new Stop[]{
new Stop(0.00, trans(c, 0.0)),
new Stop(firstStop, trans(c, 0.3)),
new Stop(0.85, trans(c, 0.5)),
new Stop(1.00, c)
});
}
private Color trans(Color c, double opacity) {
return new Color(c.getRed(), c.getGreen(), c.getBlue(), opacity);
}
Side getReadoutSide() { return readoutSide; }
void setReadoutSide(Side s) { readoutSide = s == Side.LEFT ? Side.LEFT : Side.RIGHT; }
private Gauge getGauge(Side s) { return s == Side.LEFT ? left : right; }
private Effect genTextEffect() {
return new DropShadow(2, 0, 0, Color.BLUE);
}
}
class Gauge {
private static final double log100 = Math.log(100.0);
private int direction;
private double min, max;
private Arc arc;
private Paint paint, altPaint;
private Side side;
private boolean logScale;
Gauge(Side side, int radius, double min, double max, Paint p) {
this.side = side;
this.direction = side == Side.LEFT ? -1 : 1;
this.min = min;
this.max = max;
arc = new Arc(radius, radius, radius, radius, 270, 0);
arc.setType(ArcType.ROUND);
arc.setFill(p);
paint = p;
altPaint = p;
// Ok, if min < 0 and max > 0 then we do something special. We put
// 0.0 at the midpoint and paint up for positive values and down for
// nragtive values
if (max > 0 && min < 0) {
arc.setStartAngle(side == Side.LEFT? 180 : 0);
}
}
Node getNode() { return arc; }
void setRange(double min, double max) {
this.min = min; this.max = max;
if (max > 0 && min < 0) {
arc.setStartAngle(side == Side.LEFT? 180 : 0);
}
}
void setLogScale(boolean logScale) { this.logScale = logScale; }
void setPaint(Paint mainPaint, Paint altPaint) {
this.paint = mainPaint;
this.altPaint = altPaint;
}
void setVal(double val) {
val = Math.max(min, Math.min(max, val));
// Ok, if min < 0 and max > 0 then we do something special. We put
// 0.0 at the midpoint and paint up for positive values and down for
// nragtive values
if (max > 0 && min < 0) {
if (val < 0) {
double percent = val / min;
if (logScale) {
percent = (Math.log(percent*100)/log100);
}
arc.setFill(altPaint);
arc.setLength(90 * percent * direction * -1);
} else {
double percent = val / (max);
if (logScale) {
percent = (Math.log(percent*100)/log100);
}
arc.setFill(paint);
arc.setLength(90 * percent * direction);
}
} else {
double percent = val / (max-min);
if (logScale) {
percent = (Math.log(percent*100)/log100);
}
arc.setFill(paint);
arc.setLength(180 * percent * direction);
}
}
}