1 /* 2 * Copyright (c) 2014, Oracle and/or its affiliates. 3 * All rights reserved. Use is subject to license terms. 4 * 5 * This file is available and licensed under the following license: 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * - Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * - Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the distribution. 16 * - Neither the name of Oracle Corporation nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 package com.oracle.javafx.scenebuilder.kit.util.control.effectpicker.editors; 33 34 import com.oracle.javafx.scenebuilder.kit.util.control.effectpicker.EffectPickerController; 35 import com.oracle.javafx.scenebuilder.kit.util.control.paintpicker.PaintPicker; 36 37 import java.io.IOException; 38 import java.io.InputStream; 39 import java.net.URL; 40 41 import javafx.beans.property.BooleanProperty; 42 import javafx.beans.property.ObjectProperty; 43 import javafx.beans.property.SimpleBooleanProperty; 44 import javafx.beans.property.SimpleObjectProperty; 45 import javafx.beans.value.ChangeListener; 46 import javafx.event.ActionEvent; 47 import javafx.event.Event; 48 import javafx.fxml.FXML; 49 import javafx.fxml.FXMLLoader; 50 import javafx.scene.Parent; 51 import javafx.scene.control.ChoiceBox; 52 import javafx.scene.control.Label; 53 import javafx.scene.effect.Light; 54 import javafx.scene.effect.Light.Distant; 55 import javafx.scene.effect.Light.Point; 56 import javafx.scene.effect.Light.Spot; 57 import javafx.scene.layout.VBox; 58 import javafx.scene.paint.Color; 59 import javafx.scene.paint.Paint; 60 61 public class LightControl extends VBox { 62 63 @FXML 64 private Label lightLabel; 65 @FXML 66 private ChoiceBox<LightsEnum> lightChoiceBox; 67 @FXML 68 private VBox lightProperties; 69 70 private final ObjectProperty<Light> value = new SimpleObjectProperty<>(); 71 private final EffectPickerController effectPickerController; 72 73 // Common color property 74 private PaintPicker colorPicker; 75 76 private final Light defaultDistant; 77 private final Light defaultPoint; 78 private final Light defaultSpot; 79 80 private final BooleanProperty liveUpdate = new SimpleBooleanProperty(); 81 82 private enum LightsEnum { 83 84 DISTANT, 85 POINT, 86 SPOT, 87 NONE 88 } 89 90 public LightControl(EffectPickerController effectPickerController, 91 String label, Light initValue) { 92 this.effectPickerController = effectPickerController; 93 this.defaultDistant = new Distant(); 94 this.defaultPoint = new Point(); 95 this.defaultSpot = new Spot(); 96 initialize(label, initValue); 97 } 98 99 public ObjectProperty<Light> valueProperty() { 100 return value; 101 } 102 103 public Light getValue() { 104 return value.get(); 105 } 106 107 public void setValue(Light v) { 108 value.set(v); 109 } 110 111 public final BooleanProperty liveUpdateProperty() { 112 return liveUpdate; 113 } 114 115 public boolean isLiveUpdate() { 116 return liveUpdate.get(); 117 } 118 119 public void setLiveUpdate(boolean value) { 120 liveUpdate.setValue(value); 121 } 122 123 private void initialize(String label, Light initValue) { 124 125 final URL layoutURL = EnumControl.class.getResource("LightControl.fxml"); //NOI18N 126 try (InputStream is = layoutURL.openStream()) { 127 final FXMLLoader loader = new FXMLLoader(); 128 loader.setController(this); 129 loader.setRoot(this); 130 loader.setLocation(layoutURL); 131 final Parent p = (Parent) loader.load(is); 132 assert p == this; 133 } catch (IOException x) { 134 throw new RuntimeException(x); 135 } 136 137 lightLabel.setText(label); 138 lightChoiceBox.getItems().addAll(LightsEnum.values()); 139 140 setValue(initValue); 141 if (initValue == null) { 142 lightChoiceBox.setValue(LightsEnum.NONE); 143 } else if (initValue instanceof Distant) { 144 lightChoiceBox.setValue(LightsEnum.DISTANT); 145 } else if (initValue instanceof Point) { 146 lightChoiceBox.setValue(LightsEnum.POINT); 147 } else { 148 assert initValue instanceof Spot; 149 lightChoiceBox.setValue(LightsEnum.SPOT); 150 } 151 152 lightChoiceBox.getSelectionModel().selectedItemProperty().addListener((ChangeListener<LightsEnum>) (ov, oldValue, newValue) -> { 153 final Light light; 154 switch (newValue) { 155 case DISTANT: 156 light = defaultDistant; 157 break; 158 case POINT: 159 light = defaultPoint; 160 break; 161 case SPOT: 162 light = defaultSpot; 163 break; 164 case NONE: 165 light = null; 166 break; 167 default: 168 light = null; 169 assert false; 170 } 171 // First update the model with new light value 172 setValue(light); 173 // Then update the UI 174 updateLightPropertiesUI(); 175 // Then notify the controller a change occured 176 effectPickerController.incrementRevision(); 177 }); 178 179 lightChoiceBox.addEventHandler(ActionEvent.ACTION, (Event event) -> { 180 event.consume(); 181 }); 182 183 updateLightPropertiesUI(); 184 } 185 186 private void updateLightPropertiesUI() { 187 lightProperties.getChildren().clear(); 188 189 // Add specific properties 190 if (getValue() == null) { 191 // No property to add 192 } else { 193 // Add common color property 194 lightProperties.getChildren().add(getColorPicker()); 195 colorPicker.setPaintProperty(getValue().getColor()); 196 197 if (getValue() instanceof Distant) { 198 final Distant distant = (Distant) getValue(); 199 200 final SliderControl azimuthEditor = new SliderControl( 201 effectPickerController, "azimuth", 0, 360.0, distant.getAzimuth(), 1.0, false); //NOI18N 202 distant.azimuthProperty().bind(azimuthEditor.valueProperty()); 203 lightProperties.getChildren().add(azimuthEditor); 204 205 final SliderControl elevationEditor = new SliderControl( 206 effectPickerController, "elevation", 0, 360.0, distant.getElevation(), 1.0, false); //NOI18N 207 distant.elevationProperty().bind(elevationEditor.valueProperty()); 208 lightProperties.getChildren().add(elevationEditor); 209 210 } else { 211 assert getValue() instanceof Point; 212 final Point point = (Point) getValue(); 213 214 final DoubleTextFieldControl xEditor = new DoubleTextFieldControl( 215 effectPickerController, "x", -10.0, 10.0, point.getX(), 1.0); //NOI18N 216 point.xProperty().bind(xEditor.valueProperty()); 217 lightProperties.getChildren().add(xEditor); 218 219 final DoubleTextFieldControl yEditor = new DoubleTextFieldControl( 220 effectPickerController, "y", -10.0, 10.0, point.getY(), 1.0); //NOI18N 221 point.yProperty().bind(yEditor.valueProperty()); 222 lightProperties.getChildren().add(yEditor); 223 224 final DoubleTextFieldControl zEditor = new DoubleTextFieldControl( 225 effectPickerController, "z", -10.0, 10.0, point.getY(), 1.0); //NOI18N 226 point.zProperty().bind(zEditor.valueProperty()); 227 lightProperties.getChildren().add(zEditor); 228 229 if (point instanceof Spot) { 230 final Spot spot = (Spot) getValue(); 231 232 final DoubleTextFieldControl pointsAtXEditor = new DoubleTextFieldControl( 233 effectPickerController, "pointsAtX", -10.0, 10.0, spot.getPointsAtX(), 1.0); //NOI18N 234 spot.pointsAtXProperty().bind(pointsAtXEditor.valueProperty()); 235 lightProperties.getChildren().add(pointsAtXEditor); 236 237 final DoubleTextFieldControl pointsAtYEditor = new DoubleTextFieldControl( 238 effectPickerController, "pointsAtY", -10.0, 10.0, spot.getPointsAtY(), 1.0); //NOI18N 239 spot.pointsAtYProperty().bind(pointsAtYEditor.valueProperty()); 240 lightProperties.getChildren().add(pointsAtYEditor); 241 242 final DoubleTextFieldControl pointsAtZEditor = new DoubleTextFieldControl( 243 effectPickerController, "pointsAtZ", -10.0, 10.0, spot.getPointsAtZ(), 1.0); //NOI18N 244 spot.pointsAtZProperty().bind(pointsAtZEditor.valueProperty()); 245 lightProperties.getChildren().add(pointsAtZEditor); 246 247 final SliderControl specularExponentEditor = new SliderControl( 248 effectPickerController, "specularExponent", 0, 4.0, spot.getSpecularExponent(), 1.0, false); //NOI18N 249 spot.specularExponentProperty().bind(specularExponentEditor.valueProperty()); 250 lightProperties.getChildren().add(specularExponentEditor); 251 252 } 253 } 254 } 255 } 256 257 private PaintPicker getColorPicker() { 258 if (colorPicker == null) { 259 colorPicker = new PaintPicker(effectPickerController.getPaintPickerDelegate(), PaintPicker.Mode.COLOR); 260 colorPicker.paintProperty().addListener((ChangeListener<Paint>) (ov, oldValue, newValue) -> { 261 assert newValue instanceof Color; 262 final Color color = (Color) newValue; 263 getValue().setColor(color); 264 // Then notify the controller a change occured 265 effectPickerController.incrementRevision(); 266 }); 267 colorPicker.liveUpdateProperty().addListener((ChangeListener<Boolean>) (ov, oldValue, newValue) -> setLiveUpdate(newValue)); 268 } 269 return colorPicker; 270 } 271 }