30
30
31
31
package org .scijava .ui .swing .widget ;
32
32
33
- import java .awt .Adjustable ;
34
33
import java .awt .Component ;
35
34
import java .awt .Dimension ;
36
35
import java .awt .event .AdjustmentEvent ;
@@ -84,7 +83,7 @@ public class SwingNumberWidget extends SwingInputWidget<Number> implements
84
83
@ Parameter
85
84
private LogService log ;
86
85
87
- private JScrollBar scrollBar ;
86
+ private CalibratedScrollBar scrollBar ;
88
87
private CalibratedSlider slider ;
89
88
private JSpinner spinner ;
90
89
@@ -121,6 +120,9 @@ else if (model.isStyle(NumberWidget.SLIDER_STYLE)) {
121
120
final SpinnerNumberModel spinnerModel =
122
121
new SpinnerNumberModelFactory ().createModel (value , min , max , stepSize );
123
122
spinner = new JSpinner (spinnerModel );
123
+ Dimension spinnerSize = spinner .getSize ();
124
+ spinnerSize .width = 50 ;
125
+ spinner .setPreferredSize (spinnerSize );
124
126
fixSpinner (type );
125
127
setToolTip (spinner );
126
128
getComponent ().add (spinner );
@@ -143,7 +145,7 @@ public boolean supports(final WidgetModel model) {
143
145
@ Override
144
146
public void adjustmentValueChanged (final AdjustmentEvent e ) {
145
147
// sync spinner with scroll bar value
146
- final int value = scrollBar .getValue ();
148
+ final Number value = scrollBar .getCalibratedValue ();
147
149
spinner .setValue (value );
148
150
}
149
151
@@ -168,9 +170,9 @@ else if (source == spinner) {
168
170
169
171
@ Override
170
172
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 ());
174
176
spinner .setValue (value );
175
177
syncSliders ();
176
178
}
@@ -184,14 +186,17 @@ private void addScrollBar(final Number min, final Number max,
184
186
log .warn ("Invalid min/max/step; cannot render scroll bar" );
185
187
return ;
186
188
}
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 );
195
200
setToolTip (scrollBar );
196
201
getComponent ().add (scrollBar );
197
202
scrollBar .addAdjustmentListener (this );
@@ -205,7 +210,8 @@ private void addSlider(final Number min, final Number max,
205
210
log .warn ("Invalid min/max/step; cannot render slider" );
206
211
return ;
207
212
}
208
- // TODO Integer cases can be handled in a simpler way
213
+
214
+ // TODO Integer cases can possibly be handled in a simpler way
209
215
int sMin = 0 ;
210
216
int sMax = (int ) ((max .doubleValue () - min .doubleValue ()) / step .doubleValue ());
211
217
long range = sMax - sMin ;
@@ -214,7 +220,6 @@ private void addSlider(final Number min, final Number max,
214
220
return ;
215
221
}
216
222
217
- // slider = new JSlider(sMin, sMax, sMin);
218
223
slider = new CalibratedSlider (min , max , step );
219
224
220
225
setToolTip (slider );
@@ -307,7 +312,7 @@ public void run() {
307
312
private void syncSliders () {
308
313
if (slider != null ) {
309
314
// clamp value within slider bounds
310
- Number value = getValue (). intValue () ;
315
+ Number value = getValue ();
311
316
if (value .doubleValue () < slider .getCalibratedMinimum ().doubleValue ()) value = slider .getCalibratedMinimum ();
312
317
else if (value .doubleValue () > slider .getCalibratedMaximum ().doubleValue ()) value = slider .getCalibratedMaximum ();
313
318
slider .removeChangeListener (this );
@@ -316,11 +321,11 @@ private void syncSliders() {
316
321
}
317
322
if (scrollBar != null ) {
318
323
// 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 ();
322
327
scrollBar .removeAdjustmentListener (this );
323
- scrollBar .setValue ( getValue (). intValue () );
328
+ scrollBar .setCalibratedValue ( value );
324
329
scrollBar .addAdjustmentListener (this );
325
330
}
326
331
}
@@ -409,7 +414,7 @@ private Number getCalibratedMaximum() {
409
414
}
410
415
411
416
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 ());
413
418
}
414
419
415
420
private Number toCalibrated (int n ) {
@@ -421,4 +426,55 @@ private JLabel makeLabel(Number n, int scale) {
421
426
}
422
427
423
428
}
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
+ }
424
480
}
0 commit comments