// FloatSlider.java
import java.awt.*;
import java.awt.event.*;
/**
* floating point version of JSlider.
* replaces the original integer get/set Minimum/Maximum/Value methods with the
* floating point versions: get/set FloatMinimum/FloatMaximum/FloatValue.
* it is an error to call the original versions or other methods related to them.
* note that unlike in the base class, values set via setFloatValue(val) are allowed
* to be outside the min/max range values. in those cases the slider thumb will clamp
* to the appropriate slider end (just like in the base class) but the out-of-range
* value will still be retrivable with getFloatValue().
*
* @author Melinda Green
* @author Don Hatch
*/
public class FloatSlider extends Scrollbar {
private final static int DEFAULT_RANGE = 1000; // number of descrete steps
private final static int DEFAULT_VISIBLE = 20; // pixel width of thumb
private double curFloat, minFloat, maxFloat;
private boolean isLogScale;
/**
* constructs a FloatSlider using a given number of slider positions.
* @param orientation - Scrollbar.VERTICAL or Scrollbar.HORIZONTAL.
* @param cur - real valued initial value.
* @param vis - same as in Scrollbar base class.
* @param min - real valued range minimum.
* @param max - real valued range maximum.
* @param resolution - number of descrete slider positions.
* @param log - log scale if true, linear otherwise.
*/
public FloatSlider(int orientation, double cur, int vis, double min, double max, int res, boolean log) {
super(orientation, 0, vis, 0, res+vis);
isLogScale = log;
setAll(min, max, cur);
addAdjustmentListener(new AdjustmentListener() {
public void adjustmentValueChanged(AdjustmentEvent ae) {
int
ival = FloatSlider.super.getValue(),
vis = FloatSlider.super.getVisibleAmount(),
min = FloatSlider.super.getMinimum(),
max = FloatSlider.super.getMaximum();
double dval = transformRange(false, min, max-vis, ival,
isLogScale, minFloat, maxFloat);
//System.out.println("getting: ival="+ival+" -> dval="+dval);
setFloatValue(dval);
}
});
}
/**
* uses default scale (linear).
*/
public FloatSlider(int orientation, double cur, int vis, double min, double max, int res) {
this(orientation, cur, vis, min, max, res, false);
}
/**
* uses default visible(20) and resolution(1000).
*/
public FloatSlider(int orientation, double cur, double min, double max, boolean log) {
this(orientation, cur, DEFAULT_VISIBLE, min, max, DEFAULT_RANGE, log);
}
/**
* uses default visible(20), resolution(1000), and scale (linear).
*/
public FloatSlider(int orientation, double cur, double min, double max) {
this(orientation, cur, DEFAULT_VISIBLE, min, max, DEFAULT_RANGE, false);
}
/**
* returns the closest integer in the range of the actual int extents of the base Scrollbar.
*/
protected int rangeValue(double dval) {
dval = clamp(dval, minFloat, maxFloat);
int
vis = super.getVisibleAmount(),
min = super.getMinimum(),
max = super.getMaximum();
int ival = (int)Math.round(
transformRange(isLogScale, minFloat, maxFloat, dval,
false, min, max-vis));
//System.out.println("setting: dval="+dval+" -> ival="+ival);
return ival;
}
public double getFloatMinimum() {
return minFloat;
}
public double getFloatMaximum() {
return maxFloat;
}
public double getFloatValue() {
return curFloat;
}
public void setFloatMinimum(double newmin) {
setAll(newmin, maxFloat, getFloatValue());
}
public void setFloatMaximum(double newmax) {
setAll(minFloat, newmax, getFloatValue());
}
public void setFloatValue(double newcur) {
// update the model
curFloat = newcur;
// update the view
super.setValues(rangeValue(newcur),
super.getVisibleAmount(),
super.getMinimum(),
super.getMaximum());
}
public void setAll(double newmin, double newmax, double newcur) {
minFloat = newmin;
maxFloat = newmax;
setFloatValue(newcur);
}
private static double clamp(double x, double a, double b)
{
return x <= a ? a :
x >= b ? b : x;
}
// linear interpolation
private static double lerp(double a, double b, double t)
{
return a + (b-a) * t;
}
// geometric interpolation
private static double gerp(double a, double b, double t)
{
return a * Math.pow(b/a, t);
}
// interpolate between A and B (linearly or geometrically)
// by the fraction that x is between a and b (linearly or geometrically)
private static double
transformRange(boolean isLog, double a, double b, double x,
boolean IsLog, double A, double B)
{
if (isLog)
{
a = Math.log(a);
b = Math.log(b);
x = Math.log(x);
}
double t = (x-a) / (b-a);
double X = IsLog ? gerp(A,B,t)
: lerp(A,B,t);
return X;
}
/**
* simple test program for FloatSlider class.
*/
public static void main(String args[]) {
Frame frame = new Frame("FloatSlider example");
final FloatSlider rslider = new FloatSlider(Scrollbar.HORIZONTAL, 100.1f, 5.5f, 50000f, true);
final Label curValue = new Label("FloatSlider value: " + rslider.getFloatValue());
rslider.addAdjustmentListener(new AdjustmentListener() {
public void adjustmentValueChanged(AdjustmentEvent ae) {
curValue.setText("FloatSlider value: " + rslider.getFloatValue());
}
});
Container mainpanel = new Panel();
mainpanel.setLayout(new GridLayout(3, 1));
mainpanel.add(new Label("Range: " + rslider.getFloatMinimum() + " -> " + rslider.getFloatMaximum()));
mainpanel.add(rslider);
mainpanel.add(curValue);
frame.add(mainpanel);
frame.setSize(new Dimension(800, 100));
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
System.exit(1);
}
});
frame.setVisible(true);
}
}