/*
* Copyright (c) 2013 by Gerrit Grunwald
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package eu.hansolo.enzo.sevensegment.skin;
import eu.hansolo.enzo.sevensegment.SevenSegment;
import javafx.collections.ListChangeListener;
import javafx.scene.control.Skin;
import javafx.scene.control.SkinBase;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Region;
import java.util.HashMap;
import java.util.Map;
public class SevenSegmentSkin extends SkinBase<SevenSegment> implements Skin<SevenSegment> {
private static final double PREFERRED_WIDTH = 268;
private static final double PREFERRED_HEIGHT = 357;
private static final double MINIMUM_WIDTH = 5;
private static final double MINIMUM_HEIGHT = 5;
private static final double MAXIMUM_WIDTH = 1024;
private static final double MAXIMUM_HEIGHT = 1024;
private static double aspectRatio;
private double size;
private double width;
private double height;
private Pane pane;
private Region segmentA;
private Region segmentB;
private Region segmentC;
private Region segmentD;
private Region segmentE;
private Region segmentF;
private Region segmentG;
private Region segmentDot;
private Map<SevenSegment.Segment, Region> segmentMap;
// ******************** Constructors **************************************
public SevenSegmentSkin(final SevenSegment CONTROL) {
super(CONTROL);
aspectRatio = PREFERRED_HEIGHT / PREFERRED_WIDTH;
pane = new Pane();
segmentMap = new HashMap<>(8);
init();
initGraphics();
registerListeners();
}
// ******************** Initialization ************************************
private void init() {
if (Double.compare(getSkinnable().getPrefWidth(), 0.0) <= 0 || Double.compare(getSkinnable().getPrefHeight(), 0.0) <= 0 ||
Double.compare(getSkinnable().getWidth(), 0.0) <= 0 || Double.compare(getSkinnable().getHeight(), 0.0) <= 0) {
if (getSkinnable().getPrefWidth() > 0 && getSkinnable().getPrefHeight() > 0) {
getSkinnable().setPrefSize(getSkinnable().getPrefWidth(), getSkinnable().getPrefHeight());
} else {
getSkinnable().setPrefSize(PREFERRED_WIDTH, PREFERRED_HEIGHT);
}
}
if (Double.compare(getSkinnable().getMinWidth(), 0.0) <= 0 || Double.compare(getSkinnable().getMinHeight(), 0.0) <= 0) {
getSkinnable().setMinSize(MINIMUM_WIDTH, MINIMUM_HEIGHT);
}
if (Double.compare(getSkinnable().getMaxWidth(), 0.0) <= 0 || Double.compare(getSkinnable().getMaxHeight(), 0.0) <= 0) {
getSkinnable().setMaxSize(MAXIMUM_WIDTH, MAXIMUM_HEIGHT);
}
if (getSkinnable().getPrefWidth() != PREFERRED_WIDTH || getSkinnable().getPrefHeight() != PREFERRED_HEIGHT) {
aspectRatio = getSkinnable().getPrefHeight() / getSkinnable().getPrefWidth();
}
}
private void initGraphics() {
segmentA = new Region();
segmentA.getStyleClass().setAll("a");
segmentMap.put(SevenSegment.Segment.A, segmentA);
segmentB = new Region();
segmentB.getStyleClass().setAll("b");
segmentMap.put(SevenSegment.Segment.B, segmentB);
segmentC = new Region();
segmentC.getStyleClass().setAll("c");
segmentMap.put(SevenSegment.Segment.C, segmentC);
segmentD = new Region();
segmentD.getStyleClass().setAll("d");
segmentMap.put(SevenSegment.Segment.D, segmentD);
segmentE = new Region();
segmentE.getStyleClass().setAll("e");
segmentMap.put(SevenSegment.Segment.E, segmentE);
segmentF = new Region();
segmentF.getStyleClass().setAll("f");
segmentMap.put(SevenSegment.Segment.F, segmentF);
segmentG = new Region();
segmentG.getStyleClass().setAll("g");
segmentMap.put(SevenSegment.Segment.G, segmentG);
segmentDot = new Region();
segmentDot.getStyleClass().setAll("dot");
segmentMap.put(SevenSegment.Segment.DOT, segmentDot);
pane.getChildren().setAll(segmentA,
segmentB,
segmentC,
segmentD,
segmentE,
segmentF,
segmentG,
segmentDot);
getChildren().setAll(pane);
resize();
update();
}
private void registerListeners() {
getSkinnable().widthProperty().addListener(observable -> handleControlPropertyChanged("RESIZE") );
getSkinnable().heightProperty().addListener(observable -> handleControlPropertyChanged("RESIZE") );
getSkinnable().prefWidthProperty().addListener(observable -> handleControlPropertyChanged("PREF_SIZE") );
getSkinnable().prefHeightProperty().addListener(observable -> handleControlPropertyChanged("PREF_SIZE") );
getSkinnable().characterProperty().addListener(observable -> handleControlPropertyChanged("CHARACTER") );
getSkinnable().dotOnProperty().addListener(observable -> handleControlPropertyChanged("DOT_ON") );
getSkinnable().segmentStyleProperty().addListener(observable -> handleControlPropertyChanged("UPDATE") );
getSkinnable().getStyleClass().addListener(new ListChangeListener<String>() {
@Override public void onChanged(Change<? extends String> change) {
resize();
update();
}
});
}
// ******************** Methods *******************************************
protected void handleControlPropertyChanged(final String PROPERTY) {
if ("UPDATE".equals(PROPERTY)) {
update();
} else if ("RESIZE".equals(PROPERTY)) {
resize();
update();
} else if ("PREF_SIZE".equals(PROPERTY)) {
aspectRatio = getSkinnable().getPrefHeight() / getSkinnable().getPrefWidth();
} else if ("CHARACTER".equals(PROPERTY)) {
update();
} else if ("DOT_ON".equals(PROPERTY)) {
update();
}
}
@Override protected double computeMinWidth(final double HEIGHT, double TOP_INSET, double RIGHT_INSET, double BOTTOM_INSET, double LEFT_INSET) {
return super.computeMinWidth(Math.max(MINIMUM_HEIGHT, HEIGHT - TOP_INSET - BOTTOM_INSET), TOP_INSET, RIGHT_INSET, BOTTOM_INSET, LEFT_INSET);
}
@Override protected double computeMinHeight(final double WIDTH, double TOP_INSET, double RIGHT_INSET, double BOTTOM_INSET, double LEFT_INSET) {
return super.computeMinHeight(Math.max(MINIMUM_WIDTH, WIDTH - LEFT_INSET - RIGHT_INSET), TOP_INSET, RIGHT_INSET, BOTTOM_INSET, LEFT_INSET);
}
@Override protected double computeMaxWidth(final double HEIGHT, double TOP_INSET, double RIGHT_INSET, double BOTTOM_INSET, double LEFT_INSET) {
return super.computeMaxWidth(Math.min(MAXIMUM_HEIGHT, HEIGHT - TOP_INSET - BOTTOM_INSET), TOP_INSET, RIGHT_INSET, BOTTOM_INSET, LEFT_INSET);
}
@Override protected double computeMaxHeight(final double WIDTH, double TOP_INSET, double RIGHT_INSET, double BOTTOM_INSET, double LEFT_INSET) {
return super.computeMaxHeight(Math.min(MAXIMUM_WIDTH, WIDTH - LEFT_INSET - RIGHT_INSET), TOP_INSET, RIGHT_INSET, BOTTOM_INSET, LEFT_INSET);
}
@Override protected double computePrefWidth(final double HEIGHT, double TOP_INSET, double RIGHT_INSET, double BOTTOM_INSET, double LEFT_INSET) {
double prefHeight = PREFERRED_HEIGHT;
if (HEIGHT != -1) {
prefHeight = Math.max(0, HEIGHT - TOP_INSET - BOTTOM_INSET);
}
return super.computePrefWidth(prefHeight, TOP_INSET, RIGHT_INSET, BOTTOM_INSET, LEFT_INSET);
}
@Override protected double computePrefHeight(final double WIDTH, double TOP_INSET, double RIGHT_INSET, double BOTTOM_INSET, double LEFT_INSET) {
double prefWidth = PREFERRED_WIDTH;
if (WIDTH != -1) {
prefWidth = Math.max(0, WIDTH - LEFT_INSET - RIGHT_INSET);
}
return super.computePrefHeight(prefWidth, TOP_INSET, RIGHT_INSET, BOTTOM_INSET, LEFT_INSET);
}
// ******************** Update ********************************************
private void update() {
final int ASCII = getSkinnable().getCharacter().isEmpty() ? 20 : getSkinnable().getCharacter().toUpperCase().charAt(0);
final String ON_STYLE = getSkinnable().getSegmentStyle().ON_CLASS;
final String OFF_STYLE = getSkinnable().getSegmentStyle().OFF_CLASS;
for (SevenSegment.Segment segment : segmentMap.keySet()) {
if (getSkinnable().getSegmentMapping().containsKey(ASCII)) {
if (getSkinnable().getSegmentMapping().get(ASCII).contains(segment)) {
segmentMap.get(segment).getStyleClass().setAll(segment.name().toLowerCase(), ON_STYLE);
} else {
segmentMap.get(segment).getStyleClass().setAll(segment.name().toLowerCase(), OFF_STYLE);
}
} else {
segmentMap.get(segment).getStyleClass().setAll(segment.name().toLowerCase(), OFF_STYLE);
}
}
if (getSkinnable().isDotOn()) {
segmentMap.get(SevenSegment.Segment.DOT).getStyleClass().setAll("dot", ON_STYLE);
} else {
segmentMap.get(SevenSegment.Segment.DOT).getStyleClass().setAll("dot", OFF_STYLE);
}
}
// ******************** Resizing ******************************************
private void resize() {
size = getSkinnable().getWidth() < getSkinnable().getHeight() ? getSkinnable().getWidth() : getSkinnable().getHeight();
width = getSkinnable().getWidth();
height = getSkinnable().getHeight();
if (getSkinnable().isKeepAspect()) {
if (aspectRatio * width > height) {
width = 1 / (aspectRatio / height);
} else if (1 / (aspectRatio / height) > width) {
height = aspectRatio * width;
}
}
if (width > 0 && height > 0) {
segmentA.setPrefSize(0.7078622846461055 * width, 0.12605043085349374 * height);
segmentA.setTranslateX(0.11621808294040054 * width);
segmentA.setTranslateY(0.0 * height);
segmentB.setPrefSize(0.19782541758978545 * width, 0.4623330167027749 * height);
segmentB.setTranslateX(0.6715775674848414 * width);
segmentB.setTranslateY(0.03402365890203738 * height);
segmentC.setPrefSize(0.20474943474157534 * width, 0.46794295110622375 * height);
segmentC.setTranslateX(0.6267936478799848 * width);
segmentC.setTranslateY(0.5036215902376575 * height);
segmentD.setPrefSize(0.7041493885552705 * width, 0.12605042016806722 * height);
segmentD.setTranslateX(0.04532256055234084 * width);
segmentD.setTranslateY(0.8739495798319328 * height);
segmentE.setPrefSize(0.20156638302020172 * width, 0.4595308704536502 * height);
segmentE.setTranslateX(0.0 * width);
segmentE.setTranslateY(0.5036443288252801 * height);
segmentF.setPrefSize(0.20103195532044368 * width, 0.47076633998325895 * height);
segmentF.setTranslateX(0.03783089367311392 * width);
segmentF.setTranslateY(0.028435463998831956 * height);
segmentG.setPrefSize(0.6134279165694962 * width, 0.12605042016806722 * height);
segmentG.setTranslateX(0.12985323436224638 * width);
segmentG.setTranslateY(0.4369747899159664 * height);
segmentDot.setPrefSize(0.16791044776119404 * width, 0.12605042016806722 * height);
segmentDot.setTranslateX(0.832089552238806 * width);
segmentDot.setTranslateY(0.8739495798319328 * height);
}
}
}