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 }