3030
3131package org .scijava .ui .swing .widget ;
3232
33- import java .awt .Adjustable ;
3433import java .awt .Component ;
3534import java .awt .Dimension ;
3635import java .awt .event .AdjustmentEvent ;
@@ -84,7 +83,7 @@ public class SwingNumberWidget extends SwingInputWidget<Number> implements
8483 @ Parameter
8584 private LogService log ;
8685
87- private JScrollBar scrollBar ;
86+ private CalibratedScrollBar scrollBar ;
8887 private CalibratedSlider slider ;
8988 private JSpinner spinner ;
9089
@@ -121,6 +120,9 @@ else if (model.isStyle(NumberWidget.SLIDER_STYLE)) {
121120 final SpinnerNumberModel spinnerModel =
122121 new SpinnerNumberModelFactory ().createModel (value , min , max , stepSize );
123122 spinner = new JSpinner (spinnerModel );
123+ Dimension spinnerSize = spinner .getSize ();
124+ spinnerSize .width = 50 ;
125+ spinner .setPreferredSize (spinnerSize );
124126 fixSpinner (type );
125127 setToolTip (spinner );
126128 getComponent ().add (spinner );
@@ -143,7 +145,7 @@ public boolean supports(final WidgetModel model) {
143145 @ Override
144146 public void adjustmentValueChanged (final AdjustmentEvent e ) {
145147 // sync spinner with scroll bar value
146- final int value = scrollBar .getValue ();
148+ final Number value = scrollBar .getCalibratedValue ();
147149 spinner .setValue (value );
148150 }
149151
@@ -168,9 +170,9 @@ else if (source == spinner) {
168170
169171 @ Override
170172 public void mouseWheelMoved (final MouseWheelEvent e ) {
171- int value = getValue ().intValue () + e .getWheelRotation (); // TODO convert from wheel rotations to steps on the slider
172- value = Math .min (value , this .get ().getMax ().intValue ());
173- value = Math .max (value , this .get ().getMin ().intValue ());
173+ Number value = getValue ().doubleValue () + e .getWheelRotation () * get (). getStepSize (). doubleValue ();
174+ value = Math .min (value . doubleValue () , this .get ().getMax ().doubleValue ());
175+ value = Math .max (value . doubleValue () , this .get ().getMin ().doubleValue ());
174176 spinner .setValue (value );
175177 syncSliders ();
176178 }
@@ -184,14 +186,17 @@ private void addScrollBar(final Number min, final Number max,
184186 log .warn ("Invalid min/max/step; cannot render scroll bar" );
185187 return ;
186188 }
187- int mn = min .intValue ();
188- if (mn == Integer .MIN_VALUE ) mn = Integer .MIN_VALUE + 1 ;
189- int mx = max .intValue ();
190- if (mx < Integer .MAX_VALUE ) mx ++;
191- final int st = step .intValue ();
192-
193- scrollBar = new JScrollBar (Adjustable .HORIZONTAL , mn , 1 , mn , mx );
194- scrollBar .setUnitIncrement (st );
189+
190+ // TODO Integer cases can possibly be handled in a simpler way
191+ int sMin = 0 ;
192+ int sMax = (int ) ((max .doubleValue () - min .doubleValue ()) / step .doubleValue ());
193+ long range = sMax - sMin ;
194+ if (range > Integer .MAX_VALUE ) {
195+ log .warn ("Scrollbar span too large; max - min < 2^31 required." );
196+ return ;
197+ }
198+
199+ scrollBar = new CalibratedScrollBar (min , max , step );
195200 setToolTip (scrollBar );
196201 getComponent ().add (scrollBar );
197202 scrollBar .addAdjustmentListener (this );
@@ -205,7 +210,8 @@ private void addSlider(final Number min, final Number max,
205210 log .warn ("Invalid min/max/step; cannot render slider" );
206211 return ;
207212 }
208- // TODO Integer cases can be handled in a simpler way
213+
214+ // TODO Integer cases can possibly be handled in a simpler way
209215 int sMin = 0 ;
210216 int sMax = (int ) ((max .doubleValue () - min .doubleValue ()) / step .doubleValue ());
211217 long range = sMax - sMin ;
@@ -214,7 +220,6 @@ private void addSlider(final Number min, final Number max,
214220 return ;
215221 }
216222
217- // slider = new JSlider(sMin, sMax, sMin);
218223 slider = new CalibratedSlider (min , max , step );
219224
220225 setToolTip (slider );
@@ -307,7 +312,7 @@ public void run() {
307312 private void syncSliders () {
308313 if (slider != null ) {
309314 // clamp value within slider bounds
310- Number value = getValue (). intValue () ;
315+ Number value = getValue ();
311316 if (value .doubleValue () < slider .getCalibratedMinimum ().doubleValue ()) value = slider .getCalibratedMinimum ();
312317 else if (value .doubleValue () > slider .getCalibratedMaximum ().doubleValue ()) value = slider .getCalibratedMaximum ();
313318 slider .removeChangeListener (this );
@@ -316,11 +321,11 @@ private void syncSliders() {
316321 }
317322 if (scrollBar != null ) {
318323 // clamp value within scroll bar bounds
319- int value = getValue (). intValue ();
320- if (value < scrollBar .getMinimum ()) value = scrollBar .getMinimum ();
321- else if (value > scrollBar .getMaximum ()) value = scrollBar .getMaximum ();
324+ Number value = getValue ();
325+ if (value . doubleValue () < scrollBar .getCalibratedMinimum (). doubleValue ()) value = scrollBar .getCalibratedMinimum ();
326+ else if (value . doubleValue () > scrollBar .getCalibratedMaximum (). doubleValue ()) value = scrollBar .getCalibratedMaximum ();
322327 scrollBar .removeAdjustmentListener (this );
323- scrollBar .setValue ( getValue (). intValue () );
328+ scrollBar .setCalibratedValue ( value );
324329 scrollBar .addAdjustmentListener (this );
325330 }
326331 }
@@ -409,7 +414,7 @@ private Number getCalibratedMaximum() {
409414 }
410415
411416 private int fromCalibrated (Number n ) {
412- return (int ) ((n .doubleValue () - min .doubleValue ()) / stepSize .doubleValue ());
417+ return (int ) Math . round ((n .doubleValue () - min .doubleValue ()) / stepSize .doubleValue ());
413418 }
414419
415420 private Number toCalibrated (int n ) {
@@ -421,4 +426,55 @@ private JLabel makeLabel(Number n, int scale) {
421426 }
422427
423428 }
429+
430+ private class CalibratedScrollBar extends JScrollBar {
431+
432+ private Number min ;
433+ private Number max ;
434+ private Number stepSize ;
435+
436+ private CalibratedScrollBar (final Number min , final Number max , final Number stepSize ) {
437+ // set extent to 1 to make sure the scroll bar is visible
438+ super (HORIZONTAL , 0 , 1 , 0 , 1 );
439+
440+ this .min = min ;
441+ this .max = max ;
442+ this .stepSize = stepSize ;
443+
444+ int sMin = 0 ;
445+ int sMax = (int ) ((max .doubleValue () - min .doubleValue ()) / stepSize .doubleValue ()) + 1 ;
446+
447+ // Adjust max to be an integer multiple of stepSize
448+ this .max = min .doubleValue () + (sMax -sMin ) * stepSize .doubleValue ();
449+
450+ setMinimum (sMin );
451+ setMaximum (sMax );
452+ setValue (sMin );
453+ }
454+
455+ private void setCalibratedValue (Number value ) {
456+ setValue (fromCalibrated (value ));
457+ }
458+
459+ private Number getCalibratedValue () {
460+ return toCalibrated (getValue ());
461+ }
462+
463+ private Number getCalibratedMinimum () {
464+ return min ;
465+ }
466+
467+ private Number getCalibratedMaximum () {
468+ return max ;
469+ }
470+
471+ private int fromCalibrated (Number n ) {
472+ return (int ) Math .round ((n .doubleValue () - min .doubleValue ()) / stepSize .doubleValue ());
473+ }
474+
475+ private Number toCalibrated (int n ) {
476+ return n * stepSize .doubleValue () + min .doubleValue ();
477+ }
478+
479+ }
424480}
0 commit comments