/*
* 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.onoffswitch.skin;
import eu.hansolo.enzo.common.Util;
import eu.hansolo.enzo.onoffswitch.OnOffSwitch;
import javafx.animation.TranslateTransition;
import javafx.geometry.VPos;
import javafx.scene.control.Skin;
import javafx.scene.control.SkinBase;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Region;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.FontPosture;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.util.Duration;
/**
* User: hansolo
* Date: 08.10.13
* Time: 07:50
*/
public class OnOffSwitchSkin extends SkinBase<OnOffSwitch> implements Skin<OnOffSwitch> {
private static final double PREFERRED_WIDTH = 64;
private static final double PREFERRED_HEIGHT = 32;
private static final double MINIMUM_WIDTH = 16;
private static final double MINIMUM_HEIGHT = 8;
private static final double MAXIMUM_WIDTH = 1024;
private static final double MAXIMUM_HEIGHT = 1024;
private double width;
private double height;
private Pane pane;
private double aspectRatio;
private Region background;
private Region thumb;
private Text selectedText;
private Text deselectedText;
private Font font;
private TranslateTransition moveToDeselected;
private TranslateTransition moveToSelected;
// ******************** Constructors **************************************
public OnOffSwitchSkin(final OnOffSwitch CONTROL) {
super(CONTROL);
aspectRatio = PREFERRED_HEIGHT / PREFERRED_WIDTH;
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() {
Font.loadFont(getClass().getResourceAsStream("/eu/hansolo/enzo/fonts/opensans-semibold.ttf"), (0.5 * PREFERRED_HEIGHT)); // "OpenSans"
font = Font.font("Open Sans", 0.5 * PREFERRED_HEIGHT);
background = new Region();
background.getStyleClass().setAll("background");
background.setStyle("-switch-color: " + Util.colorToCss((Color) getSkinnable().getSwitchColor()) + ";");
selectedText = new Text("1");
selectedText.setFont(font);
selectedText.getStyleClass().setAll("selected-text");
selectedText.setStyle("-text-color-on: " + Util.colorToCss((Color) getSkinnable().getTextColorOn()) + ";");
deselectedText = new Text("0");
deselectedText.setFont(font);
deselectedText.getStyleClass().setAll("deselected-text");
deselectedText.setStyle("-text-color-off: " + Util.colorToCss((Color) getSkinnable().getTextColorOff()) + ";");
thumb = new Region();
thumb.getStyleClass().setAll("thumb");
thumb.setMouseTransparent(true);
thumb.setStyle("-thumb-color: " + Util.colorToCss((Color) getSkinnable().getThumbColor()) + ";");
pane = new Pane(background, selectedText, deselectedText, thumb);
pane.getStyleClass().setAll("on-off-switch");
moveToDeselected = new TranslateTransition(Duration.millis(180), thumb);
moveToSelected = new TranslateTransition(Duration.millis(180), thumb);
// Add all nodes
getChildren().setAll(pane);
}
private void registerListeners() {
getSkinnable().widthProperty().addListener(observable -> handleControlPropertyChanged("RESIZE") );
getSkinnable().heightProperty().addListener(observable -> handleControlPropertyChanged("RESIZE") );
getSkinnable().switchColorProperty().addListener(observable -> handleControlPropertyChanged("SWITCH_COLOR") );
getSkinnable().textColorOnProperty().addListener(observable -> handleControlPropertyChanged("TEXT_ON_COLOR"));
getSkinnable().textColorOffProperty().addListener(observable -> handleControlPropertyChanged("TEXT_OFF_COLOR"));
getSkinnable().thumbColorProperty().addListener(observable -> handleControlPropertyChanged("THUMB_COLOR"));
getSkinnable().selectedProperty().addListener(observable -> handleControlPropertyChanged("SELECTED"));
pane.setOnMouseClicked(mouseEvent -> {
if (null == getSkinnable().getToggleGroup() || getSkinnable().getToggleGroup().getToggles().isEmpty()) {
getSkinnable().setSelected(!getSkinnable().isSelected());
} else {
getSkinnable().setSelected(true);
}
});
}
// ******************** Methods *******************************************
protected void handleControlPropertyChanged(final String PROPERTY) {
if ("RESIZE".equals(PROPERTY)) {
resize();
} else if ("SWITCH_COLOR".equals(PROPERTY)) {
background.setStyle("-switch-color: " + Util.colorToCss((Color) getSkinnable().getSwitchColor()) + ";");
} else if ("TEXT_ON_COLOR".equals(PROPERTY)) {
selectedText.setStyle("-text-color-selected: " + Util.colorToCss((Color) getSkinnable().getTextColorOn()) + ";");
} else if ("TEXT_OFF_COLOR".equals(PROPERTY)) {
deselectedText.setStyle("-text-color-deselected: " + Util.colorToCss((Color) getSkinnable().getTextColorOff()) + ";");
} else if ("THUMB_COLOR".equals(PROPERTY)) {
thumb.setStyle("-thumb-color: " + Util.colorToCss((Color) getSkinnable().getThumbColor()) + ";");
} else if ("SELECTED".equals(PROPERTY)) {
if (getSkinnable().isSelected()) {
moveToSelected.play();
} else {
moveToDeselected.play();
}
}
}
@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);
}
// ******************** Private Methods ***********************************
private void resize() {
width = getSkinnable().getWidth();
height = getSkinnable().getHeight();
if (width > 0 && height > 0) {
if (aspectRatio * width > height) {
width = 1 / (aspectRatio / height);
} else if (1 / (aspectRatio / height) > width) {
height = aspectRatio * width;
}
font = Font.font("Open Sans", FontWeight.EXTRA_BOLD, FontPosture.REGULAR, 0.5 * height);
background.setPrefSize(width, height);
selectedText.setFont(font);
selectedText.setTextOrigin(VPos.CENTER);
selectedText.relocate(height * 0.3125, (height - selectedText.getLayoutBounds().getHeight()) * 0.5);
deselectedText.setFont(font);
deselectedText.setTextOrigin(VPos.CENTER);
deselectedText.relocate(width - height * 0.3125 - deselectedText.getLayoutBounds().getWidth(), (height - deselectedText.getLayoutBounds().getHeight()) * 0.5);
thumb.setPrefSize((height * 0.75), (height * 0.75));
thumb.setTranslateX(getSkinnable().isSelected() ? height * 1.125 : height * 0.125);
thumb.setTranslateY(height * 0.125);
moveToDeselected.setFromX(height * 1.125);
moveToDeselected.setToX(height * 0.125);
moveToSelected.setFromX(height * 0.125);
moveToSelected.setToX(height * 1.125);
}
}
}