/* * 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.tbutton.skin; import eu.hansolo.enzo.common.Util; import eu.hansolo.enzo.experimental.tbutton.TButton; import javafx.event.EventHandler; import javafx.event.EventType; import javafx.geometry.VPos; 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.input.InputEvent; import javafx.scene.input.MouseEvent; 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; public class TButtonSkin extends SkinBase<TButton> implements Skin<TButton> { private static final double MINIMUM_SIZE = 25; private static final double MAXIMUM_SIZE = 1024; private static final double PREFERRED_SIZE = 144; private double size; private double width; private double height; private EventHandler<InputEvent> inputHandler; private Pane pane; private Region frame; private Region off; private InnerShadow offInnerShadow; private InnerShadow offInnerShadow1; private DropShadow offDropShadow; private Region ledOff; private InnerShadow ledOffInnerShadow; private InnerShadow ledOffInnerShadow1; private Region on; private InnerShadow onInnerShadow; private InnerShadow onInnerShadow1; private DropShadow onDropShadow; private Region ledOn; private InnerShadow ledOnInnerShadow; private InnerShadow ledOnInnerShadow1; private DropShadow ledOnGlow; private Text text; private Font font; private InnerShadow textInnerShadow; private InnerShadow textInnerShadow1; // ******************** Constructors ************************************** public TButtonSkin(final TButton CONTROL) { super(CONTROL); 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_SIZE, PREFERRED_SIZE); } } if (Double.compare(getSkinnable().getMinWidth(), 0.0) <= 0 || Double.compare(getSkinnable().getMinHeight(), 0.0) <= 0) { getSkinnable().setMinSize(MINIMUM_SIZE, MINIMUM_SIZE); } if (Double.compare(getSkinnable().getMaxWidth(), 0.0) <= 0 || Double.compare(getSkinnable().getMaxHeight(), 0.0) <= 0) { getSkinnable().setMaxSize(MAXIMUM_SIZE, MAXIMUM_SIZE); } inputHandler = new EventHandler<InputEvent>() { @Override public void handle(final InputEvent EVENT) { final EventType TYPE = EVENT.getEventType(); final Object SRC = EVENT.getSource(); if (MouseEvent.MOUSE_PRESSED == TYPE) { if (SRC.equals(on)) { getSkinnable().setSelected(false); } else if (SRC.equals(off)) { getSkinnable().setSelected(true); } EVENT.consume(); } } }; } private void initGraphics() { frame = new Region(); frame.getStyleClass().setAll("frame"); off = new Region(); off.getStyleClass().setAll("off"); offInnerShadow = new InnerShadow(); offInnerShadow.setOffsetX(0); offInnerShadow.setOffsetY(-5.0 / 144.0 * PREFERRED_SIZE); offInnerShadow.setRadius(2.0 / 144.0 * PREFERRED_SIZE); offInnerShadow.setColor(Color.web("0x00000080")); offInnerShadow.setBlurType(BlurType.TWO_PASS_BOX); offInnerShadow1 = new InnerShadow(); offInnerShadow1.setOffsetX(0.0); offInnerShadow1.setOffsetY(0.0); offInnerShadow1.setRadius(3.0 / 144.0 * PREFERRED_SIZE); offInnerShadow1.setColor(Color.web("0x0000004d")); offInnerShadow1.setBlurType(BlurType.TWO_PASS_BOX); offInnerShadow1.setInput(offInnerShadow); offDropShadow = new DropShadow(); offDropShadow.setOffsetX(0); offDropShadow.setOffsetY(10.0 / 144.0 * PREFERRED_SIZE); offDropShadow.setRadius(10.0 / 144.0 * PREFERRED_SIZE); offDropShadow.setColor(Color.web("0x000000bf")); offDropShadow.setBlurType(BlurType.TWO_PASS_BOX); offDropShadow.setInput(offInnerShadow1); off.setEffect(offDropShadow); off.setVisible(!getSkinnable().isSelected()); ledOff = new Region(); ledOff.getStyleClass().setAll("off-led"); ledOff.setMouseTransparent(true); ledOff.setVisible(!getSkinnable().isSelected()); ledOffInnerShadow = new InnerShadow(); ledOffInnerShadow.setOffsetX(0); ledOffInnerShadow.setOffsetY(2.0 / 144.0 * PREFERRED_SIZE); ledOffInnerShadow.setRadius(1.0 / 144.0 * PREFERRED_SIZE); ledOffInnerShadow.setColor(Color.web("0x0000004d")); ledOffInnerShadow.setBlurType(BlurType.TWO_PASS_BOX); ledOffInnerShadow1 = new InnerShadow(); ledOffInnerShadow1.setOffsetX(0); ledOffInnerShadow1.setOffsetY(-2.0); ledOffInnerShadow1.setRadius(1.0 / 144.0 * PREFERRED_SIZE); ledOffInnerShadow1.setColor(Color.web("0xffffffa6")); ledOffInnerShadow1.setBlurType(BlurType.TWO_PASS_BOX); ledOffInnerShadow1.setInput(ledOffInnerShadow); ledOff.setEffect(ledOffInnerShadow1); on = new Region(); on.getStyleClass().setAll("on"); onInnerShadow = new InnerShadow(); onInnerShadow.setOffsetX(0); onInnerShadow.setOffsetY(-2.0 / 144.0 * PREFERRED_SIZE); onInnerShadow.setRadius(2.0 / 144.0 * PREFERRED_SIZE); onInnerShadow.setColor(Color.web("0x00000080")); onInnerShadow.setBlurType(BlurType.TWO_PASS_BOX); onInnerShadow1 = new InnerShadow(); onInnerShadow1.setOffsetX(0); onInnerShadow1.setOffsetY(5.0 / 144.0 * PREFERRED_SIZE); onInnerShadow1.setRadius(2.0 / 144.0 * PREFERRED_SIZE); onInnerShadow1.setColor(Color.web("0x90909080")); onInnerShadow1.setBlurType(BlurType.TWO_PASS_BOX); onInnerShadow1.setInput(onInnerShadow); onDropShadow = new DropShadow(); onDropShadow.setOffsetX(0); onDropShadow.setOffsetY(1.0); onDropShadow.setRadius(1.0 / 144.0 * PREFERRED_SIZE); onDropShadow.setColor(Color.web("0x000000bf")); onDropShadow.setBlurType(BlurType.TWO_PASS_BOX); onDropShadow.setInput(onInnerShadow1); on.setEffect(onDropShadow); on.setVisible(getSkinnable().isSelected()); ledOn = new Region(); ledOn.getStyleClass().setAll("on-led"); ledOn.setMouseTransparent(true); ledOn.setVisible(getSkinnable().isSelected()); ledOnInnerShadow = new InnerShadow(); ledOnInnerShadow.setOffsetX(1.4142135623730951); ledOnInnerShadow.setOffsetY(1.414213562373095); ledOnInnerShadow.setRadius(1.0 / 144.0 * PREFERRED_SIZE); ledOnInnerShadow.setColor(getSkinnable().getLedColor().darker().darker().darker()); ledOnInnerShadow.setBlurType(BlurType.TWO_PASS_BOX); ledOnInnerShadow1 = new InnerShadow(); ledOnInnerShadow1.setOffsetX(-2.457456132866976); ledOnInnerShadow1.setOffsetY(-1.7207293090531375); ledOnInnerShadow1.setRadius(2.0 / 144.0 * PREFERRED_SIZE); ledOnInnerShadow1.setColor(getSkinnable().getLedColor().darker()); ledOnInnerShadow1.setBlurType(BlurType.TWO_PASS_BOX); ledOnInnerShadow1.setInput(ledOnInnerShadow); ledOnGlow = new DropShadow(); ledOnGlow.setOffsetX(0.0); ledOnGlow.setOffsetY(0.0); ledOnGlow.setRadius(9.0 / 144.0 * PREFERRED_SIZE); ledOnGlow.setColor(getSkinnable().getLedColor()); ledOnGlow.setBlurType(BlurType.TWO_PASS_BOX); ledOnGlow.setInput(ledOnInnerShadow1); ledOn.setEffect(ledOnGlow); Font.loadFont(getClass().getResourceAsStream("/eu/hansolo/enzo/fonts/opensans-semibold.ttf"), (28.0 / 144.0 * PREFERRED_SIZE)); // "OpenSans" font = Font.font("Open Sans", FontWeight.BOLD, FontPosture.REGULAR, 28.0 / 144.0 * PREFERRED_SIZE); text = new Text(getSkinnable().getText()); text.setFont(font); text.setTextOrigin(VPos.TOP); text.getStyleClass().add("text"); text.setMouseTransparent(true); textInnerShadow = new InnerShadow(); textInnerShadow.setOffsetX(0); textInnerShadow.setOffsetY(-1.0 / 144.0 * PREFERRED_SIZE); textInnerShadow.setRadius(1.0 / 144.0 * PREFERRED_SIZE); textInnerShadow.setColor(Color.web("0x90909080")); textInnerShadow.setBlurType(BlurType.TWO_PASS_BOX); textInnerShadow1 = new InnerShadow(); textInnerShadow1.setOffsetX(0); textInnerShadow1.setOffsetY(1.0 / 144.0 * PREFERRED_SIZE); textInnerShadow1.setRadius(1.0 / 144.0 * PREFERRED_SIZE); textInnerShadow1.setColor(Color.web("0x00000080")); textInnerShadow1.setBlurType(BlurType.TWO_PASS_BOX); textInnerShadow1.setInput(textInnerShadow); text.setEffect(textInnerShadow1); pane.getChildren().setAll(frame, off, ledOff, on, ledOn, text); getChildren().setAll(pane); resize(); } private void registerListeners() { getSkinnable().widthProperty().addListener(observable -> handleControlPropertyChanged("RESIZE") ); getSkinnable().heightProperty().addListener(observable -> handleControlPropertyChanged("RESIZE") ); getSkinnable().selectedProperty().addListener(observable -> handleControlPropertyChanged("SELECTED") ); getSkinnable().textProperty().addListener(observable -> handleControlPropertyChanged("TEXT") ); getSkinnable().ledColorProperty().addListener(observable -> handleControlPropertyChanged("LED_COLOR") ); on.setOnMousePressed(inputHandler); on.setOnTouchPressed(inputHandler); off.setOnMousePressed(inputHandler); off.setOnTouchPressed(inputHandler); } // ******************** Methods ******************************************* protected void handleControlPropertyChanged(final String PROPERTY) { if ("RESIZE".equals(PROPERTY)) { resize(); } else if ("SELECTED".equals(PROPERTY)) { getSkinnable().fireSelectEvent(getSkinnable().isSelected() ? new TButton.SelectEvent(getSkinnable(), getSkinnable(), TButton.SelectEvent.SELECT) : new TButton.SelectEvent(getSkinnable(), getSkinnable(), TButton.SelectEvent.DESELECT)); on.setVisible(getSkinnable().isSelected()); ledOn.setVisible(getSkinnable().isSelected()); off.setVisible(!getSkinnable().isSelected()); ledOff.setVisible(!getSkinnable().isSelected()); text.setTranslateY(getSkinnable().isSelected() ? (height - text.getLayoutBounds().getHeight()) * 0.49 + (3.0 / 144.0) * height : (height - text.getLayoutBounds().getHeight()) * 0.49); } else if ("TEXT".equals(PROPERTY)) { text.setText(getSkinnable().getText()); } else if ("LED_COLOR".equals(PROPERTY)) { getSkinnable().setStyle("-led-color: " + Util.colorToCss(getSkinnable().getLedColor()) + ";"); ledOnGlow.setColor(getSkinnable().getLedColor()); ledOnInnerShadow.setColor(getSkinnable().getLedColor().darker().darker().darker()); ledOnInnerShadow1.setColor(getSkinnable().getLedColor().darker()); } } @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_SIZE, 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_SIZE, 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_SIZE, 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_SIZE, 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_SIZE; 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_SIZE; if (WIDTH != -1) { prefWidth = Math.max(0, WIDTH - LEFT_INSET - RIGHT_INSET); } return super.computePrefHeight(prefWidth, TOP_INSET, RIGHT_INSET, BOTTOM_INSET, LEFT_INSET); } // ******************** Resizing ****************************************** private void resize() { size = getSkinnable().getWidth() < getSkinnable().getHeight() ? getSkinnable().getWidth() : getSkinnable().getHeight(); width = size; height = size; if (width > 0 && height > 0) { frame.setPrefSize(width, height); off.setPrefSize(0.7916666666666666 * width, 0.7916666666666666 * height); off.setTranslateX(0.10416666666666667 * width); off.setTranslateY(0.10416666666666667 * height); offInnerShadow.setOffsetY(-5.0 / 144.0 * size); offInnerShadow.setRadius(2.0 / 144.0 * size); offInnerShadow1.setRadius(3.0 / 144.0 * size); offDropShadow.setOffsetY(10.0 / 144.0 * size); offDropShadow.setRadius(10.0 / 144.0 * size); ledOff.setPrefSize(0.08333333333333333 * width, 0.08333333333333333 * height); ledOff.setTranslateX(0.4583333333333333 * width); ledOff.setTranslateY(0.7291666666666666 * height); ledOffInnerShadow.setRadius(1.0 / 144.0 * size); ledOffInnerShadow1.setRadius(1.0 / 144.0 * size); on.setPrefSize(0.7916666666666666 * width, 0.7916666666666666 * height); on.setTranslateX(0.10416666666666667 * width); on.setTranslateY(0.10416666666666667 * height); onInnerShadow.setOffsetY(-2.0 / 144.0 * size); onInnerShadow.setRadius(2.0 / 144.0 * size); onInnerShadow1.setOffsetY(4.0 / 144.0 * size); onInnerShadow1.setRadius(2.0 / 144.0 * size); onDropShadow.setRadius(1.0 / 144.0 * size); ledOn.setPrefSize(0.08333333333333333 * width, 0.08333333333333333 * height); ledOn.setTranslateX(0.4583333333333333 * width); ledOn.setTranslateY(0.75 * height); ledOnInnerShadow.setRadius(1.0 / 144.0 * size); ledOnInnerShadow1.setRadius(2.0 / 144.0 * size); ledOnGlow.setRadius(9.0 / 144.0 * size); font = Font.font("Open Sans", FontWeight.BOLD, FontPosture.REGULAR, 28.0 / 144.0 * size); text.setFont(font); if (text.getLayoutBounds().getWidth() > 0.78 * width) { text.setText("..."); } text.setTranslateX((width - text.getLayoutBounds().getWidth()) * 0.5); text.setTranslateY((height - text.getLayoutBounds().getHeight()) * 0.49); textInnerShadow.setOffsetY(-1.0 / 144.0 * size); textInnerShadow.setRadius(1.0 / 144.0 * size); textInnerShadow1.setOffsetY(1.0 / 144.0 * size); textInnerShadow1.setRadius(1.0 / 144.0 * size); } } }