/* * Copyright (c) 2016 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 customnodes; import javafx.animation.Animation; import javafx.animation.Animation.Status; import javafx.animation.KeyFrame; import javafx.animation.KeyValue; import javafx.animation.Timeline; import javafx.beans.DefaultProperty; import javafx.beans.property.ObjectProperty; import javafx.beans.property.ObjectPropertyBase; import javafx.collections.ObservableList; import javafx.scene.Node; import javafx.geometry.Insets; import javafx.scene.layout.Background; import javafx.scene.layout.BackgroundFill; import javafx.scene.layout.Border; import javafx.scene.layout.BorderStroke; import javafx.scene.layout.BorderStrokeStyle; import javafx.scene.layout.BorderWidths; import javafx.scene.layout.CornerRadii; import javafx.scene.layout.Pane; import javafx.scene.layout.Region; import javafx.scene.paint.Color; import javafx.scene.paint.Paint; import javafx.scene.shape.Arc; import javafx.scene.shape.StrokeLineCap; import javafx.scene.transform.Rotate; import javafx.util.Duration; /** * User: hansolo Date: 14.12.16 Time: 08:58 */ @DefaultProperty("children") public class FunIndicator extends Region { /** The Constant PREFERRED_WIDTH. */ private static final double PREFERRED_WIDTH = 250; /** The Constant PREFERRED_HEIGHT. */ private static final double PREFERRED_HEIGHT = 250; /** The Constant MINIMUM_WIDTH. */ private static final double MINIMUM_WIDTH = 50; /** The Constant MINIMUM_HEIGHT. */ private static final double MINIMUM_HEIGHT = 50; /** The Constant MAXIMUM_WIDTH. */ private static final double MAXIMUM_WIDTH = 1024; /** The Constant MAXIMUM_HEIGHT. */ private static final double MAXIMUM_HEIGHT = 1024; /** The size. */ private double size; /** The arc 7. */ private Arc arc1, arc2, arc3, arc4, arc5, arc6, arc7; /** The rot 7. */ private Rotate rot1, rot2, rot3, rot4, rot5, rot6, rot7; /** The pane. */ private Pane pane; /** The background paint. */ private Paint backgroundPaint; /** The border paint. */ private Paint borderPaint; /** The border width. */ private double borderWidth; /** The from color. */ private ObjectProperty<Color> fromColor; /** The to color. */ private ObjectProperty<Color> toColor; /** The color. */ private ObjectProperty<Color> color; /** The timeline. */ private Timeline timeline; /** * Instantiates a new fun indicator. */ // ******************** Constructors ************************************** public FunIndicator() { backgroundPaint = Color.TRANSPARENT; borderPaint = Color.TRANSPARENT; borderWidth = 0d; fromColor = new ObjectPropertyBase<Color>(Color.rgb(255, 166, 9)) { @Override public Object getBean() { return FunIndicator.this; } @Override public String getName() { return "fromColor"; } }; toColor = new ObjectPropertyBase<Color>(Color.rgb(9, 255, 166)) { @Override public Object getBean() { return FunIndicator.this; } @Override public String getName() { return "toColor"; } }; color = new ObjectPropertyBase<Color>() { @Override public Object getBean() { return FunIndicator.this; } @Override public String getName() { return "color"; } }; timeline = new Timeline(); initGraphics(); initTimeline(); registerListeners(); } /** * Inits the graphics. */ // ******************** Initialization ************************************ private void initGraphics() { if (Double.compare(getPrefWidth(), 0.0) <= 0 || Double.compare(getPrefHeight(), 0.0) <= 0 || Double.compare(getWidth(), 0.0) <= 0 || Double.compare(getHeight(), 0.0) <= 0) { if (getPrefWidth() > 0 && getPrefHeight() > 0) { setPrefSize(getPrefWidth(), getPrefHeight()); } else { setPrefSize(PREFERRED_WIDTH, PREFERRED_HEIGHT); } } rot1 = new Rotate(0, PREFERRED_WIDTH * 0.5, PREFERRED_HEIGHT * 0.5); rot2 = new Rotate(0, PREFERRED_WIDTH * 0.5, PREFERRED_HEIGHT * 0.5); rot3 = new Rotate(0, PREFERRED_WIDTH * 0.5, PREFERRED_HEIGHT * 0.5); rot4 = new Rotate(0, PREFERRED_WIDTH * 0.5, PREFERRED_HEIGHT * 0.5); rot5 = new Rotate(0, PREFERRED_WIDTH * 0.5, PREFERRED_HEIGHT * 0.5); rot6 = new Rotate(0, PREFERRED_WIDTH * 0.5, PREFERRED_HEIGHT * 0.5); rot7 = new Rotate(0, PREFERRED_WIDTH * 0.5, PREFERRED_HEIGHT * 0.5); arc1 = createArc(); arc1.getTransforms().add(rot1); arc2 = createArc(); arc2.getTransforms().add(rot2); arc3 = createArc(); arc3.getTransforms().add(rot3); arc4 = createArc(); arc4.getTransforms().add(rot4); arc5 = createArc(); arc5.getTransforms().add(rot5); arc6 = createArc(); arc6.getTransforms().add(rot6); arc7 = createArc(); arc7.getTransforms().add(rot7); pane = new Pane(arc1, arc2, arc3, arc4, arc5, arc6, arc7); pane.setBackground(new Background(new BackgroundFill(backgroundPaint, CornerRadii.EMPTY, Insets.EMPTY))); pane.setBorder(new Border(new BorderStroke(borderPaint, BorderStrokeStyle.SOLID, CornerRadii.EMPTY, new BorderWidths(borderWidth)))); getChildren().setAll(pane); } /** * Inits the timeline. */ private void initTimeline() { boolean wasRunning = Status.RUNNING == timeline.getStatus(); timeline.stop(); KeyValue colorKvBegin = new KeyValue(color, fromColor.get()); KeyValue colorKvMid = new KeyValue(color, toColor.get()); KeyValue colorKvEnd = new KeyValue(color, fromColor.get()); KeyValue arc1KvBegin = new KeyValue(rot1.angleProperty(), 0); KeyValue arc1KvEnd = new KeyValue(rot1.angleProperty(), 360); KeyValue arc2KvBegin = new KeyValue(rot2.angleProperty(), 0); KeyValue arc2KvEnd = new KeyValue(rot2.angleProperty(), 720); KeyValue arc3KvBegin = new KeyValue(rot3.angleProperty(), 0); KeyValue arc3KvEnd = new KeyValue(rot3.angleProperty(), 1080); KeyValue arc4KvBegin = new KeyValue(rot4.angleProperty(), 0); KeyValue arc4KvEnd = new KeyValue(rot4.angleProperty(), 1440); KeyValue arc5KvBegin = new KeyValue(rot5.angleProperty(), 0); KeyValue arc5KvEnd = new KeyValue(rot5.angleProperty(), 1800); KeyValue arc6KvBegin = new KeyValue(rot6.angleProperty(), 0); KeyValue arc6KvEnd = new KeyValue(rot6.angleProperty(), 2160); KeyValue arc7KvBegin = new KeyValue(rot7.angleProperty(), 0); KeyValue arc7KvEnd = new KeyValue(rot7.angleProperty(), 2520); KeyFrame kf1 = new KeyFrame(Duration.ZERO, colorKvBegin, arc1KvBegin, arc2KvBegin, arc3KvBegin, arc4KvBegin, arc5KvBegin, arc6KvBegin, arc7KvBegin); KeyFrame kf2 = new KeyFrame(Duration.millis(3000), colorKvMid); KeyFrame kf3 = new KeyFrame(Duration.millis(6000), colorKvEnd, arc1KvEnd, arc2KvEnd, arc3KvEnd, arc4KvEnd, arc5KvEnd, arc6KvEnd, arc7KvEnd); timeline.getKeyFrames().setAll(kf1, kf2, kf3); timeline.setCycleCount(Animation.INDEFINITE); if (wasRunning) timeline.play(); } /** * Register listeners. */ private void registerListeners() { widthProperty().addListener(o -> resize()); heightProperty().addListener(o -> resize()); fromColorProperty().addListener(o -> initTimeline()); toColorProperty().addListener(o -> initTimeline()); } /** * Gets the from color. * * @return the from color */ // ******************** Methods ******************************************* public Color getFromColor() { return fromColor.get(); } /** * Sets the from color. * * @param COLOR * the new from color */ public void setFromColor(final Color COLOR) { fromColor.set(COLOR); } /** * From color property. * * @return the object property */ public ObjectProperty<Color> fromColorProperty() { return fromColor; } /** * Gets the to color. * * @return the to color */ public Color getToColor() { return toColor.get(); } /** * Sets the to color. * * @param COLOR * the new to color */ public void setToColor(final Color COLOR) { toColor.set(COLOR); } /** * To color property. * * @return the object property */ public ObjectProperty<Color> toColorProperty() { return toColor; } /* (non-Javadoc) * @see javafx.scene.Parent#layoutChildren() */ @Override public void layoutChildren() { super.layoutChildren(); } /* (non-Javadoc) * @see javafx.scene.layout.Region#computeMinWidth(double) */ @Override protected double computeMinWidth(final double HEIGHT) { return MINIMUM_WIDTH; } /* (non-Javadoc) * @see javafx.scene.layout.Region#computeMinHeight(double) */ @Override protected double computeMinHeight(final double WIDTH) { return MINIMUM_HEIGHT; } /* (non-Javadoc) * @see javafx.scene.layout.Region#computePrefWidth(double) */ @Override protected double computePrefWidth(final double HEIGHT) { return super.computePrefWidth(HEIGHT); } /* (non-Javadoc) * @see javafx.scene.layout.Region#computePrefHeight(double) */ @Override protected double computePrefHeight(final double WIDTH) { return super.computePrefHeight(WIDTH); } /* (non-Javadoc) * @see javafx.scene.layout.Region#computeMaxWidth(double) */ @Override protected double computeMaxWidth(final double HEIGHT) { return MAXIMUM_WIDTH; } /* (non-Javadoc) * @see javafx.scene.layout.Region#computeMaxHeight(double) */ @Override protected double computeMaxHeight(final double WIDTH) { return MAXIMUM_HEIGHT; } /* (non-Javadoc) * @see javafx.scene.Parent#getChildren() */ @Override public ObservableList<Node> getChildren() { return super.getChildren(); } /** * Start. */ public void start() { timeline.play(); } /** * Stop. */ public void stop() { timeline.stop(); } /** * Pause. */ public void pause() { timeline.pause(); } /** * Creates the arc. * * @return the arc */ private Arc createArc() { Arc arc = new Arc(PREFERRED_WIDTH * 0.5, PREFERRED_HEIGHT * 0.5, 0, 00, 50, 80); arc.setFill(null); arc.strokeProperty().bind(color); arc.setStrokeLineCap(StrokeLineCap.ROUND); return arc; } /** * Resize arc. * * @param ARC * the arc * @param CENTER * the center * @param RADIUS * the radius * @param STROKE_WIDTH * the stroke width */ // ******************** Resizing ****************************************** private void resizeArc(final Arc ARC, final double CENTER, final double RADIUS, final double STROKE_WIDTH) { ARC.setCenterX(CENTER); ARC.setCenterY(CENTER); ARC.setRadiusX(RADIUS); ARC.setRadiusY(RADIUS); ARC.setStrokeWidth(STROKE_WIDTH); } /** * Resize. */ private void resize() { double width = getWidth() - getInsets().getLeft() - getInsets().getRight(); double height = getHeight() - getInsets().getTop() - getInsets().getBottom(); size = width < height ? width : height; if (width > 0 && height > 0) { pane.setMaxSize(size, size); pane.setPrefSize(size, size); pane.relocate((getWidth() - size) * 0.5, (getHeight() - size) * 0.5); double strokeWidth = size * 0.02; double center = size * 0.5; rot1.setPivotX(center); rot1.setPivotY(center); rot2.setPivotX(center); rot2.setPivotY(center); rot3.setPivotX(center); rot3.setPivotY(center); rot4.setPivotX(center); rot4.setPivotY(center); rot5.setPivotX(center); rot5.setPivotY(center); rot6.setPivotX(center); rot6.setPivotY(center); rot7.setPivotX(center); rot7.setPivotY(center); resizeArc(arc1, center, size * 0.45, strokeWidth); resizeArc(arc2, center, size * 0.4125, strokeWidth); resizeArc(arc3, center, size * 0.375, strokeWidth); resizeArc(arc4, center, size * 0.3375, strokeWidth); resizeArc(arc5, center, size * 0.3, strokeWidth); resizeArc(arc6, center, size * 0.2625, strokeWidth); resizeArc(arc7, center, size * 0.225, strokeWidth); redraw(); } } /** * Redraw. */ private void redraw() { pane.setBackground(new Background(new BackgroundFill(backgroundPaint, CornerRadii.EMPTY, Insets.EMPTY))); pane.setBorder(new Border(new BorderStroke(borderPaint, BorderStrokeStyle.SOLID, CornerRadii.EMPTY, new BorderWidths(borderWidth / PREFERRED_WIDTH * size)))); } }