/* * Copyright 2010-2015 Institut Pasteur. * * This file is part of Icy. * * Icy is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Icy is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Icy. If not, see <http://www.gnu.org/licenses/>. */ package icy.gui.component; import icy.gui.component.ui.RangeSliderUI; import javax.swing.BoundedRangeModel; import javax.swing.JSlider; import org.pushingpixels.substance.api.SubstanceLookAndFeel; /** * An extension of JSlider to select a range of values using two thumb controls. * The thumb controls are used to select the lower and upper value of a range * with predetermined minimum and maximum values. * <p> * Note that RangeSlider makes use of the default BoundedRangeModel, which supports an inner range * defined by a value and an extent. The upper value returned by RangeSlider is simply the lower * value plus the extent. * </p> */ public class RangeSlider extends JSlider { /** * */ private static final long serialVersionUID = 2079286476964629269L; /** * Creates a range slider with the specified orientation and the * specified minimum, maximum, initial values and extend. * The orientation can be * either <code>SwingConstants.VERTICAL</code> or <code>SwingConstants.HORIZONTAL</code>. * <p> * The <code>BoundedRangeModel</code> that holds the slider's data handles any issues that may * arise from improperly setting the minimum, initial, and maximum values on the slider. See the * {@code BoundedRangeModel} documentation for details. * * @param orientation * the orientation of the slider * @param min * the minimum value of the slider * @param max * the maximum value of the slider * @param low * the lower range value of the slider * @param high * the higher range value of the slider * @throws IllegalArgumentException * if orientation is not one of {@code VERTICAL}, {@code HORIZONTAL} * @see BoundedRangeModel * @see #setOrientation * @see #setMinimum * @see #setMaximum * @see #setLowerValue * @see #setUpperValue */ public RangeSlider(int orientation, int min, int max, int low, int high) { super(orientation, min, max, low); // remove focus as we cannot choose which bound to move super.setFocusable(false); setExtent(high); } /** * Creates a horizontal range slider using the specified min, max and value. * <p> * The <code>BoundedRangeModel</code> that holds the slider's data handles any issues that may * arise from improperly setting the minimum, initial, and maximum values on the slider. See the * {@code BoundedRangeModel} documentation for details. * * @param min * the minimum value of the slider * @param max * the maximum value of the slider * @param low * the lower range value of the slider * @param high * the higher range value of the slider * @see BoundedRangeModel * @see #setMinimum * @see #setMaximum * @see #setLowerValue * @see #setUpperValue */ public RangeSlider(int min, int max, int low, int high) { this(HORIZONTAL, min, max, low, high); } /** * Creates a horizontal range slider using the specified min and max * with an initial value equal to the average of the min plus max. * <p> * The <code>BoundedRangeModel</code> that holds the slider's data handles any issues that may * arise from improperly setting the minimum and maximum values on the slider. See the * {@code BoundedRangeModel} documentation for details. * * @param min * the minimum value of the slider * @param max * the maximum value of the slider * @see BoundedRangeModel * @see #setMinimum * @see #setMaximum */ public RangeSlider(int min, int max) { this(HORIZONTAL, min, max, (min + max) / 2, 0); } /** * Creates a range slider using the specified orientation with the * range {@code 0} to {@code 100} and an initial value of {@code 50}. * The orientation can be * either <code>SwingConstants.VERTICAL</code> or <code>SwingConstants.HORIZONTAL</code>. * * @param orientation * the orientation of the slider * @throws IllegalArgumentException * if orientation is not one of {@code VERTICAL}, {@code HORIZONTAL} * @see #setOrientation */ public RangeSlider(int orientation) { this(orientation, 0, 100, 40, 20); } /** * Creates a horizontal range slider with the range 0 to 100 and * an initial value of 50. */ public RangeSlider() { this(HORIZONTAL, 0, 100, 40, 20); } @Override public void setFocusable(boolean focusable) { // not focusable super.setFocusable(false); } /** * Overrides the superclass method to install the UI delegate to draw two * thumbs. */ @Override public void updateUI() { if (SubstanceLookAndFeel.isCurrentLookAndFeel()) { setUI(new RangeSliderUI(this)); // Update UI for slider labels. This must be called after updating the // UI of the slider. Refer to JSlider.updateUI(). updateLabelUIs(); } else super.updateUI(); } /** * Returns the lower value in the range. */ @Override public int getValue() { return super.getValue(); } /** * Sets the lower value in the range. */ @Override public void setValue(int value) { int oldValue = getValue(); if (oldValue == value) return; // Compute new value and extent to maintain upper value. int oldExtent = getExtent(); int newValue = Math.min(Math.max(getMinimum(), value), oldValue + oldExtent); int newExtent = oldExtent + oldValue - newValue; // Set new value and extent, and fire a single change event. getModel().setRangeProperties(newValue, newExtent, getMinimum(), getMaximum(), getValueIsAdjusting()); } /** * Returns the lower value in the range. */ public int getLowerValue() { return getValue(); } /** * Sets the lower value in the range. */ public void setLowerValue(int value) { setValue(value); } /** * Returns the upper value in the range. */ public int getUpperValue() { return getValue() + getExtent(); } /** * Sets the upper value in the range. */ public void setUpperValue(int value) { // Compute new extent. int lowerValue = getValue(); int newExtent = Math.min(Math.max(0, value - lowerValue), getMaximum() - lowerValue); // Set extent to set upper value. setExtent(newExtent); } }