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.paintpicker.slider; 33 34 import com.oracle.javafx.scenebuilder.kit.util.control.paintpicker.gradientpicker.GradientPicker; 35 36 import java.io.IOException; 37 import java.util.logging.Level; 38 import java.util.logging.Logger; 39 40 import javafx.beans.value.ChangeListener; 41 import javafx.event.ActionEvent; 42 import javafx.fxml.FXML; 43 import javafx.fxml.FXMLLoader; 44 import javafx.scene.control.Slider; 45 import javafx.scene.control.Label; 46 import javafx.scene.control.TextField; 47 import javafx.scene.input.KeyEvent; 48 import javafx.scene.layout.GridPane; 49 50 public class SliderControl extends GridPane { 51 52 @FXML 53 private Slider slider_slider; 54 @FXML 55 private Label slider_label; 56 @FXML 57 private TextField slider_textfield; 58 private final int roundingFactor = 100; // 2 decimals rounding 59 60 public SliderControl(String text, double min, double max, double initVal) { 61 initialize(text, min, max, initVal); 62 } 63 64 public final Slider getSlider() { 65 return slider_slider; 66 } 67 68 /** 69 * Private 70 */ 71 private void initialize(String text, double min, double max, double initVal) { 72 73 final FXMLLoader loader = new FXMLLoader(); 74 loader.setLocation(SliderControl.class.getResource("SliderControl.fxml")); //NOI18N 75 loader.setController(this); 76 loader.setRoot(this); 77 try { 78 loader.load(); 79 } catch (IOException ex) { 80 Logger.getLogger(GradientPicker.class.getName()).log(Level.SEVERE, null, ex); 81 } 82 83 assert slider_label != null; 84 assert slider_slider != null; 85 assert slider_textfield != null; 86 87 slider_label.setText(text); 88 slider_slider.setMin(min); 89 slider_slider.setMax(max); 90 slider_slider.setValue(initVal); 91 slider_textfield.setText(Double.toString(initVal)); 92 93 slider_slider.valueProperty().addListener((ChangeListener<Number>) (ov, oldValue, newValue) -> { 94 double rounded = round(newValue.doubleValue(), roundingFactor); 95 slider_textfield.setText(Double.toString(rounded)); 96 }); 97 } 98 99 @FXML 100 void sliderAction(ActionEvent event) { 101 double value = Double.valueOf(slider_textfield.getText()); 102 double rounded = round(value, roundingFactor); 103 slider_slider.setValue(rounded); 104 if (rounded > slider_slider.getMax()) { 105 rounded = slider_slider.getMax(); 106 slider_textfield.setText(Double.toString(rounded)); 107 } 108 if (rounded < slider_slider.getMin()) { 109 rounded = slider_slider.getMin(); 110 slider_textfield.setText(Double.toString(rounded)); 111 } 112 slider_textfield.selectAll(); 113 event.consume(); 114 } 115 116 @FXML 117 void sliderKeyPressed(KeyEvent e) { 118 switch (e.getCode()) { 119 case UP: 120 incOrDecFieldValue(e, 0.1); 121 break; 122 case DOWN: 123 incOrDecFieldValue(e, -0.1); 124 break; 125 default: 126 break; 127 } 128 } 129 130 private void incOrDecFieldValue(KeyEvent e, double x) { 131 132 if (!(e.getSource() instanceof TextField)) { 133 return; // check it's a textField 134 } // increment or decrement the value 135 final TextField tf = (TextField) e.getSource(); 136 final Double newValue = Double.valueOf(tf.getText()) + x; 137 double rounded = round(newValue, roundingFactor); 138 slider_slider.setValue(rounded); 139 tf.setText(Double.toString(newValue)); 140 // Avoid using runLater 141 // This should be done somewhere else (need to investigate) 142 // Platform.runLater(new Runnable() { 143 // @Override 144 // public void run() { 145 // // position caret after new value for easy editing 146 // tf.positionCaret(tf.getText().length()); 147 // } 148 // }); 149 } 150 151 private double round(double value, int roundingFactor) { 152 double doubleRounded = Math.round(value * roundingFactor); 153 return doubleRounded / roundingFactor; 154 } 155 }