Libraryless. Click here for Pure Java version (706L/5K).
1 | import javax.swing.plaf.basic.BasicSliderUI; |
2 | import java.awt.geom.Ellipse2D; |
3 | |
4 | /** |
5 | * An extension of JSlider to select a range of values using two thumb controls. |
6 | * The thumb controls are used to select the lower and upper value of a range |
7 | * with predetermined minimum and maximum values. |
8 | * |
9 | * <p>Note that RangeSlider makes use of the default BoundedRangeModel, which |
10 | * supports an inner range defined by a value and an extent. The upper value |
11 | * returned by RangeSlider is simply the lower value plus the extent.</p> |
12 | */ |
13 | sclass RangeSlider extends JSlider { |
14 | /** |
15 | * Constructs a RangeSlider with default minimum and maximum values of 0 |
16 | * and 100. |
17 | */ |
18 | public RangeSlider() { |
19 | initSlider(); |
20 | } |
21 | |
22 | /** |
23 | * Constructs a RangeSlider with the specified default minimum and maximum |
24 | * values. |
25 | */ |
26 | public RangeSlider(int min, int max) { |
27 | super(min, max); |
28 | initSlider(); |
29 | } |
30 | |
31 | /** |
32 | * Initializes the slider by setting default properties. |
33 | */ |
34 | private void initSlider() { |
35 | setOrientation(HORIZONTAL); |
36 | } |
37 | |
38 | /** |
39 | * Overrides the superclass method to install the UI delegate to draw two |
40 | * thumbs. |
41 | */ |
42 | @Override |
43 | public void updateUI() { |
44 | setUI(new RangeSliderUI(this)); |
45 | // Update UI for slider labels. This must be called after updating the |
46 | // UI of the slider. Refer to JSlider.updateUI(). |
47 | updateLabelUIs(); |
48 | } |
49 | |
50 | /** |
51 | * Returns the lower value in the range. |
52 | */ |
53 | @Override |
54 | public int getValue() { |
55 | return super.getValue(); |
56 | } |
57 | |
58 | /** |
59 | * Sets the lower value in the range. |
60 | */ |
61 | @Override |
62 | public void setValue(int value) { |
63 | int oldValue = getValue(); |
64 | if (oldValue == value) { |
65 | return; |
66 | } |
67 | |
68 | // Compute new value and extent to maintain upper value. |
69 | int oldExtent = getExtent(); |
70 | int newValue = Math.min(Math.max(getMinimum(), value), oldValue + oldExtent); |
71 | int newExtent = oldExtent + oldValue - newValue; |
72 | |
73 | // Set new value and extent, and fire a single change event. |
74 | getModel().setRangeProperties(newValue, newExtent, getMinimum(), |
75 | getMaximum(), getValueIsAdjusting()); |
76 | } |
77 | |
78 | /** |
79 | * Returns the upper value in the range. |
80 | */ |
81 | public int getUpperValue() { |
82 | return getValue() + getExtent(); |
83 | } |
84 | |
85 | /** |
86 | * Sets the upper value in the range. |
87 | */ |
88 | public void setUpperValue(int value) { |
89 | // Compute new extent. |
90 | int lowerValue = getValue(); |
91 | int newExtent = Math.min(Math.max(0, value - lowerValue), getMaximum() - lowerValue); |
92 | |
93 | // Set extent to set upper value. |
94 | setExtent(newExtent); |
95 | } |
96 | |
97 | void setValues(int value, int upper) { |
98 | setValue(value); |
99 | setUpperValue(upper); |
100 | } |
101 | } |
102 | |
103 | /** |
104 | * UI delegate for the RangeSlider component. RangeSliderUI paints two thumbs, |
105 | * one for the lower value and one for the upper value. |
106 | */ |
107 | sclass RangeSliderUI extends BasicSliderUI { |
108 | |
109 | /** Color of selected range. */ |
110 | private Color rangeColor = Color.GREEN; |
111 | |
112 | /** Location and size of thumb for upper value. */ |
113 | private Rectangle upperThumbRect; |
114 | /** Indicator that determines whether upper thumb is selected. */ |
115 | private boolean upperThumbSelected; |
116 | |
117 | /** Indicator that determines whether lower thumb is being dragged. */ |
118 | private transient boolean lowerDragging; |
119 | /** Indicator that determines whether upper thumb is being dragged. */ |
120 | private transient boolean upperDragging; |
121 | |
122 | /** |
123 | * Constructs a RangeSliderUI for the specified slider component. |
124 | * @param b RangeSlider |
125 | */ |
126 | public RangeSliderUI(RangeSlider b) { |
127 | super(b); |
128 | } |
129 | |
130 | /** |
131 | * Installs this UI delegate on the specified component. |
132 | */ |
133 | @Override |
134 | public void installUI(JComponent c) { |
135 | upperThumbRect = new Rectangle(); |
136 | super.installUI(c); |
137 | } |
138 | |
139 | /** |
140 | * Creates a listener to handle track events in the specified slider. |
141 | */ |
142 | @Override |
143 | protected TrackListener createTrackListener(JSlider slider) { |
144 | return new RangeTrackListener(); |
145 | } |
146 | |
147 | /** |
148 | * Creates a listener to handle change events in the specified slider. |
149 | */ |
150 | @Override |
151 | protected ChangeListener createChangeListener(JSlider slider) { |
152 | return new ChangeHandler(); |
153 | } |
154 | |
155 | /** |
156 | * Updates the dimensions for both thumbs. |
157 | */ |
158 | @Override |
159 | protected void calculateThumbSize() { |
160 | // Call superclass method for lower thumb size. |
161 | super.calculateThumbSize(); |
162 | |
163 | // Set upper thumb size. |
164 | upperThumbRect.setSize(thumbRect.width, thumbRect.height); |
165 | } |
166 | |
167 | /** |
168 | * Updates the locations for both thumbs. |
169 | */ |
170 | @Override |
171 | protected void calculateThumbLocation() { |
172 | // Call superclass method for lower thumb location. |
173 | super.calculateThumbLocation(); |
174 | |
175 | // Adjust upper value to snap to ticks if necessary. |
176 | if (slider.getSnapToTicks()) { |
177 | int upperValue = slider.getValue() + slider.getExtent(); |
178 | int snappedValue = upperValue; |
179 | int majorTickSpacing = slider.getMajorTickSpacing(); |
180 | int minorTickSpacing = slider.getMinorTickSpacing(); |
181 | int tickSpacing = 0; |
182 | |
183 | if (minorTickSpacing > 0) { |
184 | tickSpacing = minorTickSpacing; |
185 | } else if (majorTickSpacing > 0) { |
186 | tickSpacing = majorTickSpacing; |
187 | } |
188 | |
189 | if (tickSpacing != 0) { |
190 | // If it's not on a tick, change the value |
191 | if ((upperValue - slider.getMinimum()) % tickSpacing != 0) { |
192 | float temp = (float)(upperValue - slider.getMinimum()) / (float)tickSpacing; |
193 | int whichTick = Math.round(temp); |
194 | snappedValue = slider.getMinimum() + (whichTick * tickSpacing); |
195 | } |
196 | |
197 | if (snappedValue != upperValue) { |
198 | slider.setExtent(snappedValue - slider.getValue()); |
199 | } |
200 | } |
201 | } |
202 | |
203 | // Calculate upper thumb location. The thumb is centered over its |
204 | // value on the track. |
205 | if (slider.getOrientation() == JSlider.HORIZONTAL) { |
206 | int upperPosition = xPositionForValue(slider.getValue() + slider.getExtent()); |
207 | upperThumbRect.x = upperPosition - (upperThumbRect.width / 2); |
208 | upperThumbRect.y = trackRect.y; |
209 | |
210 | } else { |
211 | int upperPosition = yPositionForValue(slider.getValue() + slider.getExtent()); |
212 | upperThumbRect.x = trackRect.x; |
213 | upperThumbRect.y = upperPosition - (upperThumbRect.height / 2); |
214 | } |
215 | } |
216 | |
217 | /** |
218 | * Returns the size of a thumb. |
219 | */ |
220 | @Override |
221 | protected Dimension getThumbSize() { |
222 | return new Dimension(12, 12); |
223 | } |
224 | |
225 | /** |
226 | * Paints the slider. The selected thumb is always painted on top of the |
227 | * other thumb. |
228 | */ |
229 | @Override |
230 | public void paint(Graphics g, JComponent c) { |
231 | super.paint(g, c); |
232 | |
233 | Rectangle clipRect = g.getClipBounds(); |
234 | if (upperThumbSelected) { |
235 | // Paint lower thumb first, then upper thumb. |
236 | if (clipRect.intersects(thumbRect)) { |
237 | paintLowerThumb(g); |
238 | } |
239 | if (clipRect.intersects(upperThumbRect)) { |
240 | paintUpperThumb(g); |
241 | } |
242 | |
243 | } else { |
244 | // Paint upper thumb first, then lower thumb. |
245 | if (clipRect.intersects(upperThumbRect)) { |
246 | paintUpperThumb(g); |
247 | } |
248 | if (clipRect.intersects(thumbRect)) { |
249 | paintLowerThumb(g); |
250 | } |
251 | } |
252 | } |
253 | |
254 | /** |
255 | * Paints the track. |
256 | */ |
257 | @Override |
258 | public void paintTrack(Graphics g) { |
259 | // Draw track. |
260 | super.paintTrack(g); |
261 | |
262 | Rectangle trackBounds = trackRect; |
263 | |
264 | if (slider.getOrientation() == JSlider.HORIZONTAL) { |
265 | // Determine position of selected range by moving from the middle |
266 | // of one thumb to the other. |
267 | int lowerX = thumbRect.x + (thumbRect.width / 2); |
268 | int upperX = upperThumbRect.x + (upperThumbRect.width / 2); |
269 | |
270 | // Determine track position. |
271 | int cy = (trackBounds.height / 2) - 2; |
272 | |
273 | // Save color and shift position. |
274 | Color oldColor = g.getColor(); |
275 | g.translate(trackBounds.x, trackBounds.y + cy); |
276 | |
277 | // Draw selected range. |
278 | g.setColor(rangeColor); |
279 | for (int y = 0; y <= 3; y++) { |
280 | g.drawLine(lowerX - trackBounds.x, y, upperX - trackBounds.x, y); |
281 | } |
282 | |
283 | // Restore position and color. |
284 | g.translate(-trackBounds.x, -(trackBounds.y + cy)); |
285 | g.setColor(oldColor); |
286 | |
287 | } else { |
288 | // Determine position of selected range by moving from the middle |
289 | // of one thumb to the other. |
290 | int lowerY = thumbRect.x + (thumbRect.width / 2); |
291 | int upperY = upperThumbRect.x + (upperThumbRect.width / 2); |
292 | |
293 | // Determine track position. |
294 | int cx = (trackBounds.width / 2) - 2; |
295 | |
296 | // Save color and shift position. |
297 | Color oldColor = g.getColor(); |
298 | g.translate(trackBounds.x + cx, trackBounds.y); |
299 | |
300 | // Draw selected range. |
301 | g.setColor(rangeColor); |
302 | for (int x = 0; x <= 3; x++) { |
303 | g.drawLine(x, lowerY - trackBounds.y, x, upperY - trackBounds.y); |
304 | } |
305 | |
306 | // Restore position and color. |
307 | g.translate(-(trackBounds.x + cx), -trackBounds.y); |
308 | g.setColor(oldColor); |
309 | } |
310 | } |
311 | |
312 | /** |
313 | * Overrides superclass method to do nothing. Thumb painting is handled |
314 | * within the <code>paint()</code> method. |
315 | */ |
316 | @Override |
317 | public void paintThumb(Graphics g) { |
318 | // Do nothing. |
319 | } |
320 | |
321 | /** |
322 | * Paints the thumb for the lower value using the specified graphics object. |
323 | */ |
324 | private void paintLowerThumb(Graphics g) { |
325 | Rectangle knobBounds = thumbRect; |
326 | int w = knobBounds.width; |
327 | int h = knobBounds.height; |
328 | |
329 | // Create graphics copy. |
330 | Graphics2D g2d = (Graphics2D) g.create(); |
331 | |
332 | // Create default thumb shape. |
333 | Shape thumbShape = createThumbShape(w - 1, h - 1); |
334 | |
335 | // Draw thumb. |
336 | g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, |
337 | RenderingHints.VALUE_ANTIALIAS_ON); |
338 | g2d.translate(knobBounds.x, knobBounds.y); |
339 | |
340 | g2d.setColor(Color.CYAN); |
341 | g2d.fill(thumbShape); |
342 | |
343 | g2d.setColor(Color.BLUE); |
344 | g2d.draw(thumbShape); |
345 | |
346 | // Dispose graphics. |
347 | g2d.dispose(); |
348 | } |
349 | |
350 | /** |
351 | * Paints the thumb for the upper value using the specified graphics object. |
352 | */ |
353 | private void paintUpperThumb(Graphics g) { |
354 | Rectangle knobBounds = upperThumbRect; |
355 | int w = knobBounds.width; |
356 | int h = knobBounds.height; |
357 | |
358 | // Create graphics copy. |
359 | Graphics2D g2d = (Graphics2D) g.create(); |
360 | |
361 | // Create default thumb shape. |
362 | Shape thumbShape = createThumbShape(w - 1, h - 1); |
363 | |
364 | // Draw thumb. |
365 | g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, |
366 | RenderingHints.VALUE_ANTIALIAS_ON); |
367 | g2d.translate(knobBounds.x, knobBounds.y); |
368 | |
369 | g2d.setColor(Color.PINK); |
370 | g2d.fill(thumbShape); |
371 | |
372 | g2d.setColor(Color.RED); |
373 | g2d.draw(thumbShape); |
374 | |
375 | // Dispose graphics. |
376 | g2d.dispose(); |
377 | } |
378 | |
379 | /** |
380 | * Returns a Shape representing a thumb. |
381 | */ |
382 | private Shape createThumbShape(int width, int height) { |
383 | // Use circular shape. |
384 | Ellipse2D shape = new Ellipse2D.Double(0, 0, width, height); |
385 | return shape; |
386 | } |
387 | |
388 | /** |
389 | * Sets the location of the upper thumb, and repaints the slider. This is |
390 | * called when the upper thumb is dragged to repaint the slider. The |
391 | * <code>setThumbLocation()</code> method performs the same task for the |
392 | * lower thumb. |
393 | */ |
394 | private void setUpperThumbLocation(int x, int y) { |
395 | Rectangle upperUnionRect = new Rectangle(); |
396 | upperUnionRect.setBounds(upperThumbRect); |
397 | |
398 | upperThumbRect.setLocation(x, y); |
399 | |
400 | SwingUtilities.computeUnion(upperThumbRect.x, upperThumbRect.y, upperThumbRect.width, upperThumbRect.height, upperUnionRect); |
401 | slider.repaint(upperUnionRect.x, upperUnionRect.y, upperUnionRect.width, upperUnionRect.height); |
402 | } |
403 | |
404 | /** |
405 | * Moves the selected thumb in the specified direction by a block increment. |
406 | * This method is called when the user presses the Page Up or Down keys. |
407 | */ |
408 | public void scrollByBlock(int direction) { |
409 | synchronized (slider) { |
410 | int blockIncrement = (slider.getMaximum() - slider.getMinimum()) / 10; |
411 | if (blockIncrement <= 0 && slider.getMaximum() > slider.getMinimum()) { |
412 | blockIncrement = 1; |
413 | } |
414 | int delta = blockIncrement * ((direction > 0) ? POSITIVE_SCROLL : NEGATIVE_SCROLL); |
415 | |
416 | if (upperThumbSelected) { |
417 | int oldValue = ((RangeSlider) slider).getUpperValue(); |
418 | ((RangeSlider) slider).setUpperValue(oldValue + delta); |
419 | } else { |
420 | int oldValue = slider.getValue(); |
421 | slider.setValue(oldValue + delta); |
422 | } |
423 | } |
424 | } |
425 | |
426 | /** |
427 | * Moves the selected thumb in the specified direction by a unit increment. |
428 | * This method is called when the user presses one of the arrow keys. |
429 | */ |
430 | public void scrollByUnit(int direction) { |
431 | synchronized (slider) { |
432 | int delta = 1 * ((direction > 0) ? POSITIVE_SCROLL : NEGATIVE_SCROLL); |
433 | |
434 | if (upperThumbSelected) { |
435 | int oldValue = ((RangeSlider) slider).getUpperValue(); |
436 | ((RangeSlider) slider).setUpperValue(oldValue + delta); |
437 | } else { |
438 | int oldValue = slider.getValue(); |
439 | slider.setValue(oldValue + delta); |
440 | } |
441 | } |
442 | } |
443 | |
444 | /** |
445 | * Listener to handle model change events. This calculates the thumb |
446 | * locations and repaints the slider if the value change is not caused by |
447 | * dragging a thumb. |
448 | */ |
449 | public class ChangeHandler implements ChangeListener { |
450 | public void stateChanged(ChangeEvent arg0) { |
451 | if (!lowerDragging && !upperDragging) { |
452 | calculateThumbLocation(); |
453 | slider.repaint(); |
454 | } |
455 | } |
456 | } |
457 | |
458 | /** |
459 | * Listener to handle mouse movements in the slider track. |
460 | */ |
461 | public class RangeTrackListener extends TrackListener { |
462 | |
463 | @Override |
464 | public void mousePressed(MouseEvent e) { |
465 | if (!slider.isEnabled()) { |
466 | return; |
467 | } |
468 | |
469 | currentMouseX = e.getX(); |
470 | currentMouseY = e.getY(); |
471 | |
472 | if (slider.isRequestFocusEnabled()) { |
473 | slider.requestFocus(); |
474 | } |
475 | |
476 | // Determine which thumb is pressed. If the upper thumb is |
477 | // selected (last one dragged), then check its position first; |
478 | // otherwise check the position of the lower thumb first. |
479 | boolean lowerPressed = false; |
480 | boolean upperPressed = false; |
481 | if (upperThumbSelected || slider.getMinimum() == slider.getValue()) { |
482 | if (upperThumbRect.contains(currentMouseX, currentMouseY)) { |
483 | upperPressed = true; |
484 | } else if (thumbRect.contains(currentMouseX, currentMouseY)) { |
485 | lowerPressed = true; |
486 | } |
487 | } else { |
488 | if (thumbRect.contains(currentMouseX, currentMouseY)) { |
489 | lowerPressed = true; |
490 | } else if (upperThumbRect.contains(currentMouseX, currentMouseY)) { |
491 | upperPressed = true; |
492 | } |
493 | } |
494 | |
495 | // Handle lower thumb pressed. |
496 | if (lowerPressed) { |
497 | switch (slider.getOrientation()) { |
498 | case JSlider.VERTICAL: |
499 | offset = currentMouseY - thumbRect.y; |
500 | break; |
501 | case JSlider.HORIZONTAL: |
502 | offset = currentMouseX - thumbRect.x; |
503 | break; |
504 | } |
505 | upperThumbSelected = false; |
506 | lowerDragging = true; |
507 | return; |
508 | } |
509 | lowerDragging = false; |
510 | |
511 | // Handle upper thumb pressed. |
512 | if (upperPressed) { |
513 | switch (slider.getOrientation()) { |
514 | case JSlider.VERTICAL: |
515 | offset = currentMouseY - upperThumbRect.y; |
516 | break; |
517 | case JSlider.HORIZONTAL: |
518 | offset = currentMouseX - upperThumbRect.x; |
519 | break; |
520 | } |
521 | upperThumbSelected = true; |
522 | upperDragging = true; |
523 | return; |
524 | } |
525 | upperDragging = false; |
526 | } |
527 | |
528 | @Override |
529 | public void mouseReleased(MouseEvent e) { |
530 | lowerDragging = false; |
531 | upperDragging = false; |
532 | slider.setValueIsAdjusting(false); |
533 | super.mouseReleased(e); |
534 | } |
535 | |
536 | @Override |
537 | public void mouseDragged(MouseEvent e) { |
538 | if (!slider.isEnabled()) { |
539 | return; |
540 | } |
541 | |
542 | currentMouseX = e.getX(); |
543 | currentMouseY = e.getY(); |
544 | |
545 | if (lowerDragging) { |
546 | slider.setValueIsAdjusting(true); |
547 | moveLowerThumb(); |
548 | |
549 | } else if (upperDragging) { |
550 | slider.setValueIsAdjusting(true); |
551 | moveUpperThumb(); |
552 | } |
553 | } |
554 | |
555 | @Override |
556 | public boolean shouldScroll(int direction) { |
557 | return false; |
558 | } |
559 | |
560 | /** |
561 | * Moves the location of the lower thumb, and sets its corresponding |
562 | * value in the slider. |
563 | */ |
564 | private void moveLowerThumb() { |
565 | int thumbMiddle = 0; |
566 | |
567 | switch (slider.getOrientation()) { |
568 | case JSlider.VERTICAL: |
569 | int halfThumbHeight = thumbRect.height / 2; |
570 | int thumbTop = currentMouseY - offset; |
571 | int trackTop = trackRect.y; |
572 | int trackBottom = trackRect.y + (trackRect.height - 1); |
573 | int vMax = yPositionForValue(slider.getValue() + slider.getExtent()); |
574 | |
575 | // Apply bounds to thumb position. |
576 | if (drawInverted()) { |
577 | trackBottom = vMax; |
578 | } else { |
579 | trackTop = vMax; |
580 | } |
581 | thumbTop = Math.max(thumbTop, trackTop - halfThumbHeight); |
582 | thumbTop = Math.min(thumbTop, trackBottom - halfThumbHeight); |
583 | |
584 | setThumbLocation(thumbRect.x, thumbTop); |
585 | |
586 | // Update slider value. |
587 | thumbMiddle = thumbTop + halfThumbHeight; |
588 | slider.setValue(valueForYPosition(thumbMiddle)); |
589 | break; |
590 | |
591 | case JSlider.HORIZONTAL: |
592 | int halfThumbWidth = thumbRect.width / 2; |
593 | int thumbLeft = currentMouseX - offset; |
594 | int trackLeft = trackRect.x; |
595 | int trackRight = trackRect.x + (trackRect.width - 1); |
596 | int hMax = xPositionForValue(slider.getValue() + slider.getExtent()); |
597 | |
598 | // Apply bounds to thumb position. |
599 | if (drawInverted()) { |
600 | trackLeft = hMax; |
601 | } else { |
602 | trackRight = hMax; |
603 | } |
604 | thumbLeft = Math.max(thumbLeft, trackLeft - halfThumbWidth); |
605 | thumbLeft = Math.min(thumbLeft, trackRight - halfThumbWidth); |
606 | |
607 | setThumbLocation(thumbLeft, thumbRect.y); |
608 | |
609 | // Update slider value. |
610 | thumbMiddle = thumbLeft + halfThumbWidth; |
611 | slider.setValue(valueForXPosition(thumbMiddle)); |
612 | break; |
613 | |
614 | default: |
615 | return; |
616 | } |
617 | } |
618 | |
619 | /** |
620 | * Moves the location of the upper thumb, and sets its corresponding |
621 | * value in the slider. |
622 | */ |
623 | private void moveUpperThumb() { |
624 | int thumbMiddle = 0; |
625 | |
626 | switch (slider.getOrientation()) { |
627 | case JSlider.VERTICAL: |
628 | int halfThumbHeight = thumbRect.height / 2; |
629 | int thumbTop = currentMouseY - offset; |
630 | int trackTop = trackRect.y; |
631 | int trackBottom = trackRect.y + (trackRect.height - 1); |
632 | int vMin = yPositionForValue(slider.getValue()); |
633 | |
634 | // Apply bounds to thumb position. |
635 | if (drawInverted()) { |
636 | trackTop = vMin; |
637 | } else { |
638 | trackBottom = vMin; |
639 | } |
640 | thumbTop = Math.max(thumbTop, trackTop - halfThumbHeight); |
641 | thumbTop = Math.min(thumbTop, trackBottom - halfThumbHeight); |
642 | |
643 | setUpperThumbLocation(thumbRect.x, thumbTop); |
644 | |
645 | // Update slider extent. |
646 | thumbMiddle = thumbTop + halfThumbHeight; |
647 | slider.setExtent(valueForYPosition(thumbMiddle) - slider.getValue()); |
648 | break; |
649 | |
650 | case JSlider.HORIZONTAL: |
651 | int halfThumbWidth = thumbRect.width / 2; |
652 | int thumbLeft = currentMouseX - offset; |
653 | int trackLeft = trackRect.x; |
654 | int trackRight = trackRect.x + (trackRect.width - 1); |
655 | int hMin = xPositionForValue(slider.getValue()); |
656 | |
657 | // Apply bounds to thumb position. |
658 | if (drawInverted()) { |
659 | trackRight = hMin; |
660 | } else { |
661 | trackLeft = hMin; |
662 | } |
663 | thumbLeft = Math.max(thumbLeft, trackLeft - halfThumbWidth); |
664 | thumbLeft = Math.min(thumbLeft, trackRight - halfThumbWidth); |
665 | |
666 | setUpperThumbLocation(thumbLeft, thumbRect.y); |
667 | |
668 | // Update slider extent. |
669 | thumbMiddle = thumbLeft + halfThumbWidth; |
670 | slider.setExtent(valueForXPosition(thumbMiddle) - slider.getValue()); |
671 | break; |
672 | |
673 | default: |
674 | return; |
675 | } |
676 | } |
677 | } |
678 | } |
download show line numbers debug dex old transpilations
Travelled to 6 computer(s): bhatertpkbcr, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tvejysmllsmz, vouqrxazstgt
No comments. add comment
Snippet ID: | #1024530 |
Snippet name: | RangeSlider |
Eternal ID of this version: | #1024530/5 |
Text MD5: | e41b85e4a252dbfd5758ff28a773dc2f |
Transpilation MD5: | bd1c702fbf7b67e8a47ab13134216ad3 |
Author: | stefan |
Category: | javax / gui |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2019-08-17 16:58:22 |
Source code size: | 23416 bytes / 678 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 280 / 699 |
Version history: | 4 change(s) |
Referenced in: | [show references] |