//----------------------------------------------------------------------------//
// //
// L o g S l i d e r //
// //
//----------------------------------------------------------------------------//
// <editor-fold defaultstate="collapsed" desc="hdr"> //
// Copyright © Hervé Bitteur and others 2000-2013. All rights reserved. //
// This software is released under the GNU General Public License. //
// Goto http://kenai.com/projects/audiveris to report bugs or suggestions. //
//----------------------------------------------------------------------------//
// </editor-fold>
package omr.ui.view;
import omr.constant.Constant;
import omr.constant.ConstantSet;
import java.util.Hashtable;
import javax.swing.JLabel;
import javax.swing.JSlider;
/**
* Class {@code LogSlider} is a specific {@link JSlider} which handles
* double values with a logarithmic scale (while normal JSlider
* handles only integer values).
*
* <p>As with a basic JSlider, any external entity can be notified of new
* slider value, by first registering to this LogSlider via the {@link
*#addChangeListener} method.
*
* @author Hervé Bitteur
*/
public class LogSlider
extends JSlider
{
//~ Static fields/initializers ---------------------------------------------
/** Specific application parameters */
private static final Constants constants = new Constants();
// Internal resolution
private static final int unit = constants.resolution.getValue();
private static final double doubleUnit = unit; // To speed up
//~ Instance fields --------------------------------------------------------
// Base of log (generally 2 or 10)
private final double base;
//~ Constructors -----------------------------------------------------------
//-----------//
// LogSlider //
//-----------//
/**
* Creates a new {@code LogSlider} instance.
*
* @param base to specify the base of logarithm, generally either 2
* or
* 10.
* @param minors number of minor intervals within one major interval
* (if
* specified as 1 minor per major, this means that
* there is no minor ticks)
* @param orientation to specify the slider orientation, either VERTICAL
* or HORIZONTAL.
* @param min to set lower bound of the slider, specified in power
* of
* base, for example -3 to mean 1/8 (2**-3 if base =
* 2).
* @param max to set upper bound, for example 5 to mean 32 (2**5, if
* base
* = 2).
* @param initial to set the slider initial value, specified in power of
* base, for example 0 to mean 1 (2**0, if base = 2)
*/
public LogSlider (int base,
int minors,
int orientation,
int min,
int max,
int initial)
{
// JSlider construction
super(orientation, min * unit, max * unit, initial * unit);
// Cache data
this.base = (double) base;
// Ticks
super.setMajorTickSpacing(unit);
if (minors > 1) {
super.setMinorTickSpacing(unit / minors);
}
setPaintTicks(true);
// More room given to labels
// switch (orientation) {
// case HORIZONTAL : setBorder (BorderFactory.createEmptyBorder(0,0,5,0));
// break;
// case VERTICAL : setBorder (BorderFactory.createEmptyBorder(0,0,0,5));
// }
// Create and populate the label table
Hashtable<Integer, JLabel> labelTable = new Hashtable<>();
for (int i = min; i <= max; i++) {
labelTable.put(
Integer.valueOf(i * unit),
new JLabel(
(i < 0) ? ("1/" + (int) expOf(-i * unit))
: ("" + (int) expOf(i * unit))));
}
setLabelTable(labelTable);
setPaintLabels(true);
// Force the knob to align on predefined ticks
setSnapToTicks(true);
}
//~ Methods ----------------------------------------------------------------
//----------------//
// getDoubleValue //
//----------------//
/**
* Retrieve the slider current position, and return the corresponding
* value
*
* @return The current value, such as 32 or 0.125.
*/
public double getDoubleValue ()
{
return expOf(super.getValue());
}
//----------------//
// setDoubleValue //
//----------------//
/**
* Use the provided value, to set the slider internal position.
*
* @param d a {@code double} value, such as 32 or 0.125.
*/
public void setDoubleValue (double d)
{
super.setValue(logOf(d));
}
//---------------------//
// setMajorTickSpacing //
//---------------------//
/**
* This is a non supported operation, though part of the JSlider
* interface, since there is exactly one major tick per each increment
* of base power.
*
* @param n not used
*/
@Override
public void setMajorTickSpacing (int n)
{
throw new UnsupportedOperationException(
"Method setMajorTickSpacing not supported by LogSlider");
}
//---------------------//
// setMinorTickSpacing //
//---------------------//
/**
* This is a non supported operation, though part of the JSlider
* interface, since the correct way to define minor ticks is in the
* constructor to specify the number of minors (minor intervals) within
* any major interval.
*
* @param n not used
*/
@Override
public void setMinorTickSpacing (int n)
{
throw new UnsupportedOperationException(
"Method setMinorTickSpacing not supported by LogSlider");
}
//-------//
// expOf //
//-------//
private double expOf (int i)
{
return Math.pow(base, (double) i / doubleUnit);
}
//-------//
// logOf //
//-------//
private int logOf (double d)
{
return (int) Math.rint((doubleUnit * Math.log(d)) / Math.log(base));
}
//~ Inner Classes ----------------------------------------------------------
//-----------//
// Constants //
//-----------//
private static final class Constants
extends ConstantSet
{
//~ Instance fields ----------------------------------------------------
Constant.Integer resolution = new Constant.Integer(
"Values",
480,
"Number of values between two major ticks");
}
}