1 /* 2 * Copyright (c) 2009, 2012, 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 */ 24 package test.scenegraph.app; 25 26 import java.util.Arrays; 27 import java.util.List; 28 import javafx.collections.FXCollections; 29 import javafx.collections.ListChangeListener; 30 import javafx.collections.ObservableList; 31 import javafx.event.ActionEvent; 32 import javafx.event.EventHandler; 33 import javafx.scene.*; 34 import javafx.scene.control.*; 35 import javafx.scene.input.MouseEvent; 36 import javafx.scene.layout.*; 37 import javafx.scene.paint.Color; 38 import javafx.scene.shape.Circle; 39 import javafx.scene.shape.Rectangle; 40 import javafx.scene.shape.Shape; 41 42 /** 43 * 44 * @author Aleksandr Sakharuk 45 */ 46 public class DepthTestScene extends Scene 47 { 48 49 public DepthTestScene() 50 { 51 super(new BorderPane(), 500, 280.25, true); 52 BorderPane root = (BorderPane) getRoot(); 53 final Group depthTestGroup = new Group(); 54 depthTestGroup.getChildren().addListener(new NodeListener()); 55 depthTestGroup.getChildren().addAll(Nodes.RECTANGLE.getNode("green"), Nodes.CIRCLE.getNode("red")); 56 57 parentDT.setOnAction(new DepthTestChangeHandler(depthTestGroup)); 58 59 GridPane tuneGrid = new GridPane(); 60 tuneGrid.setVgap(1); 61 tuneGrid.setHgap(1); 62 tuneGrid.addRow(0, oneLabel, oneDT); 63 tuneGrid.addRow(1, anotherLabel, anotherDT); 64 tuneGrid.addRow(2, parentLabel, parentDT); 65 66 oneNodeCmb.getSelectionModel().select(Nodes.RECTANGLE); 67 oneNodeCmb.setOnAction(new NodeChangeHandler(depthTestGroup.getChildren(), 0)); 68 anotherNodeCmb.getSelectionModel().select(Nodes.CIRCLE); 69 anotherNodeCmb.setOnAction(new NodeChangeHandler(depthTestGroup.getChildren(), 1)); 70 71 HBox nodeSwitches = new HBox(1); 72 nodeSwitches.getChildren().addAll(oneNodeCmb, anotherNodeCmb); 73 74 oneToFront.setOnAction(new FrontBackChangeHandler(depthTestGroup.getChildren(), 0)); 75 anotherToFront.setOnAction(new FrontBackChangeHandler(depthTestGroup.getChildren(), 1)); 76 77 VBox backFrontRadio = new VBox(1); 78 backFrontRadio.getChildren().addAll(oneToFront, anotherToFront); 79 80 VBox switchesAndRadios = new VBox(1); 81 switchesAndRadios.getChildren().addAll(tuneGrid, backFrontRadio, 82 new HBox(10, indicator, referenceGreen, referenceRed), details); 83 84 root.setLeft(depthTestGroup); 85 root.setRight(switchesAndRadios); 86 root.setTop(nodeSwitches); 87 setCamera(new PerspectiveCamera()); 88 89 oneDT.setValue(DepthTest.INHERIT); 90 anotherDT.setValue(DepthTest.INHERIT); 91 parentDT.setValue(DepthTest.DISABLE); 92 } 93 94 private Label oneLabel = new Label("First node DepthTest"); 95 private Label anotherLabel = new Label("Second node DepthTest"); 96 private Label parentLabel = new Label("Parent node DepthTest"); 97 98 private ObservableList<DepthTest> depthTestList = FXCollections.observableArrayList(DepthTest.values()); 99 private ComboBox<DepthTest> oneDT = new ComboBox<DepthTest>(depthTestList); 100 private ComboBox<DepthTest> anotherDT = new ComboBox<DepthTest>(depthTestList); 101 private ComboBox<DepthTest> parentDT = new ComboBox<DepthTest>( 102 FXCollections.observableArrayList(DepthTest.DISABLE, DepthTest.ENABLE)); 103 104 private ObservableList<DepthTestScene.Nodes> nodesList = FXCollections.observableArrayList(DepthTestScene.Nodes.values()); 105 private ComboBox<DepthTestScene.Nodes> oneNodeCmb = new ComboBox<DepthTestScene.Nodes>(nodesList); 106 private ComboBox<DepthTestScene.Nodes> anotherNodeCmb = new ComboBox<DepthTestScene.Nodes>(nodesList); 107 108 private ToggleGroup backFrontSwitch = new ToggleGroup(); 109 private RadioButton oneToFront = new RadioButton("First node to front"); 110 private RadioButton anotherToFront = new RadioButton("Second node to front"); 111 112 private Circle indicator = new Circle(10); 113 private Label details = new Label(""); 114 private Circle referenceGreen = new Circle(10, Color.GREEN); 115 private Circle referenceRed = new Circle(10, Color.RED); 116 117 { 118 oneDT.setId("first_depth_test"); 119 anotherDT.setId("second_depth_test"); 120 parentDT.setId("parent_depth_test"); 121 122 oneNodeCmb.setId("first_node_combo"); 123 anotherNodeCmb.setId("second_node_combo"); 124 125 oneToFront.setId("first_node_to_front"); 126 anotherToFront.setId("second_node_to_front"); 127 128 oneToFront.setToggleGroup(backFrontSwitch); 129 anotherToFront.setToggleGroup(backFrontSwitch); 130 131 indicator.setId("indicator"); 132 //details.setWrapText(true); 133 referenceGreen.setId("reference_green"); 134 referenceRed.setId("reference_red"); 135 } 136 137 public enum Nodes 138 { 139 140 RECTANGLE(){ 141 public Node create() 142 { 143 Node node = new Rectangle(100, 100, Color.GREEN); 144 return node; 145 } 146 }, 147 CIRCLE(){ 148 public Node create() 149 { 150 Node node = new Circle(40, Color.RED); 151 return node; 152 } 153 }, 154 BUTTON(){ 155 public Node create() 156 { 157 Node node = new Button("Button"); 158 return node; 159 } 160 }; 161 162 protected abstract Node create(); 163 164 public Node getNode() 165 { 166 Node node = create(); 167 node.setId(toString()); 168 node.setTranslateX(100); 169 node.setTranslateY(100); 170 return node; 171 } 172 173 public Node getNode(String color) 174 { 175 Node node = create(); 176 node.setId(toString() + "-" + color); 177 if(node instanceof Shape) 178 { 179 ((Shape) node).setFill(Color.web(color)); 180 } 181 else if(node instanceof Control) 182 { 183 node.setStyle(String.format("-fx-background-color:%1$s; -fx-text-fill:%1$s", color)); 184 } 185 return node; 186 } 187 188 public String getId() 189 { 190 return id; 191 } 192 193 private String id; 194 195 } 196 197 class NodeListener implements ListChangeListener<Node> 198 { 199 200 public void onChanged(final ListChangeListener.Change<? extends Node> change) 201 { 202 while(change.next()) 203 { 204 if(change.wasAdded()) 205 { 206 final List<? extends Node> added = change.getAddedSubList(); 207 for(final Node node: added) 208 { 209 final ObservableList<? extends Node> list = change.getList(); 210 final int current = list.indexOf(node); 211 ComboBox<DepthTest> box = boxes.get(current); 212 box.setOnAction(new DepthTestScene.DepthTestChangeHandler(node)); 213 node.setDepthTest(box.getValue()); 214 labels.get(current).setText(node.getClass().getSimpleName() + " DepthTest"); 215 RadioButton radio = radios.get(current); 216 radio.setText(node.getClass().getSimpleName() + " to front"); 217 for(RadioButton rb: radios) 218 { 219 if(rb.selectedProperty().get()) 220 { 221 ActionEvent.fireEvent(rb, new ActionEvent(rb, rb)); 222 } 223 } 224 node.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() { 225 226 public void handle(MouseEvent t) 227 { 228 details.setText(node.getId() + " was reached"); 229 if(isOnTop()) 230 { 231 indicator.setStyle("-fx-fill: green;"); 232 } 233 else 234 { 235 indicator.setStyle("-fx-fill: red;"); 236 } 237 } 238 239 public boolean isOnTop() 240 { 241 boolean meets = false; 242 boolean onTop = list.indexOf(node) == list.size() - 1; 243 boolean selfDTEnable = isDepthTestEnable(boxes.get(current)); 244 boolean otherDTEnable = isDepthTestEnable(boxes.get((current + 1) % boxes.size())); 245 boolean inFront = radios.get(current).isSelected(); 246 247 if((!selfDTEnable || !otherDTEnable) && onTop) 248 meets = true; 249 if(selfDTEnable && otherDTEnable && inFront) 250 meets = true; 251 252 return meets; 253 } 254 255 private boolean isDepthTestEnable(ComboBox<DepthTest> cb) 256 { 257 boolean enable = cb.getValue().equals(DepthTest.ENABLE) || 258 (cb.getValue().equals(DepthTest.INHERIT) && 259 parentDT.getValue().equals(DepthTest.ENABLE)); 260 return enable; 261 } 262 }); 263 } 264 } 265 } 266 } 267 268 private List<ComboBox<DepthTest>> boxes = Arrays.asList(oneDT, anotherDT); 269 private List<Label> labels = Arrays.asList(oneLabel, anotherLabel); 270 private List<RadioButton> radios = Arrays.asList(oneToFront, anotherToFront); 271 272 } 273 274 class DepthTestChangeHandler implements EventHandler<ActionEvent> 275 { 276 277 DepthTestChangeHandler(Node node) 278 { 279 this.node = node; 280 } 281 282 public void handle(ActionEvent t) 283 { 284 Object source = t.getSource(); 285 if(source instanceof ComboBox) 286 { 287 node.setDepthTest(((ComboBox<DepthTest>) source).getValue()); 288 } 289 } 290 291 private Node node; 292 293 } 294 295 class NodeChangeHandler implements EventHandler<ActionEvent> 296 { 297 298 NodeChangeHandler(ObservableList<Node> nodes, int nodeIndex) 299 { 300 this.nodes = nodes; 301 this.nodeIndex = nodeIndex; 302 } 303 304 public void handle(ActionEvent t) 305 { 306 Object source = t.getSource(); 307 if(source instanceof ComboBox) 308 { 309 DepthTestScene.Nodes nd = ((ComboBox<DepthTestScene.Nodes>) source).getSelectionModel().getSelectedItem(); 310 nodes.remove(nodeIndex); 311 String color = nodeIndex == 0 ? "green" : "red"; 312 nodes.add(nodeIndex, nd.getNode(color)); 313 } 314 } 315 316 private ObservableList<Node> nodes; 317 private int nodeIndex; 318 319 } 320 321 class FrontBackChangeHandler implements EventHandler<ActionEvent> 322 { 323 324 FrontBackChangeHandler(ObservableList<Node> nodes, int nodeIndex) 325 { 326 this.nodes = nodes; 327 this.nodeIndex = nodeIndex; 328 } 329 330 public void handle(ActionEvent t) 331 { 332 for(int i = 0; i < nodes.size(); i++) 333 { 334 if(i == nodeIndex) 335 { 336 nodes.get(i).setTranslateZ(-1); 337 } 338 else 339 { 340 nodes.get(i).setTranslateZ(0); 341 } 342 } 343 } 344 345 private ObservableList<Node> nodes; 346 private int nodeIndex; 347 348 } 349 350 }