/*
* 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.experimental.pushbutton.skin;
import eu.hansolo.enzo.experimental.pushbutton.PushButton;
import javafx.collections.ListChangeListener;
import javafx.scene.control.Skin;
import javafx.scene.control.SkinBase;
import javafx.scene.effect.BlurType;
import javafx.scene.effect.DropShadow;
import javafx.scene.effect.InnerShadow;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Region;
import javafx.scene.paint.Color;
public class PushButtonSkin extends SkinBase<PushButton> implements Skin<PushButton> {
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 final double PREFERRED_WIDTH = 128;
private static final double PREFERRED_HEIGHT = 128;
private double aspectRatio;
private double size;
private double width;
private double height;
private Pane pane;
private Region frame;
private InnerShadow frameInnerShadow0;
private InnerShadow frameInnerShadow1;
private Region deselected;
private InnerShadow deselectedInnerShadow0;
private InnerShadow deselectedInnerShadow1;
private DropShadow deselectedDropShadow;
private Region selected;
private InnerShadow selectedInnerShadow0;
private InnerShadow selectedInnerShadow1;
private DropShadow selectedDropShadow;
private Region icon;
// ******************** Constructors **************************************
public PushButtonSkin(final PushButton CONTROL) {
super(CONTROL);
aspectRatio = PREFERRED_HEIGHT / PREFERRED_WIDTH;
pane = new Pane();
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() {
frame = new Region();
frame.getStyleClass().setAll("frame");
frameInnerShadow0 = new InnerShadow();
frameInnerShadow0.setOffsetX(0);
frameInnerShadow0.setOffsetY(1);
frameInnerShadow0.setRadius(0);
frameInnerShadow0.setColor(Color.web("0x333333a6"));
frameInnerShadow0.setBlurType(BlurType.TWO_PASS_BOX);
frameInnerShadow1 = new InnerShadow();
frameInnerShadow1.setOffsetX(0);
frameInnerShadow1.setOffsetY(-1);
frameInnerShadow1.setRadius(0);
frameInnerShadow1.setColor(Color.web("0xeeeeeea6"));
frameInnerShadow1.setBlurType(BlurType.TWO_PASS_BOX);
frameInnerShadow1.setInput(frameInnerShadow0);
frame.setEffect(frameInnerShadow1);
deselected = new Region();
deselected.getStyleClass().setAll("deselected");
deselectedInnerShadow0 = new InnerShadow();
deselectedInnerShadow0.setOffsetX(0);
deselectedInnerShadow0.setOffsetY(-1);
deselectedInnerShadow0.setRadius(0);
deselectedInnerShadow0.setColor(Color.web("0x4b4e52a6"));
deselectedInnerShadow0.setBlurType(BlurType.TWO_PASS_BOX);
deselectedInnerShadow1 = new InnerShadow();
deselectedInnerShadow1.setOffsetX(0);
deselectedInnerShadow1.setOffsetY(1);
deselectedInnerShadow1.setRadius(0);
deselectedInnerShadow1.setColor(Color.web("0xeeeeeea6"));
deselectedInnerShadow1.setBlurType(BlurType.TWO_PASS_BOX);
deselectedInnerShadow1.setInput(deselectedInnerShadow0);
deselectedDropShadow = new DropShadow();
deselectedDropShadow.setOffsetX(0);
deselectedDropShadow.setOffsetY(3);
deselectedDropShadow.setRadius(3.0 / 128.0 * PREFERRED_WIDTH);
deselectedDropShadow.setColor(Color.web("0x000000a6"));
deselectedDropShadow.setBlurType(BlurType.TWO_PASS_BOX);
deselectedDropShadow.setInput(deselectedInnerShadow1);
deselected.setEffect(deselectedDropShadow);
selected = new Region();
selected.getStyleClass().setAll("selected");
selectedInnerShadow0 = new InnerShadow();
selectedInnerShadow0.setOffsetX(0);
selectedInnerShadow0.setOffsetY(-1);
selectedInnerShadow0.setRadius(0);
selectedInnerShadow0.setColor(Color.web("0x4b4e52a6"));
selectedInnerShadow0.setBlurType(BlurType.TWO_PASS_BOX);
selectedInnerShadow1 = new InnerShadow();
selectedInnerShadow1.setOffsetX(0);
selectedInnerShadow1.setOffsetY(1);
selectedInnerShadow1.setRadius(0);
selectedInnerShadow1.setColor(Color.web("0xeeeeeea6"));
selectedInnerShadow1.setBlurType(BlurType.TWO_PASS_BOX);
selectedInnerShadow1.setInput(selectedInnerShadow0);
selectedDropShadow = new DropShadow();
selectedDropShadow.setOffsetX(0);
selectedDropShadow.setOffsetY(0);
selectedDropShadow.setRadius(2.0 / 128.0 * PREFERRED_WIDTH);
selectedDropShadow.setColor(Color.web("0x000000a6"));
selectedDropShadow.setBlurType(BlurType.TWO_PASS_BOX);
selectedDropShadow.setInput(selectedInnerShadow1);
selected.setEffect(selectedDropShadow);
icon = new Region();
icon.getStyleClass().setAll("icon");
pane.getChildren().setAll(frame,
deselected,
selected,
icon);
// Adjust visibility dependent on settings
updateStatus();
getChildren().setAll(pane);
resize();
}
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().statusProperty().addListener(observable -> handleControlPropertyChanged("STATUS") );
getSkinnable().colorProperty().addListener(observable -> handleControlPropertyChanged("COLOR") );
getSkinnable().getStyleClass().addListener(new ListChangeListener<String>() {
@Override public void onChanged(Change<? extends String> change) {
resize();
}
});
}
// ******************** Methods *******************************************
protected void handleControlPropertyChanged(final String PROPERTY) {
if ("RESIZE".equals(PROPERTY)) {
resize();
} else if ("STATUS".equals(PROPERTY)) {
updateStatus();
} else if ("COLOR".equals(PROPERTY)) {
icon.setBackground(new Background(new BackgroundFill(getSkinnable().getColor(), null, null)));
resize();
}
}
@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 void updateStatus() {
switch (getSkinnable().getStatus()) {
case DESELECTED:
selected.setOpacity(0);
deselected.setOpacity(1);
icon.getStyleClass().setAll("icon");
icon.setOpacity(1);
break;
case SELECTED:
selected.setOpacity(1);
deselected.setOpacity(0);
icon.getStyleClass().setAll("icon", "icon-selected");
icon.setOpacity(1);
break;
case EMPTY:
default:
selected.setOpacity(0);
deselected.setOpacity(0);
icon.setOpacity(0);
break;
}
}
// ******************** 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) {
frame.setPrefSize(width, height);
deselected.setPrefSize(0.6875 * width, 0.6875 * height);
deselected.setTranslateX(0.15625 * width);
deselected.setTranslateY(0.15625 * height);
deselectedDropShadow.setRadius(3.0 / 128.0 * size);
selected.setPrefSize(0.6875 * width, 0.6796875 * height);
selected.setTranslateX(0.15625 * width);
selected.setTranslateY(0.15625 * height);
selectedDropShadow.setRadius(2.0 / 128.0 * size);
icon.setPrefSize(0.375 * width, 0.4375 * height);
icon.setTranslateX(0.3125 * width);
icon.setTranslateY(0.28125 * height);
}
}
}