// 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); } }