1 /*
   2  * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package hello;
  27 
  28 import javafx.animation.Animation;
  29 import javafx.animation.FadeTransition;
  30 import javafx.application.Application;
  31 import javafx.beans.binding.Bindings;
  32 import javafx.beans.property.BooleanProperty;
  33 import javafx.beans.property.ObjectProperty;
  34 import javafx.beans.property.Property;
  35 import javafx.beans.property.ReadOnlyObjectProperty;
  36 import javafx.beans.property.SimpleBooleanProperty;
  37 import javafx.beans.value.WritableValue;
  38 import javafx.css.CssMetaData;
  39 import javafx.css.Styleable;
  40 import javafx.css.StyleableProperty;
  41 import javafx.css.StyleablePropertyFactory;
  42 import javafx.geometry.Insets;
  43 import javafx.geometry.Orientation;
  44 import javafx.geometry.Pos;
  45 import javafx.scene.Group;
  46 import javafx.scene.Node;
  47 import javafx.scene.Scene;
  48 import javafx.scene.SubScene;
  49 import javafx.scene.control.Button;
  50 import javafx.scene.control.Label;
  51 import javafx.scene.control.Slider;
  52 import javafx.scene.layout.BorderPane;
  53 import javafx.scene.layout.FlowPane;
  54 import javafx.scene.layout.StackPane;
  55 import javafx.scene.layout.VBox;
  56 import javafx.scene.paint.Color;
  57 import javafx.scene.shape.Rectangle;
  58 import javafx.scene.text.Text;
  59 import javafx.stage.Stage;
  60 import javafx.util.Duration;
  61 
  62 import java.util.List;
  63 
  64 public class HelloCSS extends Application {
  65     /**
  66      * @param args the command line arguments
  67      */
  68     public static void main(String[] args) {
  69         Application.launch(args);
  70     }
  71 
  72     @Override public void start(Stage stage) {
  73         stage.setTitle("Hello CSS");
  74         Scene scene = new Scene(new Group(), 600, 450);
  75         scene.setFill(Color.LIGHTGREEN);
  76         scene.getStylesheets().add("hello/hello.css");
  77         Rectangle rect = new Rectangle();
  78         rect.getStyleClass().add("rect");
  79         rect.setX(25);
  80         rect.setY(40);
  81         rect.setWidth(100);
  82         rect.setHeight(50);
  83         rect.setFill(Color.GREEN);
  84         Rectangle rect2 = new Rectangle();
  85         rect2.getStyleClass().add("rect");
  86         rect2.setX(135);
  87         rect2.setY(40);
  88         rect2.setWidth(100);
  89         rect2.setHeight(50);
  90         rect2.setStyle(
  91                 "-fx-stroke: yellow;"
  92               + "-fx-stroke-width: 3;"
  93               + "-fx-stroke-dash-array: 5 7;"
  94         );
  95 
  96         Node swapTest = createSwapTest();
  97         swapTest.setLayoutX(25);
  98         swapTest.setLayoutY(110);
  99 
 100         Node subScene = createSubSceneTest();
 101         subScene.setLayoutX(275);
 102         subScene.setLayoutY(40);
 103 
 104         Node durationTest = createDurationTest();
 105         durationTest.setLayoutX(25);
 106         durationTest.setLayoutY(210);
 107 
 108         ((Group)scene.getRoot()).getChildren().addAll(rect,rect2,swapTest,subScene, durationTest);
 109         stage.setScene(scene);
 110         stage.show();
 111     }
 112 
 113     BooleanProperty isCaspian = new SimpleBooleanProperty(this, "isCaspian");
 114     private Node createSubSceneTest() {
 115 
 116         Button button = new Button();
 117         button.setOnAction(e -> isCaspian.set(!isCaspian.get()));
 118         button.textProperty().bind(Bindings.when(isCaspian).then("Click for MODENA").otherwise("Click for CASPIAN"));
 119 
 120         Label label = new Label();
 121         label.textProperty().bind(Bindings.when(isCaspian).then("Caspian style button in a SubScene").otherwise("Modena style button in a SubScene"));
 122 
 123         VBox subSceneRoot = new VBox(5, label, button);
 124         subSceneRoot.setStyle("-fx-border-color: white; -fx-alignment: center;");
 125         SubScene subScene = new SubScene(subSceneRoot, 300, 100);
 126 
 127         isCaspian.addListener(observable -> {
 128             boolean _isCaspian = ((BooleanProperty)observable).get();
 129             if (_isCaspian) {
 130                 subScene.setUserAgentStylesheet("com/sun/javafx/scene/control/skin/caspian/caspian.css");
 131             } else {
 132                 subScene.setUserAgentStylesheet("com/sun/javafx/scene/control/skin/modena/modena.css");
 133             }
 134         });
 135 
 136         isCaspian.setValue(Boolean.TRUE);
 137 
 138         return subScene;
 139     }
 140 
 141     private Node createSwapTest() {
 142 
 143         final StackPane r1 = new StackPane();
 144         r1.setPrefSize(100,50);
 145         r1.setStyle("-fx-base: red; -fx-border-color: red;");
 146 
 147         final StackPane r2 = new StackPane();
 148         r2.setPrefSize(100,50);
 149         r2.setStyle("-fx-base: yellow; -fx-border-color: yellow;");
 150 
 151         final Button swapButton = new Button("Move");
 152         swapButton.setOnAction(actionEvent -> {
 153             if (swapButton.getParent() == r1) {
 154                 r1.getChildren().remove(swapButton);
 155                 r2.getChildren().add(swapButton);
 156             } else if (swapButton.getParent() == r2) {
 157                 r2.getChildren().remove(swapButton);
 158                 r1.getChildren().add(swapButton);
 159             }
 160         });
 161         r1.getChildren().add(swapButton);
 162 
 163         FlowPane hBox = new FlowPane(Orientation.HORIZONTAL, 5, 5);
 164         hBox.getChildren().addAll(r1, r2, new Text("Click button to move.\nButton's base color should match surrounding border."));
 165 
 166         return hBox;
 167     }
 168 
 169     private static class TestNode extends Rectangle {
 170 
 171         public TestNode() {
 172             super(100, 100);
 173         }
 174 
 175         @Override public void impl_processCSS() {
 176             super.impl_processCSS();
 177         }
 178         StyleablePropertyFactory<TestNode> factory = new StyleablePropertyFactory<>(Rectangle.getClassCssMetaData());
 179         StyleableProperty<Duration> myDuration = factory.createStyleableDurationProperty(this, "myDuration", "-my-duration", (s) -> s.myDuration, Duration.millis(1000));
 180 
 181         @Override public List<CssMetaData<? extends Styleable, ?>> getCssMetaData() {
 182             return factory.getCssMetaData();
 183         }
 184     }
 185 
 186 
 187     BooleanProperty fadeIn = new SimpleBooleanProperty(false);
 188     private Node createDurationTest() {
 189 
 190         final BorderPane pane = new BorderPane();
 191         pane.setStyle("-fx-border-color: blue;");
 192         pane.setPadding(new Insets(10,10,10,10));
 193 
 194         Slider slider = new Slider();
 195         slider.setPadding(new Insets(5,5,5,10));
 196         slider.setMin(500d);
 197         slider.setMax(1500d);
 198         slider.setBlockIncrement(50);
 199         slider.setValue(1000d);
 200         slider.setShowTickLabels(true);
 201         slider.setShowTickMarks(true);
 202         slider.setSnapToTicks(true);
 203         slider.setOrientation(Orientation.VERTICAL);
 204 
 205         pane.setRight(slider);
 206 
 207         final TestNode testNode = new TestNode();
 208         slider.valueProperty().addListener(o -> testNode.setStyle("-my-duration: " + ((Property<Number>)o).getValue().intValue() + "ms;"));
 209 
 210         final Button fadeButton = new Button();
 211         fadeButton.textProperty().bind(Bindings.when(fadeIn).then("Fade In").otherwise("Fade Out"));
 212         fadeButton.setOnAction(e -> {
 213             Duration duration = testNode.myDuration.getValue();
 214             FadeTransition transition = new FadeTransition(duration, testNode);
 215             transition.setFromValue(testNode.getOpacity());
 216             transition.statusProperty().addListener(o -> {
 217                 if (((ReadOnlyObjectProperty<Animation.Status>) o).getValue() == Animation.Status.STOPPED) {
 218                     fadeButton.setDisable(false);
 219                 } else {
 220                     fadeButton.setDisable(true);
 221                 }
 222             });
 223             if (fadeIn.get()) {
 224                 transition.setToValue(1.0);
 225                 transition.setByValue(5);
 226                 transition.setOnFinished(a -> fadeIn.set(false));
 227             } else {
 228                 transition.setToValue(0.1);
 229                 transition.setByValue(-5);
 230                 transition.setOnFinished(a -> fadeIn.set(true));
 231             }
 232             transition.playFromStart();
 233         });
 234 
 235         VBox vbox = new VBox(5, testNode, fadeButton);
 236         vbox.setAlignment(Pos.CENTER);
 237         pane.setCenter(vbox);
 238 
 239         Label label = new Label("Use slider to adjust duration of the\nFadeTransition, then click the button.");
 240         pane.setTop(label);
 241 
 242         Label status = new Label();
 243         status.textProperty().bind(Bindings.createStringBinding(
 244                 () -> testNode.myDuration.getValue().toString(),
 245                 (ObjectProperty<Duration>)testNode.myDuration
 246         ));
 247         pane.setBottom(status);
 248 
 249         BorderPane.setAlignment(label, Pos.CENTER);
 250         BorderPane.setAlignment(slider, Pos.CENTER);
 251         BorderPane.setAlignment(vbox, Pos.CENTER);
 252         BorderPane.setAlignment(status, Pos.BOTTOM_RIGHT);
 253 
 254         return pane;
 255     }
 256 
 257 }