1 /*
   2  * Copyright (c) 2012, 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;
  33 
  34 import com.oracle.javafx.scenebuilder.kit.util.control.effectpicker.editors.CheckBoxControl;
  35 import com.oracle.javafx.scenebuilder.kit.util.control.effectpicker.editors.EnumControl;
  36 import com.oracle.javafx.scenebuilder.kit.util.control.effectpicker.editors.ImageControl;
  37 import com.oracle.javafx.scenebuilder.kit.util.control.effectpicker.editors.DoubleTextFieldControl;
  38 import com.oracle.javafx.scenebuilder.kit.util.control.effectpicker.editors.LightControl;
  39 import com.oracle.javafx.scenebuilder.kit.util.control.effectpicker.editors.SliderControl;
  40 import com.oracle.javafx.scenebuilder.kit.util.control.paintpicker.PaintPicker;
  41 import com.oracle.javafx.scenebuilder.kit.util.control.paintpicker.PaintPicker.Mode;
  42 import java.net.URL;
  43 import javafx.beans.property.BooleanProperty;
  44 import javafx.beans.property.ObjectProperty;
  45 import javafx.beans.property.ReadOnlyIntegerProperty;
  46 import javafx.beans.property.SimpleBooleanProperty;
  47 import javafx.beans.property.SimpleIntegerProperty;
  48 import javafx.beans.property.SimpleObjectProperty;
  49 import javafx.beans.value.ChangeListener;
  50 import javafx.beans.value.ObservableValue;
  51 import javafx.fxml.FXML;
  52 import javafx.scene.control.Slider;
  53 import javafx.scene.control.ToggleButton;
  54 import javafx.scene.control.ToggleGroup;
  55 import javafx.scene.effect.Blend;
  56 import javafx.scene.effect.BlendMode;
  57 import javafx.scene.effect.Bloom;
  58 import javafx.scene.effect.BlurType;
  59 import javafx.scene.effect.BoxBlur;
  60 import javafx.scene.effect.ColorAdjust;
  61 import javafx.scene.effect.ColorInput;
  62 import javafx.scene.effect.DisplacementMap;
  63 import javafx.scene.effect.DropShadow;
  64 import javafx.scene.effect.Effect;
  65 import javafx.scene.effect.GaussianBlur;
  66 import javafx.scene.effect.Glow;
  67 import javafx.scene.effect.ImageInput;
  68 import javafx.scene.effect.InnerShadow;
  69 import javafx.scene.effect.Lighting;
  70 import javafx.scene.effect.MotionBlur;
  71 import javafx.scene.effect.PerspectiveTransform;
  72 import javafx.scene.effect.Reflection;
  73 import javafx.scene.effect.SepiaTone;
  74 import javafx.scene.effect.Shadow;
  75 import javafx.scene.image.Image;
  76 import javafx.scene.image.ImageView;
  77 import javafx.scene.layout.HBox;
  78 import javafx.scene.layout.VBox;
  79 import javafx.scene.paint.Color;
  80 import javafx.scene.paint.Paint;
  81 
  82 /**
  83  * Controller class for the effects editor.
  84  */
  85 public class EffectPickerController {
  86 
  87     @FXML
  88     private VBox root_vbox;
  89     @FXML
  90     private VBox props_vbox;
  91     @FXML
  92     private HBox effects_path_hbox;
  93 
  94     private final ToggleGroup effectToggleGroup = new ToggleGroup();
  95     private final Image selectionChevronImage;
  96     private EffectPicker.Delegate effectPickerDelegate;
  97     private PaintPicker.Delegate paintPickerDelegate;
  98 
  99     private final ObjectProperty<Effect> rootEffect = new SimpleObjectProperty<>();
 100     // The revision property is used when a change occurs on the root effect inputs
 101     private final SimpleIntegerProperty revision = new SimpleIntegerProperty();
 102     private final BooleanProperty liveUpdate = new SimpleBooleanProperty();
 103 
 104     public EffectPickerController() {
 105         // Initialize selection chevron image
 106         final URL selectionChevronURL = EffectPickerController.class.getResource("images/selection-chevron.png"); //NOI18N
 107         assert selectionChevronURL != null;
 108         selectionChevronImage = new Image(selectionChevronURL.toExternalForm());
 109     }
 110 
 111     public final ObjectProperty<Effect> rootEffectProperty() {
 112         return rootEffect;
 113     }
 114 
 115     public final Effect getRootEffectProperty() {
 116         return rootEffect.get();
 117     }
 118 
 119     public final void setRootEffectProperty(Effect value) {
 120         rootEffect.setValue(value);
 121     }
 122 
 123     public ReadOnlyIntegerProperty revisionProperty() {
 124         return revision;
 125     }
 126 
 127     public final BooleanProperty liveUpdateProperty() {
 128         return liveUpdate;
 129     }
 130 
 131     public boolean isLiveUpdate() {
 132         return liveUpdate.get();
 133     }
 134 
 135     public void setLiveUpdate(boolean value) {
 136         liveUpdate.setValue(value);
 137     }
 138 
 139     public EffectPicker.Delegate getEffectPickerDelegate() {
 140         return effectPickerDelegate;
 141     }
 142 
 143     void setEffectPickerDelegate(EffectPicker.Delegate delegate) {
 144         this.effectPickerDelegate = delegate;
 145     }
 146 
 147     public PaintPicker.Delegate getPaintPickerDelegate() {
 148         return paintPickerDelegate;
 149     }
 150 
 151     void setPaintPickerDelegate(PaintPicker.Delegate delegate) {
 152         this.paintPickerDelegate = delegate;
 153     }
 154 
 155     /**
 156      * Update the effect path items starting from the root effect path item.
 157      */
 158     public void updateUI() {
 159         effects_path_hbox.getChildren().clear();
 160         if (getRootEffectProperty() != null) {
 161             final EffectPathItem rootEffectPathItem = makeEffectPathItem(getRootEffectProperty(), null);
 162             assert rootEffectPathItem != null;
 163             EffectPathItem epi = rootEffectPathItem;
 164             while (epi != null) {
 165                 effects_path_hbox.getChildren().add(epi);
 166                 if (epi.getSelectedInputPathItem() != null) {
 167                     final ImageView img = new ImageView(selectionChevronImage);
 168                     effects_path_hbox.getChildren().add(img);
 169                     epi = epi.getSelectedInputPathItem();
 170                 } else {
 171                     epi = null;
 172                 }
 173             }
 174             selectEffectPathItem(rootEffectPathItem);
 175         }
 176     }
 177 
 178     /**
 179      * Update the effect path items starting from the specified effect path item.
 180      *
 181      * @param effectPathItem
 182      */
 183     public void updateUI(EffectPathItem effectPathItem) {
 184         assert effectPathItem != null;
 185         int index = effects_path_hbox.getChildren().indexOf(effectPathItem);
 186         // Remove sub items if any
 187         if (index + 1 < effects_path_hbox.getChildren().size()) {
 188             effects_path_hbox.getChildren().remove(index + 1, effects_path_hbox.getChildren().size());
 189         }
 190         // Add new sub items if any
 191         EffectPathItem epi = effectPathItem.getSelectedInputPathItem();
 192         while (epi != null) {
 193             effects_path_hbox.getChildren().add(epi);
 194             if (epi.getSelectedInputPathItem() != null) {
 195                 final ImageView img = new ImageView(selectionChevronImage);
 196                 effects_path_hbox.getChildren().add(img);
 197                 epi = epi.getSelectedInputPathItem();
 198             } else {
 199                 epi = null;
 200             }
 201         }
 202     }
 203 
 204     public ToggleGroup getEffectToggleGroup() {
 205         return effectToggleGroup;
 206     }
 207 
 208     public String getEffectPath() {
 209         final EffectPathItem rootEffectPathItem = makeEffectPathItem(getRootEffectProperty(), null);
 210         if (rootEffectPathItem == null) {
 211             return "+"; //NOI18N
 212         } else {
 213             final StringBuilder sb = new StringBuilder();
 214             EffectPathItem epi = rootEffectPathItem;
 215             while (epi != null) {
 216                 sb.append(epi.getSimpleName());
 217                 if (epi.getSelectedInputPathItem() != null) {
 218                     sb.append(", "); //NOI18N
 219                     epi = epi.getSelectedInputPathItem();
 220                 } else {
 221                     epi = null;
 222                 }
 223             }
 224             return sb.toString();
 225         }
 226     }
 227 
 228     @FXML
 229     void initialize() {
 230         assert root_vbox != null;
 231         assert effects_path_hbox != null;
 232         assert props_vbox != null;
 233     }
 234 
 235     public void incrementRevision() {
 236         revision.set(revision.get() + 1);
 237     }
 238 
 239     private EffectPathItem makeEffectPathItem(Effect effect, EffectPathItem hostPathItem) {
 240         final EffectPathItem epi;
 241         if (effect == null) {
 242             return null;
 243         }
 244         if (effect instanceof Blend) {
 245             epi = makeBlendPathItem(effect, hostPathItem);
 246         } else if (effect instanceof ColorInput) {
 247             epi = makeColorInputPathItem(effect, hostPathItem);
 248         } else if (effect instanceof ImageInput) {
 249             epi = makeImageInputPathItem(effect, hostPathItem);
 250         } else if (effect instanceof Lighting) {
 251             epi = makeLightingPathItem(effect, hostPathItem);
 252         } else {
 253             epi = makeSingleInputPathItem(effect, hostPathItem);
 254         }
 255         return epi;
 256     }
 257 
 258     private EffectPathItem makeBlendPathItem(Effect effect, EffectPathItem hostPathItem) {
 259         assert effect != null;
 260         final BlendPathItem epi = new BlendPathItem(this, effect, hostPathItem);
 261         final Effect topInput = epi.getTopInput();
 262         final EffectPathItem topInputPathItem
 263                 = topInput == null ? null : makeEffectPathItem(topInput, epi);
 264         epi.setTopInputPathItem(topInputPathItem);
 265         final Effect bottomInput = epi.getBottomInput();
 266         final EffectPathItem bottomInputPathItem
 267                 = bottomInput == null ? null : makeEffectPathItem(bottomInput, epi);
 268         epi.setBottomInputPathItem(bottomInputPathItem);
 269         return epi;
 270     }
 271 
 272     private EffectPathItem makeColorInputPathItem(Effect effect, EffectPathItem hostPathItem) {
 273         assert effect != null;
 274         final ColorInputPathItem epi = new ColorInputPathItem(this, effect, hostPathItem);
 275         return epi;
 276     }
 277 
 278     private EffectPathItem makeImageInputPathItem(Effect effect, EffectPathItem hostPathItem) {
 279         assert effect != null;
 280         final ImageInputPathItem epi = new ImageInputPathItem(this, effect, hostPathItem);
 281         return epi;
 282     }
 283 
 284     private EffectPathItem makeLightingPathItem(Effect effect, EffectPathItem hostPathItem) {
 285         assert effect != null;
 286         final LightingPathItem epi = new LightingPathItem(this, effect, hostPathItem);
 287         final Effect bumpInput = epi.getBumpInput();
 288         final EffectPathItem bumpInputPathItem
 289                 = bumpInput == null ? null : makeEffectPathItem(bumpInput, epi);
 290         epi.setBumpInputPathItem(bumpInputPathItem);
 291         final Effect contentInput = epi.getContentInput();
 292         final EffectPathItem contentInputPathItem
 293                 = contentInput == null ? null : makeEffectPathItem(contentInput, epi);
 294         epi.setContentInputPathItem(contentInputPathItem);
 295         return epi;
 296     }
 297 
 298     private EffectPathItem makeSingleInputPathItem(Effect effect, EffectPathItem hostPathItem) {
 299         assert effect != null;
 300         final SingleInputPathItem epi = new SingleInputPathItem(this, effect, hostPathItem);
 301         final Effect input = epi.getInput();
 302         final EffectPathItem inputPathItem
 303                 = input == null ? null : makeEffectPathItem(input, epi);
 304         epi.setInputPathItem(inputPathItem);
 305         return epi;
 306     }
 307 
 308     public void selectEffectPathItem(EffectPathItem epi) {
 309         assert epi != null;
 310         final ToggleButton tb = epi.getToggleButton();
 311         final Effect effect = epi.getValue();
 312         tb.setSelected(true);
 313         props_vbox.getChildren().clear();
 314         if (effect != null) {
 315             makeEffectUI(effect);
 316         }
 317     }
 318 
 319     ////////////////////////////////////////////////////////////////////////////
 320     //////////////////////////////// Effects UI ////////////////////////////////
 321     ////////////////////////////////////////////////////////////////////////////
 322     private void makeEffectUI(Effect effect) {
 323         if (effect instanceof Blend) {
 324             makeBlendUI(effect);
 325         } else if (effect instanceof Bloom) {
 326             makeBloomUI(effect);
 327         } else if (effect instanceof BoxBlur) {
 328             makeBoxBlurUI(effect);
 329         } else if (effect instanceof ColorAdjust) {
 330             makeColorAdjustUI(effect);
 331         } else if (effect instanceof ColorInput) {
 332             makeColorInputUI(effect);
 333         } else if (effect instanceof DisplacementMap) {
 334             makeDisplacementMapUI(effect);
 335         } else if (effect instanceof DropShadow) {
 336             makeDropShadowUI(effect);
 337         } else if (effect instanceof GaussianBlur) {
 338             makeGaussianBlurUI(effect);
 339         } else if (effect instanceof Glow) {
 340             makeGlowUI(effect);
 341         } else if (effect instanceof ImageInput) {
 342             makeImageInputUI(effect);
 343         } else if (effect instanceof InnerShadow) {
 344             makeInnerShadowUI(effect);
 345         } else if (effect instanceof Lighting) {
 346             makeLightingUI(effect);
 347         } else if (effect instanceof MotionBlur) {
 348             makeMotionBlurUI(effect);
 349         } else if (effect instanceof PerspectiveTransform) {
 350             makePerspectiveTransformUI(effect);
 351         } else if (effect instanceof Reflection) {
 352             makeReflectionUI(effect);
 353         } else if (effect instanceof SepiaTone) {
 354             makeSepiaToneUI(effect);
 355         } else {
 356             assert effect instanceof Shadow;
 357             makeShadowUI(effect);
 358         }
 359     }
 360 
 361     private void makeBlendUI(Effect effect) {
 362         assert effect instanceof Blend;
 363         final Blend blend = (Blend) effect;
 364         final VBox vBox = new VBox(8.0);
 365 
 366         final EnumControl<BlendMode> modeEditor = new EnumControl<>(
 367                 this, "mode", BlendMode.values(), blend.getMode()); //NOI18N
 368         blend.modeProperty().bind(modeEditor.valueProperty());
 369         vBox.getChildren().add(modeEditor);
 370 
 371         final SliderControl opacityEditor = new SliderControl(
 372                 this, "opacity", 0, 1.0, blend.getOpacity(), 0.1, false); //NOI18N
 373         blend.opacityProperty().bind(opacityEditor.valueProperty());
 374         vBox.getChildren().add(opacityEditor);
 375 
 376         props_vbox.getChildren().add(vBox);
 377     }
 378 
 379     private void makeBloomUI(Effect effect) {
 380         assert effect instanceof Bloom;
 381         final Bloom bloom = (Bloom) effect;
 382         VBox vBox = new VBox(8.0);
 383 
 384         final SliderControl thresholdEditor = new SliderControl(
 385                 this, "threshold", 0, 1.0, bloom.getThreshold(), 0.1, false); //NOI18N
 386         bloom.thresholdProperty().bind(thresholdEditor.valueProperty());
 387         vBox.getChildren().add(thresholdEditor);
 388 
 389         props_vbox.getChildren().add(vBox);
 390     }
 391 
 392     private void makeBoxBlurUI(Effect effect) {
 393         assert effect instanceof BoxBlur;
 394         final BoxBlur boxBlur = (BoxBlur) effect;
 395         VBox vBox = new VBox(8.0);
 396 
 397         final SliderControl widthEditor = new SliderControl(
 398                 this, "width", 0, 255.0, boxBlur.getWidth(), 1.0, false); //NOI18N
 399         boxBlur.widthProperty().bind(widthEditor.valueProperty());
 400         vBox.getChildren().add(widthEditor);
 401 
 402         final SliderControl heightEditor = new SliderControl(
 403                 this, "height", 0, 255.0, boxBlur.getHeight(), 1.0, false); //NOI18N
 404         boxBlur.heightProperty().bind(heightEditor.valueProperty());
 405         vBox.getChildren().add(heightEditor);
 406 
 407         final SliderControl iterationsEditor = new SliderControl(
 408                 this, "iterations", 0, 3.0, boxBlur.getIterations(), 1.0, true); //NOI18N
 409         final Slider slider = iterationsEditor.getSlider();
 410         slider.setBlockIncrement(1.0);
 411         slider.setMajorTickUnit(1.0);
 412         slider.setMinorTickCount(0);
 413         slider.setSnapToTicks(true);
 414         slider.setShowTickMarks(true);
 415         boxBlur.iterationsProperty().bind(iterationsEditor.valueProperty());
 416         vBox.getChildren().add(iterationsEditor);
 417 
 418         props_vbox.getChildren().add(vBox);
 419     }
 420 
 421     private void makeColorAdjustUI(Effect effect) {
 422         assert effect instanceof ColorAdjust;
 423         final ColorAdjust colorAdjust = (ColorAdjust) effect;
 424         VBox vBox = new VBox(8.0);
 425 
 426         final SliderControl brightnessEditor = new SliderControl(
 427                 this, "brightness", -1.0, 1.0, colorAdjust.getBrightness(), 0.1, false); //NOI18N
 428         colorAdjust.brightnessProperty().bind(brightnessEditor.valueProperty());
 429         vBox.getChildren().add(brightnessEditor);
 430 
 431         final SliderControl contrastEditor = new SliderControl(
 432                 this, "contrast", -1.0, 1.0, colorAdjust.getContrast(), 0.1, false); //NOI18N
 433         colorAdjust.contrastProperty().bind(contrastEditor.valueProperty());
 434         vBox.getChildren().add(contrastEditor);
 435 
 436         final SliderControl hueEditor = new SliderControl(
 437                 this, "hue", -1.0, 1.0, colorAdjust.getHue(), 0.1, false); //NOI18N
 438         colorAdjust.hueProperty().bind(hueEditor.valueProperty());
 439         vBox.getChildren().add(hueEditor);
 440 
 441         final SliderControl saturationEditor = new SliderControl(
 442                 this, "saturation", -1.0, 1.0, colorAdjust.getSaturation(), 0.1, false); //NOI18N
 443         colorAdjust.saturationProperty().bind(saturationEditor.valueProperty());
 444         vBox.getChildren().add(saturationEditor);
 445 
 446         props_vbox.getChildren().add(vBox);
 447     }
 448 
 449     private void makeColorInputUI(Effect effect) {
 450         assert effect instanceof ColorInput;
 451         final ColorInput colorInput = (ColorInput) effect;
 452         VBox vBox = new VBox(8.0);
 453 
 454         final SliderControl widthEditor = new SliderControl(
 455                 this, "width", 0, 255.0, colorInput.getWidth(), 1.0, false); //NOI18N
 456         colorInput.widthProperty().bind(widthEditor.valueProperty());
 457         vBox.getChildren().add(widthEditor);
 458 
 459         final SliderControl heightEditor = new SliderControl(
 460                 this, "height", 0, 255.0, colorInput.getHeight(), 1.0, false); //NOI18N
 461         colorInput.heightProperty().bind(heightEditor.valueProperty());
 462         vBox.getChildren().add(heightEditor);
 463 
 464         final DoubleTextFieldControl xEditor = new DoubleTextFieldControl(
 465                 this, "x", -10.0, 10.0, colorInput.getX(), 1.0); //NOI18N
 466         colorInput.xProperty().bind(xEditor.valueProperty());
 467         vBox.getChildren().add(xEditor);
 468 
 469         final DoubleTextFieldControl yEditor = new DoubleTextFieldControl(
 470                 this, "y", -10.0, 10.0, colorInput.getY(), 1.0); //NOI18N
 471         colorInput.yProperty().bind(yEditor.valueProperty());
 472         vBox.getChildren().add(yEditor);
 473 
 474         final PaintPicker colorPicker = new PaintPicker(paintPickerDelegate);
 475         colorPicker.setPaintProperty(colorInput.getPaint());
 476         colorPicker.paintProperty().addListener(new PaintChangeListener(this, colorInput));
 477         colorPicker.liveUpdateProperty().addListener(new PaintPickerLiveUpdateListener(colorPicker, this));
 478         vBox.getChildren().add(colorPicker);
 479 
 480         props_vbox.getChildren().add(vBox);
 481     }
 482 
 483     private void makeDisplacementMapUI(Effect effect) {
 484         assert effect instanceof DisplacementMap;
 485         final DisplacementMap displacementMap = (DisplacementMap) effect;
 486         VBox vBox = new VBox(8.0);
 487 
 488         final DoubleTextFieldControl offsetXEditor = new DoubleTextFieldControl(
 489                 this, "offsetX", -10.0, 10.0, displacementMap.getOffsetX(), 1.0); //NOI18N
 490         displacementMap.offsetXProperty().bind(offsetXEditor.valueProperty());
 491         vBox.getChildren().add(offsetXEditor);
 492 
 493         final DoubleTextFieldControl offsetYEditor = new DoubleTextFieldControl(
 494                 this, "offsetY", -10.0, 10.0, displacementMap.getOffsetY(), 1.0); //NOI18N
 495         displacementMap.offsetYProperty().bind(offsetYEditor.valueProperty());
 496         vBox.getChildren().add(offsetYEditor);
 497 
 498         final DoubleTextFieldControl scaleXEditor = new DoubleTextFieldControl(
 499                 this, "scaleX", -10.0, 10.0, displacementMap.getScaleX(), 1.0); //NOI18N
 500         displacementMap.scaleXProperty().bind(scaleXEditor.valueProperty());
 501         vBox.getChildren().add(scaleXEditor);
 502 
 503         final DoubleTextFieldControl scaleYEditor = new DoubleTextFieldControl(
 504                 this, "scaleY", -10.0, 10.0, displacementMap.getScaleY(), 1.0); //NOI18N
 505         displacementMap.scaleYProperty().bind(scaleYEditor.valueProperty());
 506         vBox.getChildren().add(scaleYEditor);
 507 
 508         final CheckBoxControl wrapEditor = new CheckBoxControl(
 509                 this, "wrap", displacementMap.isWrap()); //NOI18N
 510         displacementMap.wrapProperty().bind(wrapEditor.valueProperty());
 511         vBox.getChildren().add(wrapEditor);
 512 
 513         props_vbox.getChildren().add(vBox);
 514     }
 515 
 516     private void makeDropShadowUI(Effect effect) {
 517         assert effect instanceof DropShadow;
 518         final DropShadow dropShadow = (DropShadow) effect;
 519         VBox vBox = new VBox(8.0);
 520 
 521         final EnumControl<BlurType> blurTypeEditor = new EnumControl<>(
 522                 this, "blurType", BlurType.values(), dropShadow.getBlurType()); //NOI18N
 523         dropShadow.blurTypeProperty().bind(blurTypeEditor.valueProperty());
 524         vBox.getChildren().add(blurTypeEditor);
 525 
 526         final SliderControl widthEditor = new SliderControl(
 527                 this, "width", 0, 255.0, dropShadow.getWidth(), 1.0, false); //NOI18N
 528         dropShadow.widthProperty().bind(widthEditor.valueProperty());
 529         vBox.getChildren().add(widthEditor);
 530 
 531         final SliderControl heightEditor = new SliderControl(
 532                 this, "height", 0, 255.0, dropShadow.getHeight(), 1.0, false); //NOI18N
 533         dropShadow.heightProperty().bind(heightEditor.valueProperty());
 534         vBox.getChildren().add(heightEditor);
 535 
 536         // setting radius equivalent to setting both width and height attributes to value of (2 * radius + 1)
 537         final SliderControl radiusEditor = new SliderControl(
 538                 this, "radius", 0, 127.0, dropShadow.getRadius(), 1.0, false); //NOI18N
 539         dropShadow.radiusProperty().bind(radiusEditor.valueProperty());
 540         vBox.getChildren().add(radiusEditor);
 541 
 542         final DoubleTextFieldControl offsetXEditor = new DoubleTextFieldControl(
 543                 this, "offsetX", -10.0, 10.0, dropShadow.getOffsetX(), 1.0); //NOI18N
 544         dropShadow.offsetXProperty().bind(offsetXEditor.valueProperty());
 545         vBox.getChildren().add(offsetXEditor);
 546 
 547         final DoubleTextFieldControl offsetYEditor = new DoubleTextFieldControl(
 548                 this, "offsetY", -10.0, 10.0, dropShadow.getOffsetY(), 1.0); //NOI18N
 549         dropShadow.offsetYProperty().bind(offsetYEditor.valueProperty());
 550         vBox.getChildren().add(offsetYEditor);
 551 
 552         final SliderControl spreadEditor = new SliderControl(
 553                 this, "spread", 0, 1.0, dropShadow.getSpread(), 0.1, false); //NOI18N
 554         dropShadow.spreadProperty().bind(spreadEditor.valueProperty());
 555         vBox.getChildren().add(spreadEditor);
 556 
 557         final PaintPicker colorPicker = new PaintPicker(paintPickerDelegate, Mode.COLOR);
 558         colorPicker.setPaintProperty(dropShadow.getColor());
 559         colorPicker.paintProperty().addListener(new ColorChangeListener(this, dropShadow));
 560         colorPicker.liveUpdateProperty().addListener(new PaintPickerLiveUpdateListener(colorPicker, this));
 561         vBox.getChildren().add(colorPicker);
 562 
 563         props_vbox.getChildren().add(vBox);
 564     }
 565 
 566     private void makeGaussianBlurUI(Effect effect) {
 567         assert effect instanceof GaussianBlur;
 568         final GaussianBlur gaussianBlur = (GaussianBlur) effect;
 569         VBox vBox = new VBox(8.0);
 570 
 571         final SliderControl radiusEditor = new SliderControl(
 572                 this, "radius", 0, 63.0, gaussianBlur.getRadius(), 0.1, false); //NOI18N
 573         gaussianBlur.radiusProperty().bind(radiusEditor.valueProperty());
 574         vBox.getChildren().add(radiusEditor);
 575 
 576         props_vbox.getChildren().add(vBox);
 577     }
 578 
 579     private void makeGlowUI(Effect effect) {
 580         assert effect instanceof Glow;
 581         final Glow glow = (Glow) effect;
 582         VBox vBox = new VBox(8.0);
 583 
 584         final SliderControl levelEditor = new SliderControl(
 585                 this, "level", 0, 1.0, glow.getLevel(), 0.1, false); //NOI18N
 586         glow.levelProperty().bind(levelEditor.valueProperty());
 587         vBox.getChildren().add(levelEditor);
 588 
 589         props_vbox.getChildren().add(vBox);
 590     }
 591 
 592     private void makeImageInputUI(Effect effect) {
 593         assert effect instanceof ImageInput;
 594         final ImageInput imageInput = (ImageInput) effect;
 595         VBox vBox = new VBox(8.0);
 596 
 597         final DoubleTextFieldControl xEditor = new DoubleTextFieldControl(
 598                 this, "x", -10.0, 10.0, imageInput.getX(), 1.0); //NOI18N
 599         imageInput.xProperty().bind(xEditor.valueProperty());
 600         vBox.getChildren().add(xEditor);
 601 
 602         final DoubleTextFieldControl yEditor = new DoubleTextFieldControl(
 603                 this, "y", -10.0, 10.0, imageInput.getY(), 1.0); //NOI18N
 604         imageInput.yProperty().bind(yEditor.valueProperty());
 605         vBox.getChildren().add(yEditor);
 606 
 607         final ImageControl imageEditor = new ImageControl(
 608                 this, "source", imageInput.getSource()); //NOI18N
 609         imageInput.sourceProperty().bind(imageEditor.valueProperty());
 610         vBox.getChildren().add(imageEditor);
 611 
 612         props_vbox.getChildren().add(vBox);
 613     }
 614 
 615     private void makeInnerShadowUI(Effect effect) {
 616         assert effect instanceof InnerShadow;
 617         final InnerShadow innerShadow = (InnerShadow) effect;
 618         VBox vBox = new VBox(8.0);
 619 
 620         final EnumControl<BlurType> blurTypeEditor = new EnumControl<>(
 621                 this, "blurType", BlurType.values(), innerShadow.getBlurType()); //NOI18N
 622         innerShadow.blurTypeProperty().bind(blurTypeEditor.valueProperty());
 623         vBox.getChildren().add(blurTypeEditor);
 624 
 625         final SliderControl chokeEditor = new SliderControl(
 626                 this, "choke", 0, 1.0, innerShadow.getChoke(), 0.1, false); //NOI18N
 627         innerShadow.chokeProperty().bind(chokeEditor.valueProperty());
 628         vBox.getChildren().add(chokeEditor);
 629 
 630         final SliderControl widthEditor = new SliderControl(
 631                 this, "width", 0, 255.0, innerShadow.getWidth(), 1.0, false); //NOI18N
 632         innerShadow.widthProperty().bind(widthEditor.valueProperty());
 633         vBox.getChildren().add(widthEditor);
 634 
 635         final SliderControl heightEditor = new SliderControl(
 636                 this, "height", 0, 255.0, innerShadow.getHeight(), 1.0, false); //NOI18N
 637         innerShadow.heightProperty().bind(heightEditor.valueProperty());
 638         vBox.getChildren().add(heightEditor);
 639 
 640         // setting radius equivalent to setting both width and height attributes to value of (2 * radius + 1)
 641         final SliderControl radiusEditor = new SliderControl(
 642                 this, "radius", 0, 127.0, innerShadow.getRadius(), 1.0, false); //NOI18N
 643         innerShadow.radiusProperty().bind(radiusEditor.valueProperty());
 644         vBox.getChildren().add(radiusEditor);
 645 
 646         final DoubleTextFieldControl offsetXEditor = new DoubleTextFieldControl(
 647                 this, "offsetX", -10.0, 10.0, innerShadow.getOffsetX(), 1.0); //NOI18N
 648         innerShadow.offsetXProperty().bind(offsetXEditor.valueProperty());
 649         vBox.getChildren().add(offsetXEditor);
 650 
 651         final DoubleTextFieldControl offsetYEditor = new DoubleTextFieldControl(
 652                 this, "offsetY", -10.0, 10.0, innerShadow.getOffsetY(), 1.0); //NOI18N
 653         innerShadow.offsetYProperty().bind(offsetYEditor.valueProperty());
 654         vBox.getChildren().add(offsetYEditor);
 655 
 656         final PaintPicker colorPicker = new PaintPicker(paintPickerDelegate, Mode.COLOR);
 657         colorPicker.setPaintProperty(innerShadow.getColor());
 658         colorPicker.paintProperty().addListener(new ColorChangeListener(this, innerShadow));
 659         colorPicker.liveUpdateProperty().addListener(new PaintPickerLiveUpdateListener(colorPicker, this));
 660         vBox.getChildren().add(colorPicker);
 661 
 662         props_vbox.getChildren().add(vBox);
 663     }
 664 
 665     private void makeLightingUI(Effect effect) {
 666         assert effect instanceof Lighting;
 667         final Lighting lighting = (Lighting) effect;
 668         VBox vBox = new VBox(8.0);
 669 
 670         final SliderControl diffuseConstantEditor = new SliderControl(
 671                 this, "diffuseConstant", 0, 2.0, lighting.getDiffuseConstant(), 1.0, false); //NOI18N
 672         lighting.diffuseConstantProperty().bind(diffuseConstantEditor.valueProperty());
 673         vBox.getChildren().add(diffuseConstantEditor);
 674 
 675         final SliderControl specularConstantEditor = new SliderControl(
 676                 this, "specularConstant", 0, 2.0, lighting.getSpecularConstant(), 1.0, false); //NOI18N
 677         lighting.specularConstantProperty().bind(specularConstantEditor.valueProperty());
 678         vBox.getChildren().add(specularConstantEditor);
 679 
 680         final SliderControl specularExponentEditor = new SliderControl(
 681                 this, "specularExponent", 0, 40.0, lighting.getSpecularExponent(), 1.0, false); //NOI18N
 682         lighting.specularExponentProperty().bind(specularExponentEditor.valueProperty());
 683         vBox.getChildren().add(specularExponentEditor);
 684 
 685         final SliderControl surfaceScaleEditor = new SliderControl(
 686                 this, "surfaceScale", 0, 10.0, lighting.getSurfaceScale(), 1.0, false); //NOI18N
 687         lighting.surfaceScaleProperty().bind(surfaceScaleEditor.valueProperty());
 688         vBox.getChildren().add(surfaceScaleEditor);
 689 
 690         final LightControl lightControl = new LightControl(
 691                 this, "light", lighting.getLight()); //NOI18N
 692         lighting.lightProperty().bind(lightControl.valueProperty());
 693         lightControl.liveUpdateProperty().addListener(new LightControlLiveUpdateListener(lightControl, this));
 694         vBox.getChildren().add(lightControl);
 695 
 696         props_vbox.getChildren().add(vBox);
 697     }
 698 
 699     private void makeMotionBlurUI(Effect effect) {
 700         assert effect instanceof MotionBlur;
 701         final MotionBlur motionBlur = (MotionBlur) effect;
 702         VBox vBox = new VBox(8.0);
 703 
 704         final SliderControl angleEditor = new SliderControl(
 705                 this, "angle", 0, 360.0, motionBlur.getAngle(), 1.0, false); //NOI18N
 706         motionBlur.angleProperty().bind(angleEditor.valueProperty());
 707         vBox.getChildren().add(angleEditor);
 708 
 709         final SliderControl radiusEditor = new SliderControl(
 710                 this, "radius", 0, 63.0, motionBlur.getRadius(), 1.0, false); //NOI18N
 711         motionBlur.radiusProperty().bind(radiusEditor.valueProperty());
 712         vBox.getChildren().add(radiusEditor);
 713 
 714         props_vbox.getChildren().add(vBox);
 715     }
 716 
 717     private void makePerspectiveTransformUI(Effect effect) {
 718         assert effect instanceof PerspectiveTransform;
 719         final PerspectiveTransform perspectiveTransform = (PerspectiveTransform) effect;
 720         VBox vBox = new VBox(8.0);
 721 
 722         final DoubleTextFieldControl llxEditor = new DoubleTextFieldControl(
 723                 this, "llx", -10.0, 10.0, perspectiveTransform.getLlx(), 1.0); //NOI18N
 724         perspectiveTransform.llxProperty().bind(llxEditor.valueProperty());
 725         vBox.getChildren().add(llxEditor);
 726 
 727         final DoubleTextFieldControl llyEditor = new DoubleTextFieldControl(
 728                 this, "lly", -10.0, 10.0, perspectiveTransform.getLly(), 1.0); //NOI18N
 729         perspectiveTransform.llyProperty().bind(llyEditor.valueProperty());
 730         vBox.getChildren().add(llyEditor);
 731 
 732         final DoubleTextFieldControl lrxEditor = new DoubleTextFieldControl(
 733                 this, "lrx", -10.0, 10.0, perspectiveTransform.getLrx(), 1.0); //NOI18N
 734         perspectiveTransform.lrxProperty().bind(lrxEditor.valueProperty());
 735         vBox.getChildren().add(lrxEditor);
 736 
 737         final DoubleTextFieldControl lryEditor = new DoubleTextFieldControl(
 738                 this, "lry", -10.0, 10.0, perspectiveTransform.getLry(), 1.0); //NOI18N
 739         perspectiveTransform.lryProperty().bind(lryEditor.valueProperty());
 740         vBox.getChildren().add(lryEditor);
 741 
 742         final DoubleTextFieldControl ulxEditor = new DoubleTextFieldControl(
 743                 this, "ulx", -10.0, 10.0, perspectiveTransform.getUlx(), 1.0); //NOI18N
 744         perspectiveTransform.ulxProperty().bind(ulxEditor.valueProperty());
 745         vBox.getChildren().add(ulxEditor);
 746 
 747         final DoubleTextFieldControl ulyEditor = new DoubleTextFieldControl(
 748                 this, "uly", -10.0, 10.0, perspectiveTransform.getUly(), 1.0); //NOI18N
 749         perspectiveTransform.ulyProperty().bind(ulyEditor.valueProperty());
 750         vBox.getChildren().add(ulyEditor);
 751 
 752         final DoubleTextFieldControl urxEditor = new DoubleTextFieldControl(
 753                 this, "urx", -10.0, 10.0, perspectiveTransform.getUrx(), 1.0); //NOI18N
 754         perspectiveTransform.urxProperty().bind(urxEditor.valueProperty());
 755         vBox.getChildren().add(urxEditor);
 756 
 757         final DoubleTextFieldControl uryEditor = new DoubleTextFieldControl(
 758                 this, "ury", -10.0, 10.0, perspectiveTransform.getUry(), 1.0); //NOI18N
 759         perspectiveTransform.uryProperty().bind(uryEditor.valueProperty());
 760         vBox.getChildren().add(uryEditor);
 761 
 762         props_vbox.getChildren().add(vBox);
 763     }
 764 
 765     private void makeReflectionUI(Effect effect) {
 766         assert effect instanceof Reflection;
 767         final Reflection reflection = (Reflection) effect;
 768         VBox vBox = new VBox(8.0);
 769 
 770         final SliderControl bottomOpacityEditor = new SliderControl(
 771                 this, "bottomOpacity", 0, 1.0, reflection.getBottomOpacity(), 0.1, false); //NOI18N
 772         reflection.bottomOpacityProperty().bind(bottomOpacityEditor.valueProperty());
 773         vBox.getChildren().add(bottomOpacityEditor);
 774 
 775         final SliderControl topOpacityEditor = new SliderControl(
 776                 this, "topOpacity", 0, 1.0, reflection.getTopOpacity(), 0.1, false); //NOI18N
 777         reflection.topOpacityProperty().bind(topOpacityEditor.valueProperty());
 778         vBox.getChildren().add(topOpacityEditor);
 779 
 780         final DoubleTextFieldControl topOffsetEditor = new DoubleTextFieldControl(
 781                 this, "topOffset", -10.0, 10.0, reflection.getTopOffset(), 1.0); //NOI18N
 782         reflection.topOffsetProperty().bind(topOffsetEditor.valueProperty());
 783         vBox.getChildren().add(topOffsetEditor);
 784 
 785         final SliderControl fractionEditor = new SliderControl(
 786                 this, "fraction", 0, 1.0, reflection.getFraction(), 0.1, false); //NOI18N
 787         reflection.fractionProperty().bind(fractionEditor.valueProperty());
 788         vBox.getChildren().add(fractionEditor);
 789 
 790         props_vbox.getChildren().add(vBox);
 791     }
 792 
 793     private void makeSepiaToneUI(Effect effect) {
 794         assert effect instanceof SepiaTone;
 795         final SepiaTone sepiaTone = (SepiaTone) effect;
 796         VBox vBox = new VBox(8.0);
 797 
 798         final SliderControl levelEditor = new SliderControl(
 799                 this, "level", 0, 1.0, sepiaTone.getLevel(), 0.1, false); //NOI18N
 800         sepiaTone.levelProperty().bind(levelEditor.valueProperty());
 801         vBox.getChildren().add(levelEditor);
 802 
 803         props_vbox.getChildren().add(vBox);
 804     }
 805 
 806     private void makeShadowUI(Effect effect) {
 807         assert effect instanceof Shadow;
 808         final Shadow shadow = (Shadow) effect;
 809         VBox vBox = new VBox(8.0);
 810 
 811         final EnumControl<BlurType> blurTypeEditor = new EnumControl<>(
 812                 this, "blurType", BlurType.values(), shadow.getBlurType()); //NOI18N
 813         shadow.blurTypeProperty().bind(blurTypeEditor.valueProperty());
 814         vBox.getChildren().add(blurTypeEditor);
 815 
 816         final SliderControl widthEditor = new SliderControl(
 817                 this, "width", 0, 255.0, shadow.getWidth(), 1.0, false); //NOI18N
 818         shadow.widthProperty().bind(widthEditor.valueProperty());
 819         vBox.getChildren().add(widthEditor);
 820 
 821         final SliderControl heightEditor = new SliderControl(
 822                 this, "height", 0, 255.0, shadow.getHeight(), 1.0, false); //NOI18N
 823         shadow.heightProperty().bind(heightEditor.valueProperty());
 824         vBox.getChildren().add(heightEditor);
 825 
 826         // setting radius equivalent to setting both width and height attributes to value of (2 * radius + 1)
 827         final SliderControl radiusEditor = new SliderControl(
 828                 this, "radius", 0, 127.0, shadow.getRadius(), 1.0, false); //NOI18N
 829         shadow.radiusProperty().bind(radiusEditor.valueProperty());
 830         vBox.getChildren().add(radiusEditor);
 831 
 832         final PaintPicker colorPicker = new PaintPicker(paintPickerDelegate, Mode.COLOR);
 833         colorPicker.setPaintProperty(shadow.getColor());
 834         colorPicker.paintProperty().addListener(new ColorChangeListener(this, shadow));
 835         colorPicker.liveUpdateProperty().addListener(new PaintPickerLiveUpdateListener(colorPicker, this));
 836         vBox.getChildren().add(colorPicker);
 837 
 838         props_vbox.getChildren().add(vBox);
 839     }
 840 
 841     /**
 842      * *************************************************************************
 843      * Static inner class
 844      * *************************************************************************
 845      */
 846     private static class PaintPickerLiveUpdateListener implements ChangeListener<Boolean> {
 847 
 848         private final PaintPicker paintPicker;
 849         private final EffectPickerController effectPickerController;
 850 
 851         public PaintPickerLiveUpdateListener(
 852                 PaintPicker paintPicker,
 853                 EffectPickerController effectPickerController) {
 854             this.paintPicker = paintPicker;
 855             this.effectPickerController = effectPickerController;
 856         }
 857 
 858         @Override
 859         public void changed(ObservableValue<? extends Boolean> ov, Boolean oldValue, Boolean newValue) {
 860             effectPickerController.setLiveUpdate(paintPicker.isLiveUpdate());
 861         }
 862     }
 863 
 864     private static class LightControlLiveUpdateListener implements ChangeListener<Boolean> {
 865 
 866         private final LightControl lightControl;
 867         private final EffectPickerController effectPickerController;
 868 
 869         public LightControlLiveUpdateListener(
 870                 LightControl lightControl,
 871                 EffectPickerController effectPickerController) {
 872             this.lightControl = lightControl;
 873             this.effectPickerController = effectPickerController;
 874         }
 875 
 876         @Override
 877         public void changed(ObservableValue<? extends Boolean> ov, Boolean oldValue, Boolean newValue) {
 878             effectPickerController.setLiveUpdate(lightControl.isLiveUpdate());
 879         }
 880     }
 881 
 882     private static class ColorChangeListener implements ChangeListener<Paint> {
 883 
 884         private final EffectPickerController effectPickerController;
 885         private final Effect effect;
 886 
 887         public ColorChangeListener(EffectPickerController effectPickerController, Effect effect) {
 888             assert effect instanceof DropShadow
 889                     || effect instanceof InnerShadow
 890                     || effect instanceof Shadow;
 891             this.effectPickerController = effectPickerController;
 892             this.effect = effect;
 893         }
 894 
 895         @Override
 896         public void changed(ObservableValue<? extends Paint> ov, Paint oldValue, Paint newValue) {
 897             assert newValue instanceof Color;
 898             final Color color = (Color) newValue;
 899             if (effect instanceof DropShadow) {
 900                 ((DropShadow) effect).setColor(color);
 901             } else if (effect instanceof InnerShadow) {
 902                 ((InnerShadow) effect).setColor(color);
 903             } else {
 904                 assert effect instanceof Shadow;
 905                 ((Shadow) effect).setColor(color);
 906             }
 907             // Then notify the controller a change occured
 908             effectPickerController.incrementRevision();
 909         }
 910     }
 911 
 912     private static class PaintChangeListener implements ChangeListener<Paint> {
 913 
 914         private final EffectPickerController effectPickerController;
 915         private final ColorInput colorInput;
 916 
 917         public PaintChangeListener(EffectPickerController effectPickerController, ColorInput colorInput) {
 918             this.effectPickerController = effectPickerController;
 919             this.colorInput = colorInput;
 920         }
 921 
 922         @Override
 923         public void changed(ObservableValue<? extends Paint> ov, Paint oldValue, Paint newValue) {
 924             colorInput.setPaint(newValue);
 925             // Then notify the controller a change occured
 926             effectPickerController.incrementRevision();
 927         }
 928     }
 929 }