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