package org.geotoolkit.gui.javafx.util; import java.text.DecimalFormat; import javafx.beans.property.FloatProperty; import javafx.beans.property.SimpleFloatProperty; import javafx.scene.control.SpinnerValueFactory; import javafx.util.StringConverter; import org.apache.sis.util.ObjectConverter; import org.apache.sis.util.ObjectConverters; /** * A {@link SpinnerValueFactory} which work on float values. * * @author Alexis Manin (Geomatys) */ public class FloatSpinnerValueFactory extends SpinnerValueFactory<Float> { protected static final DecimalFormat FLOAT_TO_STRING = new DecimalFormat("#.##"); protected static final ObjectConverter<? super String, ? extends Float> STRING_TO_FLOAT = ObjectConverters.find(String.class, Float.class); /** * Minimum allowed value for edition. */ private SimpleFloatProperty min = new SimpleFloatProperty(this, "min"); /** * Maximum allowed value for edition. */ private FloatProperty max = new SimpleFloatProperty(this, "max"); /** * Incremented / decremented amount when an arrow is clicked. */ private FloatProperty amountToStepBy = new SimpleFloatProperty(this, "amountToStepBy"); public FloatSpinnerValueFactory() { this(-Float.MAX_VALUE, Float.MAX_VALUE); } public FloatSpinnerValueFactory(float min, float max) { this(min, max, 0); } public FloatSpinnerValueFactory(float min, float max, float initialValue) { this(min, max, initialValue, 0.1f); } public FloatSpinnerValueFactory(float min, float max, float initialValue, float step) { setMin(min); setMax(max); setAmountToStepBy(step); setConverter(new StringConverter<Float>() { @Override public String toString(Float object) { return object == null ? "" : FLOAT_TO_STRING.format(object); } @Override public Float fromString(String string) { return string == null || string.isEmpty() ? null : STRING_TO_FLOAT.apply(string); } }); valueProperty().addListener((o, oldValue, newValue) -> { // when the value is set, we need to react to ensure it is a // valid value (and if not, blow up appropriately) if (newValue < getMin()) { setValue(getMin()); } else if (newValue > getMax()) { setValue(getMax()); } }); setValue(StrictMath.min(getMax(), StrictMath.max(getMin(), initialValue))); } /** * Set minimum allowed value for edition * @param value minimum value */ public final void setMin(float value) { min.set(value); } /** * Get minimum allowed value for edition * @return minimum value */ public final float getMin() { return min.get(); } /** * Minimum allowed value for edition * @return minimum value property */ public final FloatProperty minProperty() { return min; } /** * Set maximum allowed value for edition * @param value maximum value */ public final void setMax(float value) { max.set(value); } /** * Get maximum allowed value for edition * @return maximum value */ public final float getMax() { return max.get(); } /** * Maximum allowed value for edition * @return maximum property */ public final FloatProperty maxProperty() { return max; } /** * Set incremented / decremented amount when an arrow is clicked. * @param value step amount */ public final void setAmountToStepBy(float value) { amountToStepBy.set(value); } /** * Get incremented / decremented amount when an arrow is clicked. * @return step amount */ public final float getAmountToStepBy() { return amountToStepBy.get(); } /** * Incremented / decremented amount when an arrow is clicked. * @return step amount property */ public final FloatProperty amountToStepByProperty() { return amountToStepBy; } /** * {@inheritDoc} */ @Override public void decrement(int steps) { final float newValue = getValue() - (float) steps * amountToStepBy.floatValue(); setValue(StrictMath.min(getMax(), StrictMath.max(getMin(), newValue))); } /** * {@inheritDoc} */ @Override public void increment(int steps) { final float newValue = getValue() + (float) steps * amountToStepBy.floatValue(); setValue(StrictMath.min(getMax(), StrictMath.max(getMin(), newValue))); } }