|
1 /* |
|
2 * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. Sun designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Sun in the LICENSE file that accompanied this code. |
|
10 * |
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 * version 2 for more details (a copy is included in the LICENSE file that |
|
15 * accompanied this code). |
|
16 * |
|
17 * You should have received a copy of the GNU General Public License version |
|
18 * 2 along with this work; if not, write to the Free Software Foundation, |
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 * |
|
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
|
22 * CA 95054 USA or visit www.sun.com if you need additional information or |
|
23 * have any questions. |
|
24 */ |
|
25 |
|
26 package javax.swing.plaf.basic; |
|
27 |
|
28 import java.awt.Component; |
|
29 import java.awt.Container; |
|
30 import java.awt.Adjustable; |
|
31 import java.awt.event.*; |
|
32 import java.awt.FontMetrics; |
|
33 import java.awt.Graphics; |
|
34 import java.awt.Dimension; |
|
35 import java.awt.Rectangle; |
|
36 import java.awt.Point; |
|
37 import java.awt.Insets; |
|
38 import java.awt.Color; |
|
39 import java.awt.IllegalComponentStateException; |
|
40 import java.awt.Polygon; |
|
41 import java.beans.*; |
|
42 import java.util.Dictionary; |
|
43 import java.util.Enumeration; |
|
44 |
|
45 import javax.swing.border.AbstractBorder; |
|
46 |
|
47 import javax.swing.*; |
|
48 import javax.swing.event.*; |
|
49 import javax.swing.plaf.*; |
|
50 import sun.swing.DefaultLookup; |
|
51 import sun.swing.UIAction; |
|
52 |
|
53 |
|
54 /** |
|
55 * A Basic L&F implementation of SliderUI. |
|
56 * |
|
57 * @author Tom Santos |
|
58 */ |
|
59 public class BasicSliderUI extends SliderUI{ |
|
60 // Old actions forward to an instance of this. |
|
61 private static final Actions SHARED_ACTION = new Actions(); |
|
62 |
|
63 public static final int POSITIVE_SCROLL = +1; |
|
64 public static final int NEGATIVE_SCROLL = -1; |
|
65 public static final int MIN_SCROLL = -2; |
|
66 public static final int MAX_SCROLL = +2; |
|
67 |
|
68 protected Timer scrollTimer; |
|
69 protected JSlider slider; |
|
70 |
|
71 protected Insets focusInsets = null; |
|
72 protected Insets insetCache = null; |
|
73 protected boolean leftToRightCache = true; |
|
74 protected Rectangle focusRect = null; |
|
75 protected Rectangle contentRect = null; |
|
76 protected Rectangle labelRect = null; |
|
77 protected Rectangle tickRect = null; |
|
78 protected Rectangle trackRect = null; |
|
79 protected Rectangle thumbRect = null; |
|
80 |
|
81 protected int trackBuffer = 0; // The distance that the track is from the side of the control |
|
82 |
|
83 private transient boolean isDragging; |
|
84 |
|
85 protected TrackListener trackListener; |
|
86 protected ChangeListener changeListener; |
|
87 protected ComponentListener componentListener; |
|
88 protected FocusListener focusListener; |
|
89 protected ScrollListener scrollListener; |
|
90 protected PropertyChangeListener propertyChangeListener; |
|
91 private Handler handler; |
|
92 private int lastValue; |
|
93 |
|
94 // Colors |
|
95 private Color shadowColor; |
|
96 private Color highlightColor; |
|
97 private Color focusColor; |
|
98 |
|
99 /** |
|
100 * Whther or not sameLabelBaselines is up to date. |
|
101 */ |
|
102 private boolean checkedLabelBaselines; |
|
103 /** |
|
104 * Whether or not all the entries in the labeltable have the same |
|
105 * baseline. |
|
106 */ |
|
107 private boolean sameLabelBaselines; |
|
108 |
|
109 |
|
110 protected Color getShadowColor() { |
|
111 return shadowColor; |
|
112 } |
|
113 |
|
114 protected Color getHighlightColor() { |
|
115 return highlightColor; |
|
116 } |
|
117 |
|
118 protected Color getFocusColor() { |
|
119 return focusColor; |
|
120 } |
|
121 |
|
122 /** |
|
123 * Returns true if the user is dragging the slider. |
|
124 * |
|
125 * @return true if the user is dragging the slider |
|
126 * @since 1.5 |
|
127 */ |
|
128 protected boolean isDragging() { |
|
129 return isDragging; |
|
130 } |
|
131 |
|
132 ///////////////////////////////////////////////////////////////////////////// |
|
133 // ComponentUI Interface Implementation methods |
|
134 ///////////////////////////////////////////////////////////////////////////// |
|
135 public static ComponentUI createUI(JComponent b) { |
|
136 return new BasicSliderUI((JSlider)b); |
|
137 } |
|
138 |
|
139 public BasicSliderUI(JSlider b) { |
|
140 } |
|
141 |
|
142 public void installUI(JComponent c) { |
|
143 slider = (JSlider) c; |
|
144 |
|
145 checkedLabelBaselines = false; |
|
146 |
|
147 slider.setEnabled(slider.isEnabled()); |
|
148 LookAndFeel.installProperty(slider, "opaque", Boolean.TRUE); |
|
149 |
|
150 isDragging = false; |
|
151 trackListener = createTrackListener( slider ); |
|
152 changeListener = createChangeListener( slider ); |
|
153 componentListener = createComponentListener( slider ); |
|
154 focusListener = createFocusListener( slider ); |
|
155 scrollListener = createScrollListener( slider ); |
|
156 propertyChangeListener = createPropertyChangeListener( slider ); |
|
157 |
|
158 installDefaults( slider ); |
|
159 installListeners( slider ); |
|
160 installKeyboardActions( slider ); |
|
161 |
|
162 scrollTimer = new Timer( 100, scrollListener ); |
|
163 scrollTimer.setInitialDelay( 300 ); |
|
164 |
|
165 insetCache = slider.getInsets(); |
|
166 leftToRightCache = BasicGraphicsUtils.isLeftToRight(slider); |
|
167 focusRect = new Rectangle(); |
|
168 contentRect = new Rectangle(); |
|
169 labelRect = new Rectangle(); |
|
170 tickRect = new Rectangle(); |
|
171 trackRect = new Rectangle(); |
|
172 thumbRect = new Rectangle(); |
|
173 lastValue = slider.getValue(); |
|
174 |
|
175 calculateGeometry(); // This figures out where the labels, ticks, track, and thumb are. |
|
176 } |
|
177 |
|
178 public void uninstallUI(JComponent c) { |
|
179 if ( c != slider ) |
|
180 throw new IllegalComponentStateException( |
|
181 this + " was asked to deinstall() " |
|
182 + c + " when it only knows about " |
|
183 + slider + "."); |
|
184 |
|
185 LookAndFeel.uninstallBorder(slider); |
|
186 |
|
187 scrollTimer.stop(); |
|
188 scrollTimer = null; |
|
189 |
|
190 uninstallListeners( slider ); |
|
191 uninstallKeyboardActions(slider); |
|
192 |
|
193 focusInsets = null; |
|
194 insetCache = null; |
|
195 leftToRightCache = true; |
|
196 focusRect = null; |
|
197 contentRect = null; |
|
198 labelRect = null; |
|
199 tickRect = null; |
|
200 trackRect = null; |
|
201 thumbRect = null; |
|
202 trackListener = null; |
|
203 changeListener = null; |
|
204 componentListener = null; |
|
205 focusListener = null; |
|
206 scrollListener = null; |
|
207 propertyChangeListener = null; |
|
208 slider = null; |
|
209 } |
|
210 |
|
211 protected void installDefaults( JSlider slider ) { |
|
212 LookAndFeel.installBorder(slider, "Slider.border"); |
|
213 LookAndFeel.installColorsAndFont(slider, "Slider.background", |
|
214 "Slider.foreground", "Slider.font"); |
|
215 highlightColor = UIManager.getColor("Slider.highlight"); |
|
216 |
|
217 shadowColor = UIManager.getColor("Slider.shadow"); |
|
218 focusColor = UIManager.getColor("Slider.focus"); |
|
219 |
|
220 focusInsets = (Insets)UIManager.get( "Slider.focusInsets" ); |
|
221 } |
|
222 |
|
223 protected TrackListener createTrackListener(JSlider slider) { |
|
224 return new TrackListener(); |
|
225 } |
|
226 |
|
227 protected ChangeListener createChangeListener(JSlider slider) { |
|
228 return getHandler(); |
|
229 } |
|
230 |
|
231 protected ComponentListener createComponentListener(JSlider slider) { |
|
232 return getHandler(); |
|
233 } |
|
234 |
|
235 protected FocusListener createFocusListener(JSlider slider) { |
|
236 return getHandler(); |
|
237 } |
|
238 |
|
239 protected ScrollListener createScrollListener( JSlider slider ) { |
|
240 return new ScrollListener(); |
|
241 } |
|
242 |
|
243 protected PropertyChangeListener createPropertyChangeListener( |
|
244 JSlider slider) { |
|
245 return getHandler(); |
|
246 } |
|
247 |
|
248 private Handler getHandler() { |
|
249 if (handler == null) { |
|
250 handler = new Handler(); |
|
251 } |
|
252 return handler; |
|
253 } |
|
254 |
|
255 protected void installListeners( JSlider slider ) { |
|
256 slider.addMouseListener(trackListener); |
|
257 slider.addMouseMotionListener(trackListener); |
|
258 slider.addFocusListener(focusListener); |
|
259 slider.addComponentListener(componentListener); |
|
260 slider.addPropertyChangeListener( propertyChangeListener ); |
|
261 slider.getModel().addChangeListener(changeListener); |
|
262 } |
|
263 |
|
264 protected void uninstallListeners( JSlider slider ) { |
|
265 slider.removeMouseListener(trackListener); |
|
266 slider.removeMouseMotionListener(trackListener); |
|
267 slider.removeFocusListener(focusListener); |
|
268 slider.removeComponentListener(componentListener); |
|
269 slider.removePropertyChangeListener( propertyChangeListener ); |
|
270 slider.getModel().removeChangeListener(changeListener); |
|
271 handler = null; |
|
272 } |
|
273 |
|
274 protected void installKeyboardActions( JSlider slider ) { |
|
275 InputMap km = getInputMap(JComponent.WHEN_FOCUSED, slider); |
|
276 SwingUtilities.replaceUIInputMap(slider, JComponent.WHEN_FOCUSED, km); |
|
277 LazyActionMap.installLazyActionMap(slider, BasicSliderUI.class, |
|
278 "Slider.actionMap"); |
|
279 } |
|
280 |
|
281 InputMap getInputMap(int condition, JSlider slider) { |
|
282 if (condition == JComponent.WHEN_FOCUSED) { |
|
283 InputMap keyMap = (InputMap)DefaultLookup.get(slider, this, |
|
284 "Slider.focusInputMap"); |
|
285 InputMap rtlKeyMap; |
|
286 |
|
287 if (slider.getComponentOrientation().isLeftToRight() || |
|
288 ((rtlKeyMap = (InputMap)DefaultLookup.get(slider, this, |
|
289 "Slider.focusInputMap.RightToLeft")) == null)) { |
|
290 return keyMap; |
|
291 } else { |
|
292 rtlKeyMap.setParent(keyMap); |
|
293 return rtlKeyMap; |
|
294 } |
|
295 } |
|
296 return null; |
|
297 } |
|
298 |
|
299 /** |
|
300 * Populates ComboBox's actions. |
|
301 */ |
|
302 static void loadActionMap(LazyActionMap map) { |
|
303 map.put(new Actions(Actions.POSITIVE_UNIT_INCREMENT)); |
|
304 map.put(new Actions(Actions.POSITIVE_BLOCK_INCREMENT)); |
|
305 map.put(new Actions(Actions.NEGATIVE_UNIT_INCREMENT)); |
|
306 map.put(new Actions(Actions.NEGATIVE_BLOCK_INCREMENT)); |
|
307 map.put(new Actions(Actions.MIN_SCROLL_INCREMENT)); |
|
308 map.put(new Actions(Actions.MAX_SCROLL_INCREMENT)); |
|
309 } |
|
310 |
|
311 protected void uninstallKeyboardActions( JSlider slider ) { |
|
312 SwingUtilities.replaceUIActionMap(slider, null); |
|
313 SwingUtilities.replaceUIInputMap(slider, JComponent.WHEN_FOCUSED, |
|
314 null); |
|
315 } |
|
316 |
|
317 |
|
318 /** |
|
319 * Returns the baseline. |
|
320 * |
|
321 * @throws NullPointerException {@inheritDoc} |
|
322 * @throws IllegalArgumentException {@inheritDoc} |
|
323 * @see javax.swing.JComponent#getBaseline(int, int) |
|
324 * @since 1.6 |
|
325 */ |
|
326 public int getBaseline(JComponent c, int width, int height) { |
|
327 super.getBaseline(c, width, height); |
|
328 if (slider.getPaintLabels() && labelsHaveSameBaselines()) { |
|
329 FontMetrics metrics = slider.getFontMetrics(slider.getFont()); |
|
330 Insets insets = slider.getInsets(); |
|
331 Dimension thumbSize = getThumbSize(); |
|
332 if (slider.getOrientation() == JSlider.HORIZONTAL) { |
|
333 int tickLength = getTickLength(); |
|
334 int contentHeight = height - insets.top - insets.bottom - |
|
335 focusInsets.top - focusInsets.bottom; |
|
336 int thumbHeight = thumbSize.height; |
|
337 int centerSpacing = thumbHeight; |
|
338 if (slider.getPaintTicks()) { |
|
339 centerSpacing += tickLength; |
|
340 } |
|
341 // Assume uniform labels. |
|
342 centerSpacing += getHeightOfTallestLabel(); |
|
343 int trackY = insets.top + focusInsets.top + |
|
344 (contentHeight - centerSpacing - 1) / 2; |
|
345 int trackHeight = thumbHeight; |
|
346 int tickY = trackY + trackHeight; |
|
347 int tickHeight = tickLength; |
|
348 if (!slider.getPaintTicks()) { |
|
349 tickHeight = 0; |
|
350 } |
|
351 int labelY = tickY + tickHeight; |
|
352 return labelY + metrics.getAscent(); |
|
353 } |
|
354 else { // vertical |
|
355 boolean inverted = slider.getInverted(); |
|
356 Integer value = inverted ? getLowestValue() : |
|
357 getHighestValue(); |
|
358 if (value != null) { |
|
359 int thumbHeight = thumbSize.height; |
|
360 int trackBuffer = Math.max(metrics.getHeight() / 2, |
|
361 thumbHeight / 2); |
|
362 int contentY = focusInsets.top + insets.top; |
|
363 int trackY = contentY + trackBuffer; |
|
364 int trackHeight = height - focusInsets.top - |
|
365 focusInsets.bottom - insets.top - insets.bottom - |
|
366 trackBuffer - trackBuffer; |
|
367 int yPosition = yPositionForValue(value, trackY, |
|
368 trackHeight); |
|
369 return yPosition - metrics.getHeight() / 2 + |
|
370 metrics.getAscent(); |
|
371 } |
|
372 } |
|
373 } |
|
374 return 0; |
|
375 } |
|
376 |
|
377 /** |
|
378 * Returns an enum indicating how the baseline of the component |
|
379 * changes as the size changes. |
|
380 * |
|
381 * @throws NullPointerException {@inheritDoc} |
|
382 * @see javax.swing.JComponent#getBaseline(int, int) |
|
383 * @since 1.6 |
|
384 */ |
|
385 public Component.BaselineResizeBehavior getBaselineResizeBehavior( |
|
386 JComponent c) { |
|
387 super.getBaselineResizeBehavior(c); |
|
388 // NOTE: BasicSpinner really provides for CENTER_OFFSET, but |
|
389 // the default min/pref size is smaller than it should be |
|
390 // so that getBaseline() doesn't implement the contract |
|
391 // for CENTER_OFFSET as defined in Component. |
|
392 return Component.BaselineResizeBehavior.OTHER; |
|
393 } |
|
394 |
|
395 /** |
|
396 * Returns true if all the labels from the label table have the same |
|
397 * baseline. |
|
398 * |
|
399 * @return true if all the labels from the label table have the |
|
400 * same baseline |
|
401 * @since 1.6 |
|
402 */ |
|
403 protected boolean labelsHaveSameBaselines() { |
|
404 if (!checkedLabelBaselines) { |
|
405 checkedLabelBaselines = true; |
|
406 Dictionary dictionary = slider.getLabelTable(); |
|
407 if (dictionary != null) { |
|
408 sameLabelBaselines = true; |
|
409 Enumeration elements = dictionary.elements(); |
|
410 int baseline = -1; |
|
411 while (elements.hasMoreElements()) { |
|
412 Component label = (Component)elements.nextElement(); |
|
413 Dimension pref = label.getPreferredSize(); |
|
414 int labelBaseline = label.getBaseline(pref.width, |
|
415 pref.height); |
|
416 if (labelBaseline >= 0) { |
|
417 if (baseline == -1) { |
|
418 baseline = labelBaseline; |
|
419 } |
|
420 else if (baseline != labelBaseline) { |
|
421 sameLabelBaselines = false; |
|
422 break; |
|
423 } |
|
424 } |
|
425 else { |
|
426 sameLabelBaselines = false; |
|
427 break; |
|
428 } |
|
429 } |
|
430 } |
|
431 else { |
|
432 sameLabelBaselines = false; |
|
433 } |
|
434 } |
|
435 return sameLabelBaselines; |
|
436 } |
|
437 |
|
438 public Dimension getPreferredHorizontalSize() { |
|
439 Dimension horizDim = (Dimension)DefaultLookup.get(slider, |
|
440 this, "Slider.horizontalSize"); |
|
441 if (horizDim == null) { |
|
442 horizDim = new Dimension(200, 21); |
|
443 } |
|
444 return horizDim; |
|
445 } |
|
446 |
|
447 public Dimension getPreferredVerticalSize() { |
|
448 Dimension vertDim = (Dimension)DefaultLookup.get(slider, |
|
449 this, "Slider.verticalSize"); |
|
450 if (vertDim == null) { |
|
451 vertDim = new Dimension(21, 200); |
|
452 } |
|
453 return vertDim; |
|
454 } |
|
455 |
|
456 public Dimension getMinimumHorizontalSize() { |
|
457 Dimension minHorizDim = (Dimension)DefaultLookup.get(slider, |
|
458 this, "Slider.minimumHorizontalSize"); |
|
459 if (minHorizDim == null) { |
|
460 minHorizDim = new Dimension(36, 21); |
|
461 } |
|
462 return minHorizDim; |
|
463 } |
|
464 |
|
465 public Dimension getMinimumVerticalSize() { |
|
466 Dimension minVertDim = (Dimension)DefaultLookup.get(slider, |
|
467 this, "Slider.minimumVerticalSize"); |
|
468 if (minVertDim == null) { |
|
469 minVertDim = new Dimension(21, 36); |
|
470 } |
|
471 return minVertDim; |
|
472 } |
|
473 |
|
474 public Dimension getPreferredSize(JComponent c) { |
|
475 recalculateIfInsetsChanged(); |
|
476 Dimension d; |
|
477 if ( slider.getOrientation() == JSlider.VERTICAL ) { |
|
478 d = new Dimension(getPreferredVerticalSize()); |
|
479 d.width = insetCache.left + insetCache.right; |
|
480 d.width += focusInsets.left + focusInsets.right; |
|
481 d.width += trackRect.width + tickRect.width + labelRect.width; |
|
482 } |
|
483 else { |
|
484 d = new Dimension(getPreferredHorizontalSize()); |
|
485 d.height = insetCache.top + insetCache.bottom; |
|
486 d.height += focusInsets.top + focusInsets.bottom; |
|
487 d.height += trackRect.height + tickRect.height + labelRect.height; |
|
488 } |
|
489 |
|
490 return d; |
|
491 } |
|
492 |
|
493 public Dimension getMinimumSize(JComponent c) { |
|
494 recalculateIfInsetsChanged(); |
|
495 Dimension d; |
|
496 |
|
497 if ( slider.getOrientation() == JSlider.VERTICAL ) { |
|
498 d = new Dimension(getMinimumVerticalSize()); |
|
499 d.width = insetCache.left + insetCache.right; |
|
500 d.width += focusInsets.left + focusInsets.right; |
|
501 d.width += trackRect.width + tickRect.width + labelRect.width; |
|
502 } |
|
503 else { |
|
504 d = new Dimension(getMinimumHorizontalSize()); |
|
505 d.height = insetCache.top + insetCache.bottom; |
|
506 d.height += focusInsets.top + focusInsets.bottom; |
|
507 d.height += trackRect.height + tickRect.height + labelRect.height; |
|
508 } |
|
509 |
|
510 return d; |
|
511 } |
|
512 |
|
513 public Dimension getMaximumSize(JComponent c) { |
|
514 Dimension d = getPreferredSize(c); |
|
515 if ( slider.getOrientation() == JSlider.VERTICAL ) { |
|
516 d.height = Short.MAX_VALUE; |
|
517 } |
|
518 else { |
|
519 d.width = Short.MAX_VALUE; |
|
520 } |
|
521 |
|
522 return d; |
|
523 } |
|
524 |
|
525 protected void calculateGeometry() { |
|
526 calculateFocusRect(); |
|
527 calculateContentRect(); |
|
528 calculateThumbSize(); |
|
529 calculateTrackBuffer(); |
|
530 calculateTrackRect(); |
|
531 calculateTickRect(); |
|
532 calculateLabelRect(); |
|
533 calculateThumbLocation(); |
|
534 } |
|
535 |
|
536 protected void calculateFocusRect() { |
|
537 focusRect.x = insetCache.left; |
|
538 focusRect.y = insetCache.top; |
|
539 focusRect.width = slider.getWidth() - (insetCache.left + insetCache.right); |
|
540 focusRect.height = slider.getHeight() - (insetCache.top + insetCache.bottom); |
|
541 } |
|
542 |
|
543 protected void calculateThumbSize() { |
|
544 Dimension size = getThumbSize(); |
|
545 thumbRect.setSize( size.width, size.height ); |
|
546 } |
|
547 |
|
548 protected void calculateContentRect() { |
|
549 contentRect.x = focusRect.x + focusInsets.left; |
|
550 contentRect.y = focusRect.y + focusInsets.top; |
|
551 contentRect.width = focusRect.width - (focusInsets.left + focusInsets.right); |
|
552 contentRect.height = focusRect.height - (focusInsets.top + focusInsets.bottom); |
|
553 } |
|
554 |
|
555 protected void calculateThumbLocation() { |
|
556 if ( slider.getSnapToTicks() ) { |
|
557 int sliderValue = slider.getValue(); |
|
558 int snappedValue = sliderValue; |
|
559 int majorTickSpacing = slider.getMajorTickSpacing(); |
|
560 int minorTickSpacing = slider.getMinorTickSpacing(); |
|
561 int tickSpacing = 0; |
|
562 |
|
563 if ( minorTickSpacing > 0 ) { |
|
564 tickSpacing = minorTickSpacing; |
|
565 } |
|
566 else if ( majorTickSpacing > 0 ) { |
|
567 tickSpacing = majorTickSpacing; |
|
568 } |
|
569 |
|
570 if ( tickSpacing != 0 ) { |
|
571 // If it's not on a tick, change the value |
|
572 if ( (sliderValue - slider.getMinimum()) % tickSpacing != 0 ) { |
|
573 float temp = (float)(sliderValue - slider.getMinimum()) / (float)tickSpacing; |
|
574 int whichTick = Math.round( temp ); |
|
575 |
|
576 // This is the fix for the bug #6401380 |
|
577 if (temp - (int)temp == .5 && sliderValue < lastValue) { |
|
578 whichTick --; |
|
579 } |
|
580 snappedValue = slider.getMinimum() + (whichTick * tickSpacing); |
|
581 } |
|
582 |
|
583 if( snappedValue != sliderValue ) { |
|
584 slider.setValue( snappedValue ); |
|
585 } |
|
586 } |
|
587 } |
|
588 |
|
589 if ( slider.getOrientation() == JSlider.HORIZONTAL ) { |
|
590 int valuePosition = xPositionForValue(slider.getValue()); |
|
591 |
|
592 thumbRect.x = valuePosition - (thumbRect.width / 2); |
|
593 thumbRect.y = trackRect.y; |
|
594 } |
|
595 else { |
|
596 int valuePosition = yPositionForValue(slider.getValue()); |
|
597 |
|
598 thumbRect.x = trackRect.x; |
|
599 thumbRect.y = valuePosition - (thumbRect.height / 2); |
|
600 } |
|
601 } |
|
602 |
|
603 protected void calculateTrackBuffer() { |
|
604 if ( slider.getPaintLabels() && slider.getLabelTable() != null ) { |
|
605 Component highLabel = getHighestValueLabel(); |
|
606 Component lowLabel = getLowestValueLabel(); |
|
607 |
|
608 if ( slider.getOrientation() == JSlider.HORIZONTAL ) { |
|
609 trackBuffer = Math.max( highLabel.getBounds().width, lowLabel.getBounds().width ) / 2; |
|
610 trackBuffer = Math.max( trackBuffer, thumbRect.width / 2 ); |
|
611 } |
|
612 else { |
|
613 trackBuffer = Math.max( highLabel.getBounds().height, lowLabel.getBounds().height ) / 2; |
|
614 trackBuffer = Math.max( trackBuffer, thumbRect.height / 2 ); |
|
615 } |
|
616 } |
|
617 else { |
|
618 if ( slider.getOrientation() == JSlider.HORIZONTAL ) { |
|
619 trackBuffer = thumbRect.width / 2; |
|
620 } |
|
621 else { |
|
622 trackBuffer = thumbRect.height / 2; |
|
623 } |
|
624 } |
|
625 } |
|
626 |
|
627 |
|
628 protected void calculateTrackRect() { |
|
629 int centerSpacing = 0; // used to center sliders added using BorderLayout.CENTER (bug 4275631) |
|
630 if ( slider.getOrientation() == JSlider.HORIZONTAL ) { |
|
631 centerSpacing = thumbRect.height; |
|
632 if ( slider.getPaintTicks() ) centerSpacing += getTickLength(); |
|
633 if ( slider.getPaintLabels() ) centerSpacing += getHeightOfTallestLabel(); |
|
634 trackRect.x = contentRect.x + trackBuffer; |
|
635 trackRect.y = contentRect.y + (contentRect.height - centerSpacing - 1)/2; |
|
636 trackRect.width = contentRect.width - (trackBuffer * 2); |
|
637 trackRect.height = thumbRect.height; |
|
638 } |
|
639 else { |
|
640 centerSpacing = thumbRect.width; |
|
641 if (BasicGraphicsUtils.isLeftToRight(slider)) { |
|
642 if ( slider.getPaintTicks() ) centerSpacing += getTickLength(); |
|
643 if ( slider.getPaintLabels() ) centerSpacing += getWidthOfWidestLabel(); |
|
644 } else { |
|
645 if ( slider.getPaintTicks() ) centerSpacing -= getTickLength(); |
|
646 if ( slider.getPaintLabels() ) centerSpacing -= getWidthOfWidestLabel(); |
|
647 } |
|
648 trackRect.x = contentRect.x + (contentRect.width - centerSpacing - 1)/2; |
|
649 trackRect.y = contentRect.y + trackBuffer; |
|
650 trackRect.width = thumbRect.width; |
|
651 trackRect.height = contentRect.height - (trackBuffer * 2); |
|
652 } |
|
653 |
|
654 } |
|
655 |
|
656 /** |
|
657 * Gets the height of the tick area for horizontal sliders and the width of the |
|
658 * tick area for vertical sliders. BasicSliderUI uses the returned value to |
|
659 * determine the tick area rectangle. If you want to give your ticks some room, |
|
660 * make this larger than you need and paint your ticks away from the sides in paintTicks(). |
|
661 */ |
|
662 protected int getTickLength() { |
|
663 return 8; |
|
664 } |
|
665 |
|
666 protected void calculateTickRect() { |
|
667 if ( slider.getOrientation() == JSlider.HORIZONTAL ) { |
|
668 tickRect.x = trackRect.x; |
|
669 tickRect.y = trackRect.y + trackRect.height; |
|
670 tickRect.width = trackRect.width; |
|
671 tickRect.height = (slider.getPaintTicks()) ? getTickLength() : 0; |
|
672 } |
|
673 else { |
|
674 tickRect.width = (slider.getPaintTicks()) ? getTickLength() : 0; |
|
675 if(BasicGraphicsUtils.isLeftToRight(slider)) { |
|
676 tickRect.x = trackRect.x + trackRect.width; |
|
677 } |
|
678 else { |
|
679 tickRect.x = trackRect.x - tickRect.width; |
|
680 } |
|
681 tickRect.y = trackRect.y; |
|
682 tickRect.height = trackRect.height; |
|
683 } |
|
684 } |
|
685 |
|
686 protected void calculateLabelRect() { |
|
687 if ( slider.getPaintLabels() ) { |
|
688 if ( slider.getOrientation() == JSlider.HORIZONTAL ) { |
|
689 labelRect.x = tickRect.x - trackBuffer; |
|
690 labelRect.y = tickRect.y + tickRect.height; |
|
691 labelRect.width = tickRect.width + (trackBuffer * 2); |
|
692 labelRect.height = getHeightOfTallestLabel(); |
|
693 } |
|
694 else { |
|
695 if(BasicGraphicsUtils.isLeftToRight(slider)) { |
|
696 labelRect.x = tickRect.x + tickRect.width; |
|
697 labelRect.width = getWidthOfWidestLabel(); |
|
698 } |
|
699 else { |
|
700 labelRect.width = getWidthOfWidestLabel(); |
|
701 labelRect.x = tickRect.x - labelRect.width; |
|
702 } |
|
703 labelRect.y = tickRect.y - trackBuffer; |
|
704 labelRect.height = tickRect.height + (trackBuffer * 2); |
|
705 } |
|
706 } |
|
707 else { |
|
708 if ( slider.getOrientation() == JSlider.HORIZONTAL ) { |
|
709 labelRect.x = tickRect.x; |
|
710 labelRect.y = tickRect.y + tickRect.height; |
|
711 labelRect.width = tickRect.width; |
|
712 labelRect.height = 0; |
|
713 } |
|
714 else { |
|
715 if(BasicGraphicsUtils.isLeftToRight(slider)) { |
|
716 labelRect.x = tickRect.x + tickRect.width; |
|
717 } |
|
718 else { |
|
719 labelRect.x = tickRect.x; |
|
720 } |
|
721 labelRect.y = tickRect.y; |
|
722 labelRect.width = 0; |
|
723 labelRect.height = tickRect.height; |
|
724 } |
|
725 } |
|
726 } |
|
727 |
|
728 protected Dimension getThumbSize() { |
|
729 Dimension size = new Dimension(); |
|
730 |
|
731 if ( slider.getOrientation() == JSlider.VERTICAL ) { |
|
732 size.width = 20; |
|
733 size.height = 11; |
|
734 } |
|
735 else { |
|
736 size.width = 11; |
|
737 size.height = 20; |
|
738 } |
|
739 |
|
740 return size; |
|
741 } |
|
742 |
|
743 public class PropertyChangeHandler implements PropertyChangeListener { |
|
744 // NOTE: This class exists only for backward compatability. All |
|
745 // its functionality has been moved into Handler. If you need to add |
|
746 // new functionality add it to the Handler, but make sure this |
|
747 // class calls into the Handler. |
|
748 public void propertyChange( PropertyChangeEvent e ) { |
|
749 getHandler().propertyChange(e); |
|
750 } |
|
751 } |
|
752 |
|
753 protected int getWidthOfWidestLabel() { |
|
754 Dictionary dictionary = slider.getLabelTable(); |
|
755 int widest = 0; |
|
756 if ( dictionary != null ) { |
|
757 Enumeration keys = dictionary.keys(); |
|
758 while ( keys.hasMoreElements() ) { |
|
759 Component label = (Component)dictionary.get( keys.nextElement() ); |
|
760 widest = Math.max( label.getPreferredSize().width, widest ); |
|
761 } |
|
762 } |
|
763 return widest; |
|
764 } |
|
765 |
|
766 protected int getHeightOfTallestLabel() { |
|
767 Dictionary dictionary = slider.getLabelTable(); |
|
768 int tallest = 0; |
|
769 if ( dictionary != null ) { |
|
770 Enumeration keys = dictionary.keys(); |
|
771 while ( keys.hasMoreElements() ) { |
|
772 Component label = (Component)dictionary.get( keys.nextElement() ); |
|
773 tallest = Math.max( label.getPreferredSize().height, tallest ); |
|
774 } |
|
775 } |
|
776 return tallest; |
|
777 } |
|
778 |
|
779 protected int getWidthOfHighValueLabel() { |
|
780 Component label = getHighestValueLabel(); |
|
781 int width = 0; |
|
782 |
|
783 if ( label != null ) { |
|
784 width = label.getPreferredSize().width; |
|
785 } |
|
786 |
|
787 return width; |
|
788 } |
|
789 |
|
790 protected int getWidthOfLowValueLabel() { |
|
791 Component label = getLowestValueLabel(); |
|
792 int width = 0; |
|
793 |
|
794 if ( label != null ) { |
|
795 width = label.getPreferredSize().width; |
|
796 } |
|
797 |
|
798 return width; |
|
799 } |
|
800 |
|
801 protected int getHeightOfHighValueLabel() { |
|
802 Component label = getHighestValueLabel(); |
|
803 int height = 0; |
|
804 |
|
805 if ( label != null ) { |
|
806 height = label.getPreferredSize().height; |
|
807 } |
|
808 |
|
809 return height; |
|
810 } |
|
811 |
|
812 protected int getHeightOfLowValueLabel() { |
|
813 Component label = getLowestValueLabel(); |
|
814 int height = 0; |
|
815 |
|
816 if ( label != null ) { |
|
817 height = label.getPreferredSize().height; |
|
818 } |
|
819 |
|
820 return height; |
|
821 } |
|
822 |
|
823 protected boolean drawInverted() { |
|
824 if (slider.getOrientation()==JSlider.HORIZONTAL) { |
|
825 if(BasicGraphicsUtils.isLeftToRight(slider)) { |
|
826 return slider.getInverted(); |
|
827 } else { |
|
828 return !slider.getInverted(); |
|
829 } |
|
830 } else { |
|
831 return slider.getInverted(); |
|
832 } |
|
833 } |
|
834 |
|
835 /** |
|
836 * Returns the biggest value that has an entry in the label table. |
|
837 * |
|
838 * @return biggest value that has an entry in the label table, or |
|
839 * null. |
|
840 * @since 1.6 |
|
841 */ |
|
842 protected Integer getHighestValue() { |
|
843 Dictionary dictionary = slider.getLabelTable(); |
|
844 if (dictionary != null) { |
|
845 Enumeration keys = dictionary.keys(); |
|
846 int max = slider.getMinimum() - 1; |
|
847 while (keys.hasMoreElements()) { |
|
848 max = Math.max(max, ((Integer)keys.nextElement()).intValue()); |
|
849 } |
|
850 if (max == slider.getMinimum() - 1) { |
|
851 return null; |
|
852 } |
|
853 return max; |
|
854 } |
|
855 return null; |
|
856 } |
|
857 |
|
858 /** |
|
859 * Returns the smallest value that has an entry in the label table. |
|
860 * |
|
861 * @return smallest value that has an entry in the label table, or |
|
862 * null. |
|
863 * @since 1.6 |
|
864 */ |
|
865 protected Integer getLowestValue() { |
|
866 Dictionary dictionary = slider.getLabelTable(); |
|
867 if (dictionary != null) { |
|
868 Enumeration keys = dictionary.keys(); |
|
869 int min = slider.getMaximum() + 1; |
|
870 while (keys.hasMoreElements()) { |
|
871 min = Math.min(min, ((Integer)keys.nextElement()).intValue()); |
|
872 } |
|
873 if (min == slider.getMaximum() + 1) { |
|
874 return null; |
|
875 } |
|
876 return min; |
|
877 } |
|
878 return null; |
|
879 } |
|
880 |
|
881 |
|
882 /** |
|
883 * Returns the label that corresponds to the highest slider value in the label table. |
|
884 * @see JSlider#setLabelTable |
|
885 */ |
|
886 protected Component getLowestValueLabel() { |
|
887 Integer min = getLowestValue(); |
|
888 if (min != null) { |
|
889 return (Component)slider.getLabelTable().get(min); |
|
890 } |
|
891 return null; |
|
892 } |
|
893 |
|
894 /** |
|
895 * Returns the label that corresponds to the lowest slider value in the label table. |
|
896 * @see JSlider#setLabelTable |
|
897 */ |
|
898 protected Component getHighestValueLabel() { |
|
899 Integer max = getHighestValue(); |
|
900 if (max != null) { |
|
901 return (Component)slider.getLabelTable().get(max); |
|
902 } |
|
903 return null; |
|
904 } |
|
905 |
|
906 public void paint( Graphics g, JComponent c ) { |
|
907 recalculateIfInsetsChanged(); |
|
908 recalculateIfOrientationChanged(); |
|
909 Rectangle clip = g.getClipBounds(); |
|
910 |
|
911 if ( !clip.intersects(trackRect) && slider.getPaintTrack()) |
|
912 calculateGeometry(); |
|
913 |
|
914 if ( slider.getPaintTrack() && clip.intersects( trackRect ) ) { |
|
915 paintTrack( g ); |
|
916 } |
|
917 if ( slider.getPaintTicks() && clip.intersects( tickRect ) ) { |
|
918 paintTicks( g ); |
|
919 } |
|
920 if ( slider.getPaintLabels() && clip.intersects( labelRect ) ) { |
|
921 paintLabels( g ); |
|
922 } |
|
923 if ( slider.hasFocus() && clip.intersects( focusRect ) ) { |
|
924 paintFocus( g ); |
|
925 } |
|
926 if ( clip.intersects( thumbRect ) ) { |
|
927 paintThumb( g ); |
|
928 } |
|
929 } |
|
930 |
|
931 protected void recalculateIfInsetsChanged() { |
|
932 Insets newInsets = slider.getInsets(); |
|
933 if ( !newInsets.equals( insetCache ) ) { |
|
934 insetCache = newInsets; |
|
935 calculateGeometry(); |
|
936 } |
|
937 } |
|
938 |
|
939 protected void recalculateIfOrientationChanged() { |
|
940 boolean ltr = BasicGraphicsUtils.isLeftToRight(slider); |
|
941 if ( ltr!=leftToRightCache ) { |
|
942 leftToRightCache = ltr; |
|
943 calculateGeometry(); |
|
944 } |
|
945 } |
|
946 |
|
947 public void paintFocus(Graphics g) { |
|
948 g.setColor( getFocusColor() ); |
|
949 |
|
950 BasicGraphicsUtils.drawDashedRect( g, focusRect.x, focusRect.y, |
|
951 focusRect.width, focusRect.height ); |
|
952 } |
|
953 |
|
954 public void paintTrack(Graphics g) { |
|
955 |
|
956 Rectangle trackBounds = trackRect; |
|
957 |
|
958 if ( slider.getOrientation() == JSlider.HORIZONTAL ) { |
|
959 int cy = (trackBounds.height / 2) - 2; |
|
960 int cw = trackBounds.width; |
|
961 |
|
962 g.translate(trackBounds.x, trackBounds.y + cy); |
|
963 |
|
964 g.setColor(getShadowColor()); |
|
965 g.drawLine(0, 0, cw - 1, 0); |
|
966 g.drawLine(0, 1, 0, 2); |
|
967 g.setColor(getHighlightColor()); |
|
968 g.drawLine(0, 3, cw, 3); |
|
969 g.drawLine(cw, 0, cw, 3); |
|
970 g.setColor(Color.black); |
|
971 g.drawLine(1, 1, cw-2, 1); |
|
972 |
|
973 g.translate(-trackBounds.x, -(trackBounds.y + cy)); |
|
974 } |
|
975 else { |
|
976 int cx = (trackBounds.width / 2) - 2; |
|
977 int ch = trackBounds.height; |
|
978 |
|
979 g.translate(trackBounds.x + cx, trackBounds.y); |
|
980 |
|
981 g.setColor(getShadowColor()); |
|
982 g.drawLine(0, 0, 0, ch - 1); |
|
983 g.drawLine(1, 0, 2, 0); |
|
984 g.setColor(getHighlightColor()); |
|
985 g.drawLine(3, 0, 3, ch); |
|
986 g.drawLine(0, ch, 3, ch); |
|
987 g.setColor(Color.black); |
|
988 g.drawLine(1, 1, 1, ch-2); |
|
989 |
|
990 g.translate(-(trackBounds.x + cx), -trackBounds.y); |
|
991 } |
|
992 } |
|
993 |
|
994 public void paintTicks(Graphics g) { |
|
995 Rectangle tickBounds = tickRect; |
|
996 int i; |
|
997 int maj, min, max; |
|
998 int w = tickBounds.width; |
|
999 int h = tickBounds.height; |
|
1000 int centerEffect, tickHeight; |
|
1001 |
|
1002 g.setColor(DefaultLookup.getColor(slider, this, "Slider.tickColor", Color.black)); |
|
1003 |
|
1004 maj = slider.getMajorTickSpacing(); |
|
1005 min = slider.getMinorTickSpacing(); |
|
1006 |
|
1007 if ( slider.getOrientation() == JSlider.HORIZONTAL ) { |
|
1008 g.translate( 0, tickBounds.y); |
|
1009 |
|
1010 int value = slider.getMinimum(); |
|
1011 int xPos = 0; |
|
1012 |
|
1013 if ( slider.getMinorTickSpacing() > 0 ) { |
|
1014 while ( value <= slider.getMaximum() ) { |
|
1015 xPos = xPositionForValue( value ); |
|
1016 paintMinorTickForHorizSlider( g, tickBounds, xPos ); |
|
1017 value += slider.getMinorTickSpacing(); |
|
1018 } |
|
1019 } |
|
1020 |
|
1021 if ( slider.getMajorTickSpacing() > 0 ) { |
|
1022 value = slider.getMinimum(); |
|
1023 |
|
1024 while ( value <= slider.getMaximum() ) { |
|
1025 xPos = xPositionForValue( value ); |
|
1026 paintMajorTickForHorizSlider( g, tickBounds, xPos ); |
|
1027 value += slider.getMajorTickSpacing(); |
|
1028 } |
|
1029 } |
|
1030 |
|
1031 g.translate( 0, -tickBounds.y); |
|
1032 } |
|
1033 else { |
|
1034 g.translate(tickBounds.x, 0); |
|
1035 |
|
1036 int value = slider.getMinimum(); |
|
1037 int yPos = 0; |
|
1038 |
|
1039 if ( slider.getMinorTickSpacing() > 0 ) { |
|
1040 int offset = 0; |
|
1041 if(!BasicGraphicsUtils.isLeftToRight(slider)) { |
|
1042 offset = tickBounds.width - tickBounds.width / 2; |
|
1043 g.translate(offset, 0); |
|
1044 } |
|
1045 |
|
1046 while ( value <= slider.getMaximum() ) { |
|
1047 yPos = yPositionForValue( value ); |
|
1048 paintMinorTickForVertSlider( g, tickBounds, yPos ); |
|
1049 value += slider.getMinorTickSpacing(); |
|
1050 } |
|
1051 |
|
1052 if(!BasicGraphicsUtils.isLeftToRight(slider)) { |
|
1053 g.translate(-offset, 0); |
|
1054 } |
|
1055 } |
|
1056 |
|
1057 if ( slider.getMajorTickSpacing() > 0 ) { |
|
1058 value = slider.getMinimum(); |
|
1059 if(!BasicGraphicsUtils.isLeftToRight(slider)) { |
|
1060 g.translate(2, 0); |
|
1061 } |
|
1062 |
|
1063 while ( value <= slider.getMaximum() ) { |
|
1064 yPos = yPositionForValue( value ); |
|
1065 paintMajorTickForVertSlider( g, tickBounds, yPos ); |
|
1066 value += slider.getMajorTickSpacing(); |
|
1067 } |
|
1068 |
|
1069 if(!BasicGraphicsUtils.isLeftToRight(slider)) { |
|
1070 g.translate(-2, 0); |
|
1071 } |
|
1072 } |
|
1073 g.translate(-tickBounds.x, 0); |
|
1074 } |
|
1075 } |
|
1076 |
|
1077 protected void paintMinorTickForHorizSlider( Graphics g, Rectangle tickBounds, int x ) { |
|
1078 g.drawLine( x, 0, x, tickBounds.height / 2 - 1 ); |
|
1079 } |
|
1080 |
|
1081 protected void paintMajorTickForHorizSlider( Graphics g, Rectangle tickBounds, int x ) { |
|
1082 g.drawLine( x, 0, x, tickBounds.height - 2 ); |
|
1083 } |
|
1084 |
|
1085 protected void paintMinorTickForVertSlider( Graphics g, Rectangle tickBounds, int y ) { |
|
1086 g.drawLine( 0, y, tickBounds.width / 2 - 1, y ); |
|
1087 } |
|
1088 |
|
1089 protected void paintMajorTickForVertSlider( Graphics g, Rectangle tickBounds, int y ) { |
|
1090 g.drawLine( 0, y, tickBounds.width - 2, y ); |
|
1091 } |
|
1092 |
|
1093 public void paintLabels( Graphics g ) { |
|
1094 Rectangle labelBounds = labelRect; |
|
1095 |
|
1096 Dictionary dictionary = slider.getLabelTable(); |
|
1097 if ( dictionary != null ) { |
|
1098 Enumeration keys = dictionary.keys(); |
|
1099 int minValue = slider.getMinimum(); |
|
1100 int maxValue = slider.getMaximum(); |
|
1101 boolean enabled = slider.isEnabled(); |
|
1102 while ( keys.hasMoreElements() ) { |
|
1103 Integer key = (Integer)keys.nextElement(); |
|
1104 int value = key.intValue(); |
|
1105 if (value >= minValue && value <= maxValue) { |
|
1106 Component label = (Component)dictionary.get( key ); |
|
1107 if (label instanceof JComponent) { |
|
1108 ((JComponent)label).setEnabled(enabled); |
|
1109 } |
|
1110 if ( slider.getOrientation() == JSlider.HORIZONTAL ) { |
|
1111 g.translate( 0, labelBounds.y ); |
|
1112 paintHorizontalLabel( g, value, label ); |
|
1113 g.translate( 0, -labelBounds.y ); |
|
1114 } |
|
1115 else { |
|
1116 int offset = 0; |
|
1117 if (!BasicGraphicsUtils.isLeftToRight(slider)) { |
|
1118 offset = labelBounds.width - |
|
1119 label.getPreferredSize().width; |
|
1120 } |
|
1121 g.translate( labelBounds.x + offset, 0 ); |
|
1122 paintVerticalLabel( g, value, label ); |
|
1123 g.translate( -labelBounds.x - offset, 0 ); |
|
1124 } |
|
1125 } |
|
1126 } |
|
1127 } |
|
1128 |
|
1129 } |
|
1130 |
|
1131 /** |
|
1132 * Called for every label in the label table. Used to draw the labels for horizontal sliders. |
|
1133 * The graphics have been translated to labelRect.y already. |
|
1134 * @see JSlider#setLabelTable |
|
1135 */ |
|
1136 protected void paintHorizontalLabel( Graphics g, int value, Component label ) { |
|
1137 int labelCenter = xPositionForValue( value ); |
|
1138 int labelLeft = labelCenter - (label.getPreferredSize().width / 2); |
|
1139 g.translate( labelLeft, 0 ); |
|
1140 label.paint( g ); |
|
1141 g.translate( -labelLeft, 0 ); |
|
1142 } |
|
1143 |
|
1144 /** |
|
1145 * Called for every label in the label table. Used to draw the labels for vertical sliders. |
|
1146 * The graphics have been translated to labelRect.x already. |
|
1147 * @see JSlider#setLabelTable |
|
1148 */ |
|
1149 protected void paintVerticalLabel( Graphics g, int value, Component label ) { |
|
1150 int labelCenter = yPositionForValue( value ); |
|
1151 int labelTop = labelCenter - (label.getPreferredSize().height / 2); |
|
1152 g.translate( 0, labelTop ); |
|
1153 label.paint( g ); |
|
1154 g.translate( 0, -labelTop ); |
|
1155 } |
|
1156 |
|
1157 public void paintThumb(Graphics g) { |
|
1158 Rectangle knobBounds = thumbRect; |
|
1159 int w = knobBounds.width; |
|
1160 int h = knobBounds.height; |
|
1161 |
|
1162 g.translate(knobBounds.x, knobBounds.y); |
|
1163 |
|
1164 if ( slider.isEnabled() ) { |
|
1165 g.setColor(slider.getBackground()); |
|
1166 } |
|
1167 else { |
|
1168 g.setColor(slider.getBackground().darker()); |
|
1169 } |
|
1170 |
|
1171 Boolean paintThumbArrowShape = |
|
1172 (Boolean)slider.getClientProperty("Slider.paintThumbArrowShape"); |
|
1173 |
|
1174 if ((!slider.getPaintTicks() && paintThumbArrowShape == null) || |
|
1175 paintThumbArrowShape == Boolean.FALSE) { |
|
1176 |
|
1177 // "plain" version |
|
1178 g.fillRect(0, 0, w, h); |
|
1179 |
|
1180 g.setColor(Color.black); |
|
1181 g.drawLine(0, h-1, w-1, h-1); |
|
1182 g.drawLine(w-1, 0, w-1, h-1); |
|
1183 |
|
1184 g.setColor(highlightColor); |
|
1185 g.drawLine(0, 0, 0, h-2); |
|
1186 g.drawLine(1, 0, w-2, 0); |
|
1187 |
|
1188 g.setColor(shadowColor); |
|
1189 g.drawLine(1, h-2, w-2, h-2); |
|
1190 g.drawLine(w-2, 1, w-2, h-3); |
|
1191 } |
|
1192 else if ( slider.getOrientation() == JSlider.HORIZONTAL ) { |
|
1193 int cw = w / 2; |
|
1194 g.fillRect(1, 1, w-3, h-1-cw); |
|
1195 Polygon p = new Polygon(); |
|
1196 p.addPoint(1, h-cw); |
|
1197 p.addPoint(cw-1, h-1); |
|
1198 p.addPoint(w-2, h-1-cw); |
|
1199 g.fillPolygon(p); |
|
1200 |
|
1201 g.setColor(highlightColor); |
|
1202 g.drawLine(0, 0, w-2, 0); |
|
1203 g.drawLine(0, 1, 0, h-1-cw); |
|
1204 g.drawLine(0, h-cw, cw-1, h-1); |
|
1205 |
|
1206 g.setColor(Color.black); |
|
1207 g.drawLine(w-1, 0, w-1, h-2-cw); |
|
1208 g.drawLine(w-1, h-1-cw, w-1-cw, h-1); |
|
1209 |
|
1210 g.setColor(shadowColor); |
|
1211 g.drawLine(w-2, 1, w-2, h-2-cw); |
|
1212 g.drawLine(w-2, h-1-cw, w-1-cw, h-2); |
|
1213 } |
|
1214 else { // vertical |
|
1215 int cw = h / 2; |
|
1216 if(BasicGraphicsUtils.isLeftToRight(slider)) { |
|
1217 g.fillRect(1, 1, w-1-cw, h-3); |
|
1218 Polygon p = new Polygon(); |
|
1219 p.addPoint(w-cw-1, 0); |
|
1220 p.addPoint(w-1, cw); |
|
1221 p.addPoint(w-1-cw, h-2); |
|
1222 g.fillPolygon(p); |
|
1223 |
|
1224 g.setColor(highlightColor); |
|
1225 g.drawLine(0, 0, 0, h - 2); // left |
|
1226 g.drawLine(1, 0, w-1-cw, 0); // top |
|
1227 g.drawLine(w-cw-1, 0, w-1, cw); // top slant |
|
1228 |
|
1229 g.setColor(Color.black); |
|
1230 g.drawLine(0, h-1, w-2-cw, h-1); // bottom |
|
1231 g.drawLine(w-1-cw, h-1, w-1, h-1-cw); // bottom slant |
|
1232 |
|
1233 g.setColor(shadowColor); |
|
1234 g.drawLine(1, h-2, w-2-cw, h-2 ); // bottom |
|
1235 g.drawLine(w-1-cw, h-2, w-2, h-cw-1 ); // bottom slant |
|
1236 } |
|
1237 else { |
|
1238 g.fillRect(5, 1, w-1-cw, h-3); |
|
1239 Polygon p = new Polygon(); |
|
1240 p.addPoint(cw, 0); |
|
1241 p.addPoint(0, cw); |
|
1242 p.addPoint(cw, h-2); |
|
1243 g.fillPolygon(p); |
|
1244 |
|
1245 g.setColor(highlightColor); |
|
1246 g.drawLine(cw-1, 0, w-2, 0); // top |
|
1247 g.drawLine(0, cw, cw, 0); // top slant |
|
1248 |
|
1249 g.setColor(Color.black); |
|
1250 g.drawLine(0, h-1-cw, cw, h-1 ); // bottom slant |
|
1251 g.drawLine(cw, h-1, w-1, h-1); // bottom |
|
1252 |
|
1253 g.setColor(shadowColor); |
|
1254 g.drawLine(cw, h-2, w-2, h-2 ); // bottom |
|
1255 g.drawLine(w-1, 1, w-1, h-2 ); // right |
|
1256 } |
|
1257 } |
|
1258 |
|
1259 g.translate(-knobBounds.x, -knobBounds.y); |
|
1260 } |
|
1261 |
|
1262 // Used exclusively by setThumbLocation() |
|
1263 private static Rectangle unionRect = new Rectangle(); |
|
1264 |
|
1265 public void setThumbLocation(int x, int y) { |
|
1266 unionRect.setBounds( thumbRect ); |
|
1267 |
|
1268 thumbRect.setLocation( x, y ); |
|
1269 |
|
1270 SwingUtilities.computeUnion( thumbRect.x, thumbRect.y, thumbRect.width, thumbRect.height, unionRect ); |
|
1271 slider.repaint( unionRect.x, unionRect.y, unionRect.width, unionRect.height ); |
|
1272 } |
|
1273 |
|
1274 public void scrollByBlock(int direction) { |
|
1275 synchronized(slider) { |
|
1276 |
|
1277 int oldValue = slider.getValue(); |
|
1278 int blockIncrement = |
|
1279 (slider.getMaximum() - slider.getMinimum()) / 10; |
|
1280 if (blockIncrement <= 0 && |
|
1281 slider.getMaximum() > slider.getMinimum()) { |
|
1282 |
|
1283 blockIncrement = 1; |
|
1284 } |
|
1285 |
|
1286 int delta = blockIncrement * ((direction > 0) ? POSITIVE_SCROLL : NEGATIVE_SCROLL); |
|
1287 slider.setValue(oldValue + delta); |
|
1288 } |
|
1289 } |
|
1290 |
|
1291 public void scrollByUnit(int direction) { |
|
1292 synchronized(slider) { |
|
1293 |
|
1294 int oldValue = slider.getValue(); |
|
1295 int delta = 1 * ((direction > 0) ? POSITIVE_SCROLL : NEGATIVE_SCROLL); |
|
1296 |
|
1297 slider.setValue(oldValue + delta); |
|
1298 } |
|
1299 } |
|
1300 |
|
1301 /** |
|
1302 * This function is called when a mousePressed was detected in the track, not |
|
1303 * in the thumb. The default behavior is to scroll by block. You can |
|
1304 * override this method to stop it from scrolling or to add additional behavior. |
|
1305 */ |
|
1306 protected void scrollDueToClickInTrack( int dir ) { |
|
1307 scrollByBlock( dir ); |
|
1308 } |
|
1309 |
|
1310 protected int xPositionForValue( int value ) { |
|
1311 int min = slider.getMinimum(); |
|
1312 int max = slider.getMaximum(); |
|
1313 int trackLength = trackRect.width; |
|
1314 double valueRange = (double)max - (double)min; |
|
1315 double pixelsPerValue = (double)trackLength / valueRange; |
|
1316 int trackLeft = trackRect.x; |
|
1317 int trackRight = trackRect.x + (trackRect.width - 1); |
|
1318 int xPosition; |
|
1319 |
|
1320 if ( !drawInverted() ) { |
|
1321 xPosition = trackLeft; |
|
1322 xPosition += Math.round( pixelsPerValue * ((double)value - min) ); |
|
1323 } |
|
1324 else { |
|
1325 xPosition = trackRight; |
|
1326 xPosition -= Math.round( pixelsPerValue * ((double)value - min) ); |
|
1327 } |
|
1328 |
|
1329 xPosition = Math.max( trackLeft, xPosition ); |
|
1330 xPosition = Math.min( trackRight, xPosition ); |
|
1331 |
|
1332 return xPosition; |
|
1333 } |
|
1334 |
|
1335 protected int yPositionForValue( int value ) { |
|
1336 return yPositionForValue(value, trackRect.y, trackRect.height); |
|
1337 } |
|
1338 |
|
1339 /** |
|
1340 * Returns the y location for the specified value. No checking is |
|
1341 * done on the arguments. In particular if <code>trackHeight</code> is |
|
1342 * negative undefined results may occur. |
|
1343 * |
|
1344 * @param value the slider value to get the location for |
|
1345 * @param trackY y-origin of the track |
|
1346 * @param trackHeight the height of the track |
|
1347 * @since 1.6 |
|
1348 */ |
|
1349 protected int yPositionForValue(int value, int trackY, int trackHeight) { |
|
1350 int min = slider.getMinimum(); |
|
1351 int max = slider.getMaximum(); |
|
1352 double valueRange = (double)max - (double)min; |
|
1353 double pixelsPerValue = (double)trackHeight / (double)valueRange; |
|
1354 int trackBottom = trackY + (trackHeight - 1); |
|
1355 int yPosition; |
|
1356 |
|
1357 if ( !drawInverted() ) { |
|
1358 yPosition = trackY; |
|
1359 yPosition += Math.round( pixelsPerValue * ((double)max - value ) ); |
|
1360 } |
|
1361 else { |
|
1362 yPosition = trackY; |
|
1363 yPosition += Math.round( pixelsPerValue * ((double)value - min) ); |
|
1364 } |
|
1365 |
|
1366 yPosition = Math.max( trackY, yPosition ); |
|
1367 yPosition = Math.min( trackBottom, yPosition ); |
|
1368 |
|
1369 return yPosition; |
|
1370 } |
|
1371 |
|
1372 /** |
|
1373 * Returns a value give a y position. If yPos is past the track at the top or the |
|
1374 * bottom it will set the value to the min or max of the slider, depending if the |
|
1375 * slider is inverted or not. |
|
1376 */ |
|
1377 public int valueForYPosition( int yPos ) { |
|
1378 int value; |
|
1379 final int minValue = slider.getMinimum(); |
|
1380 final int maxValue = slider.getMaximum(); |
|
1381 final int trackLength = trackRect.height; |
|
1382 final int trackTop = trackRect.y; |
|
1383 final int trackBottom = trackRect.y + (trackRect.height - 1); |
|
1384 |
|
1385 if ( yPos <= trackTop ) { |
|
1386 value = drawInverted() ? minValue : maxValue; |
|
1387 } |
|
1388 else if ( yPos >= trackBottom ) { |
|
1389 value = drawInverted() ? maxValue : minValue; |
|
1390 } |
|
1391 else { |
|
1392 int distanceFromTrackTop = yPos - trackTop; |
|
1393 double valueRange = (double)maxValue - (double)minValue; |
|
1394 double valuePerPixel = valueRange / (double)trackLength; |
|
1395 int valueFromTrackTop = (int)Math.round( distanceFromTrackTop * valuePerPixel ); |
|
1396 |
|
1397 value = drawInverted() ? minValue + valueFromTrackTop : maxValue - valueFromTrackTop; |
|
1398 } |
|
1399 |
|
1400 return value; |
|
1401 } |
|
1402 |
|
1403 /** |
|
1404 * Returns a value give an x position. If xPos is past the track at the left or the |
|
1405 * right it will set the value to the min or max of the slider, depending if the |
|
1406 * slider is inverted or not. |
|
1407 */ |
|
1408 public int valueForXPosition( int xPos ) { |
|
1409 int value; |
|
1410 final int minValue = slider.getMinimum(); |
|
1411 final int maxValue = slider.getMaximum(); |
|
1412 final int trackLength = trackRect.width; |
|
1413 final int trackLeft = trackRect.x; |
|
1414 final int trackRight = trackRect.x + (trackRect.width - 1); |
|
1415 |
|
1416 if ( xPos <= trackLeft ) { |
|
1417 value = drawInverted() ? maxValue : minValue; |
|
1418 } |
|
1419 else if ( xPos >= trackRight ) { |
|
1420 value = drawInverted() ? minValue : maxValue; |
|
1421 } |
|
1422 else { |
|
1423 int distanceFromTrackLeft = xPos - trackLeft; |
|
1424 double valueRange = (double)maxValue - (double)minValue; |
|
1425 double valuePerPixel = valueRange / (double)trackLength; |
|
1426 int valueFromTrackLeft = (int)Math.round( distanceFromTrackLeft * valuePerPixel ); |
|
1427 |
|
1428 value = drawInverted() ? maxValue - valueFromTrackLeft : |
|
1429 minValue + valueFromTrackLeft; |
|
1430 } |
|
1431 |
|
1432 return value; |
|
1433 } |
|
1434 |
|
1435 |
|
1436 private class Handler implements ChangeListener, |
|
1437 ComponentListener, FocusListener, PropertyChangeListener { |
|
1438 // Change Handler |
|
1439 public void stateChanged(ChangeEvent e) { |
|
1440 if (!isDragging) { |
|
1441 calculateThumbLocation(); |
|
1442 slider.repaint(); |
|
1443 } |
|
1444 lastValue = slider.getValue(); |
|
1445 } |
|
1446 |
|
1447 // Component Handler |
|
1448 public void componentHidden(ComponentEvent e) { } |
|
1449 public void componentMoved(ComponentEvent e) { } |
|
1450 public void componentResized(ComponentEvent e) { |
|
1451 calculateGeometry(); |
|
1452 slider.repaint(); |
|
1453 } |
|
1454 public void componentShown(ComponentEvent e) { } |
|
1455 |
|
1456 // Focus Handler |
|
1457 public void focusGained(FocusEvent e) { slider.repaint(); } |
|
1458 public void focusLost(FocusEvent e) { slider.repaint(); } |
|
1459 |
|
1460 // Property Change Handler |
|
1461 public void propertyChange(PropertyChangeEvent e) { |
|
1462 String propertyName = e.getPropertyName(); |
|
1463 if (propertyName == "orientation" || |
|
1464 propertyName == "inverted" || |
|
1465 propertyName == "labelTable" || |
|
1466 propertyName == "majorTickSpacing" || |
|
1467 propertyName == "minorTickSpacing" || |
|
1468 propertyName == "paintTicks" || |
|
1469 propertyName == "paintTrack" || |
|
1470 propertyName == "font" || |
|
1471 propertyName == "paintLabels") { |
|
1472 checkedLabelBaselines = false; |
|
1473 calculateGeometry(); |
|
1474 slider.repaint(); |
|
1475 } else if (propertyName == "componentOrientation") { |
|
1476 calculateGeometry(); |
|
1477 slider.repaint(); |
|
1478 InputMap km = getInputMap(JComponent.WHEN_FOCUSED, slider); |
|
1479 SwingUtilities.replaceUIInputMap(slider, |
|
1480 JComponent.WHEN_FOCUSED, km); |
|
1481 } else if (propertyName == "model") { |
|
1482 ((BoundedRangeModel)e.getOldValue()).removeChangeListener( |
|
1483 changeListener); |
|
1484 ((BoundedRangeModel)e.getNewValue()).addChangeListener( |
|
1485 changeListener); |
|
1486 calculateThumbLocation(); |
|
1487 slider.repaint(); |
|
1488 } |
|
1489 } |
|
1490 } |
|
1491 |
|
1492 ///////////////////////////////////////////////////////////////////////// |
|
1493 /// Model Listener Class |
|
1494 ///////////////////////////////////////////////////////////////////////// |
|
1495 /** |
|
1496 * Data model listener. |
|
1497 * |
|
1498 * This class should be treated as a "protected" inner class. |
|
1499 * Instantiate it only within subclasses of <Foo>. |
|
1500 */ |
|
1501 public class ChangeHandler implements ChangeListener { |
|
1502 // NOTE: This class exists only for backward compatability. All |
|
1503 // its functionality has been moved into Handler. If you need to add |
|
1504 // new functionality add it to the Handler, but make sure this |
|
1505 // class calls into the Handler. |
|
1506 public void stateChanged(ChangeEvent e) { |
|
1507 getHandler().stateChanged(e); |
|
1508 } |
|
1509 } |
|
1510 |
|
1511 ///////////////////////////////////////////////////////////////////////// |
|
1512 /// Track Listener Class |
|
1513 ///////////////////////////////////////////////////////////////////////// |
|
1514 /** |
|
1515 * Track mouse movements. |
|
1516 * |
|
1517 * This class should be treated as a "protected" inner class. |
|
1518 * Instantiate it only within subclasses of <Foo>. |
|
1519 */ |
|
1520 public class TrackListener extends MouseInputAdapter { |
|
1521 protected transient int offset; |
|
1522 protected transient int currentMouseX, currentMouseY; |
|
1523 |
|
1524 public void mouseReleased(MouseEvent e) { |
|
1525 if (!slider.isEnabled()) { |
|
1526 return; |
|
1527 } |
|
1528 |
|
1529 offset = 0; |
|
1530 scrollTimer.stop(); |
|
1531 |
|
1532 // This is the way we have to determine snap-to-ticks. It's |
|
1533 // hard to explain but since ChangeEvents don't give us any |
|
1534 // idea what has changed we don't have a way to stop the thumb |
|
1535 // bounds from being recalculated. Recalculating the thumb |
|
1536 // bounds moves the thumb over the current value (i.e., snapping |
|
1537 // to the ticks). |
|
1538 if (slider.getSnapToTicks() /*|| slider.getSnapToValue()*/ ) { |
|
1539 isDragging = false; |
|
1540 slider.setValueIsAdjusting(false); |
|
1541 } |
|
1542 else { |
|
1543 slider.setValueIsAdjusting(false); |
|
1544 isDragging = false; |
|
1545 } |
|
1546 slider.repaint(); |
|
1547 } |
|
1548 |
|
1549 /** |
|
1550 * If the mouse is pressed above the "thumb" component |
|
1551 * then reduce the scrollbars value by one page ("page up"), |
|
1552 * otherwise increase it by one page. If there is no |
|
1553 * thumb then page up if the mouse is in the upper half |
|
1554 * of the track. |
|
1555 */ |
|
1556 public void mousePressed(MouseEvent e) { |
|
1557 if (!slider.isEnabled()) { |
|
1558 return; |
|
1559 } |
|
1560 |
|
1561 // We should recalculate geometry just before |
|
1562 // calculation of the thumb movement direction. |
|
1563 // It is important for the case, when JSlider |
|
1564 // is a cell editor in JTable. See 6348946. |
|
1565 calculateGeometry(); |
|
1566 |
|
1567 currentMouseX = e.getX(); |
|
1568 currentMouseY = e.getY(); |
|
1569 |
|
1570 if (slider.isRequestFocusEnabled()) { |
|
1571 slider.requestFocus(); |
|
1572 } |
|
1573 |
|
1574 // Clicked in the Thumb area? |
|
1575 if (thumbRect.contains(currentMouseX, currentMouseY)) { |
|
1576 switch (slider.getOrientation()) { |
|
1577 case JSlider.VERTICAL: |
|
1578 offset = currentMouseY - thumbRect.y; |
|
1579 break; |
|
1580 case JSlider.HORIZONTAL: |
|
1581 offset = currentMouseX - thumbRect.x; |
|
1582 break; |
|
1583 } |
|
1584 isDragging = true; |
|
1585 return; |
|
1586 } |
|
1587 isDragging = false; |
|
1588 slider.setValueIsAdjusting(true); |
|
1589 |
|
1590 Dimension sbSize = slider.getSize(); |
|
1591 int direction = POSITIVE_SCROLL; |
|
1592 |
|
1593 switch (slider.getOrientation()) { |
|
1594 case JSlider.VERTICAL: |
|
1595 if ( thumbRect.isEmpty() ) { |
|
1596 int scrollbarCenter = sbSize.height / 2; |
|
1597 if ( !drawInverted() ) { |
|
1598 direction = (currentMouseY < scrollbarCenter) ? |
|
1599 POSITIVE_SCROLL : NEGATIVE_SCROLL; |
|
1600 } |
|
1601 else { |
|
1602 direction = (currentMouseY < scrollbarCenter) ? |
|
1603 NEGATIVE_SCROLL : POSITIVE_SCROLL; |
|
1604 } |
|
1605 } |
|
1606 else { |
|
1607 int thumbY = thumbRect.y; |
|
1608 if ( !drawInverted() ) { |
|
1609 direction = (currentMouseY < thumbY) ? |
|
1610 POSITIVE_SCROLL : NEGATIVE_SCROLL; |
|
1611 } |
|
1612 else { |
|
1613 direction = (currentMouseY < thumbY) ? |
|
1614 NEGATIVE_SCROLL : POSITIVE_SCROLL; |
|
1615 } |
|
1616 } |
|
1617 break; |
|
1618 case JSlider.HORIZONTAL: |
|
1619 if ( thumbRect.isEmpty() ) { |
|
1620 int scrollbarCenter = sbSize.width / 2; |
|
1621 if ( !drawInverted() ) { |
|
1622 direction = (currentMouseX < scrollbarCenter) ? |
|
1623 NEGATIVE_SCROLL : POSITIVE_SCROLL; |
|
1624 } |
|
1625 else { |
|
1626 direction = (currentMouseX < scrollbarCenter) ? |
|
1627 POSITIVE_SCROLL : NEGATIVE_SCROLL; |
|
1628 } |
|
1629 } |
|
1630 else { |
|
1631 int thumbX = thumbRect.x; |
|
1632 if ( !drawInverted() ) { |
|
1633 direction = (currentMouseX < thumbX) ? |
|
1634 NEGATIVE_SCROLL : POSITIVE_SCROLL; |
|
1635 } |
|
1636 else { |
|
1637 direction = (currentMouseX < thumbX) ? |
|
1638 POSITIVE_SCROLL : NEGATIVE_SCROLL; |
|
1639 } |
|
1640 } |
|
1641 break; |
|
1642 } |
|
1643 |
|
1644 if (shouldScroll(direction)) { |
|
1645 scrollDueToClickInTrack(direction); |
|
1646 } |
|
1647 if (shouldScroll(direction)) { |
|
1648 scrollTimer.stop(); |
|
1649 scrollListener.setDirection(direction); |
|
1650 scrollTimer.start(); |
|
1651 } |
|
1652 } |
|
1653 |
|
1654 public boolean shouldScroll(int direction) { |
|
1655 Rectangle r = thumbRect; |
|
1656 if (slider.getOrientation() == JSlider.VERTICAL) { |
|
1657 if (drawInverted() ? direction < 0 : direction > 0) { |
|
1658 if (r.y <= currentMouseY) { |
|
1659 return false; |
|
1660 } |
|
1661 } |
|
1662 else if (r.y + r.height >= currentMouseY) { |
|
1663 return false; |
|
1664 } |
|
1665 } |
|
1666 else { |
|
1667 if (drawInverted() ? direction < 0 : direction > 0) { |
|
1668 if (r.x + r.width >= currentMouseX) { |
|
1669 return false; |
|
1670 } |
|
1671 } |
|
1672 else if (r.x <= currentMouseX) { |
|
1673 return false; |
|
1674 } |
|
1675 } |
|
1676 |
|
1677 if (direction > 0 && slider.getValue() + slider.getExtent() >= |
|
1678 slider.getMaximum()) { |
|
1679 return false; |
|
1680 } |
|
1681 else if (direction < 0 && slider.getValue() <= |
|
1682 slider.getMinimum()) { |
|
1683 return false; |
|
1684 } |
|
1685 |
|
1686 return true; |
|
1687 } |
|
1688 |
|
1689 /** |
|
1690 * Set the models value to the position of the top/left |
|
1691 * of the thumb relative to the origin of the track. |
|
1692 */ |
|
1693 public void mouseDragged(MouseEvent e) { |
|
1694 int thumbMiddle = 0; |
|
1695 |
|
1696 if (!slider.isEnabled()) { |
|
1697 return; |
|
1698 } |
|
1699 |
|
1700 currentMouseX = e.getX(); |
|
1701 currentMouseY = e.getY(); |
|
1702 |
|
1703 if (!isDragging) { |
|
1704 return; |
|
1705 } |
|
1706 |
|
1707 slider.setValueIsAdjusting(true); |
|
1708 |
|
1709 switch (slider.getOrientation()) { |
|
1710 case JSlider.VERTICAL: |
|
1711 int halfThumbHeight = thumbRect.height / 2; |
|
1712 int thumbTop = e.getY() - offset; |
|
1713 int trackTop = trackRect.y; |
|
1714 int trackBottom = trackRect.y + (trackRect.height - 1); |
|
1715 int vMax = yPositionForValue(slider.getMaximum() - |
|
1716 slider.getExtent()); |
|
1717 |
|
1718 if (drawInverted()) { |
|
1719 trackBottom = vMax; |
|
1720 } |
|
1721 else { |
|
1722 trackTop = vMax; |
|
1723 } |
|
1724 thumbTop = Math.max(thumbTop, trackTop - halfThumbHeight); |
|
1725 thumbTop = Math.min(thumbTop, trackBottom - halfThumbHeight); |
|
1726 |
|
1727 setThumbLocation(thumbRect.x, thumbTop); |
|
1728 |
|
1729 thumbMiddle = thumbTop + halfThumbHeight; |
|
1730 slider.setValue( valueForYPosition( thumbMiddle ) ); |
|
1731 break; |
|
1732 case JSlider.HORIZONTAL: |
|
1733 int halfThumbWidth = thumbRect.width / 2; |
|
1734 int thumbLeft = e.getX() - offset; |
|
1735 int trackLeft = trackRect.x; |
|
1736 int trackRight = trackRect.x + (trackRect.width - 1); |
|
1737 int hMax = xPositionForValue(slider.getMaximum() - |
|
1738 slider.getExtent()); |
|
1739 |
|
1740 if (drawInverted()) { |
|
1741 trackLeft = hMax; |
|
1742 } |
|
1743 else { |
|
1744 trackRight = hMax; |
|
1745 } |
|
1746 thumbLeft = Math.max(thumbLeft, trackLeft - halfThumbWidth); |
|
1747 thumbLeft = Math.min(thumbLeft, trackRight - halfThumbWidth); |
|
1748 |
|
1749 setThumbLocation(thumbLeft, thumbRect.y); |
|
1750 |
|
1751 thumbMiddle = thumbLeft + halfThumbWidth; |
|
1752 slider.setValue(valueForXPosition(thumbMiddle)); |
|
1753 break; |
|
1754 default: |
|
1755 return; |
|
1756 } |
|
1757 } |
|
1758 |
|
1759 public void mouseMoved(MouseEvent e) { } |
|
1760 } |
|
1761 |
|
1762 /** |
|
1763 * Scroll-event listener. |
|
1764 * |
|
1765 * This class should be treated as a "protected" inner class. |
|
1766 * Instantiate it only within subclasses of <Foo>. |
|
1767 */ |
|
1768 public class ScrollListener implements ActionListener { |
|
1769 // changed this class to public to avoid bogus IllegalAccessException |
|
1770 // bug in InternetExplorer browser. It was protected. Work around |
|
1771 // for 4109432 |
|
1772 int direction = POSITIVE_SCROLL; |
|
1773 boolean useBlockIncrement; |
|
1774 |
|
1775 public ScrollListener() { |
|
1776 direction = POSITIVE_SCROLL; |
|
1777 useBlockIncrement = true; |
|
1778 } |
|
1779 |
|
1780 public ScrollListener(int dir, boolean block) { |
|
1781 direction = dir; |
|
1782 useBlockIncrement = block; |
|
1783 } |
|
1784 |
|
1785 public void setDirection(int direction) { |
|
1786 this.direction = direction; |
|
1787 } |
|
1788 |
|
1789 public void setScrollByBlock(boolean block) { |
|
1790 this.useBlockIncrement = block; |
|
1791 } |
|
1792 |
|
1793 public void actionPerformed(ActionEvent e) { |
|
1794 if (useBlockIncrement) { |
|
1795 scrollByBlock(direction); |
|
1796 } |
|
1797 else { |
|
1798 scrollByUnit(direction); |
|
1799 } |
|
1800 if (!trackListener.shouldScroll(direction)) { |
|
1801 ((Timer)e.getSource()).stop(); |
|
1802 } |
|
1803 } |
|
1804 } |
|
1805 |
|
1806 /** |
|
1807 * Listener for resizing events. |
|
1808 * <p> |
|
1809 * This class should be treated as a "protected" inner class. |
|
1810 * Instantiate it only within subclasses of <Foo>. |
|
1811 */ |
|
1812 public class ComponentHandler extends ComponentAdapter { |
|
1813 // NOTE: This class exists only for backward compatability. All |
|
1814 // its functionality has been moved into Handler. If you need to add |
|
1815 // new functionality add it to the Handler, but make sure this |
|
1816 // class calls into the Handler. |
|
1817 public void componentResized(ComponentEvent e) { |
|
1818 getHandler().componentResized(e); |
|
1819 } |
|
1820 }; |
|
1821 |
|
1822 /** |
|
1823 * Focus-change listener. |
|
1824 * <p> |
|
1825 * This class should be treated as a "protected" inner class. |
|
1826 * Instantiate it only within subclasses of <Foo>. |
|
1827 */ |
|
1828 public class FocusHandler implements FocusListener { |
|
1829 // NOTE: This class exists only for backward compatability. All |
|
1830 // its functionality has been moved into Handler. If you need to add |
|
1831 // new functionality add it to the Handler, but make sure this |
|
1832 // class calls into the Handler. |
|
1833 public void focusGained(FocusEvent e) { |
|
1834 getHandler().focusGained(e); |
|
1835 } |
|
1836 |
|
1837 public void focusLost(FocusEvent e) { |
|
1838 getHandler().focusLost(e); |
|
1839 } |
|
1840 } |
|
1841 |
|
1842 /** |
|
1843 * As of Java 2 platform v1.3 this undocumented class is no longer used. |
|
1844 * The recommended approach to creating bindings is to use a |
|
1845 * combination of an <code>ActionMap</code>, to contain the action, |
|
1846 * and an <code>InputMap</code> to contain the mapping from KeyStroke |
|
1847 * to action description. The InputMap is is usually described in the |
|
1848 * LookAndFeel tables. |
|
1849 * <p> |
|
1850 * Please refer to the key bindings specification for further details. |
|
1851 * <p> |
|
1852 * This class should be treated as a "protected" inner class. |
|
1853 * Instantiate it only within subclasses of <Foo>. |
|
1854 */ |
|
1855 public class ActionScroller extends AbstractAction { |
|
1856 // NOTE: This class exists only for backward compatability. All |
|
1857 // its functionality has been moved into Actions. If you need to add |
|
1858 // new functionality add it to the Actions, but make sure this |
|
1859 // class calls into the Actions. |
|
1860 int dir; |
|
1861 boolean block; |
|
1862 JSlider slider; |
|
1863 |
|
1864 public ActionScroller( JSlider slider, int dir, boolean block) { |
|
1865 this.dir = dir; |
|
1866 this.block = block; |
|
1867 this.slider = slider; |
|
1868 } |
|
1869 |
|
1870 public void actionPerformed(ActionEvent e) { |
|
1871 SHARED_ACTION.scroll(slider, BasicSliderUI.this, dir, block); |
|
1872 } |
|
1873 |
|
1874 public boolean isEnabled() { |
|
1875 boolean b = true; |
|
1876 if (slider != null) { |
|
1877 b = slider.isEnabled(); |
|
1878 } |
|
1879 return b; |
|
1880 } |
|
1881 |
|
1882 }; |
|
1883 |
|
1884 |
|
1885 /** |
|
1886 * A static version of the above. |
|
1887 */ |
|
1888 static class SharedActionScroller extends AbstractAction { |
|
1889 // NOTE: This class exists only for backward compatability. All |
|
1890 // its functionality has been moved into Actions. If you need to add |
|
1891 // new functionality add it to the Actions, but make sure this |
|
1892 // class calls into the Actions. |
|
1893 int dir; |
|
1894 boolean block; |
|
1895 |
|
1896 public SharedActionScroller(int dir, boolean block) { |
|
1897 this.dir = dir; |
|
1898 this.block = block; |
|
1899 } |
|
1900 |
|
1901 public void actionPerformed(ActionEvent evt) { |
|
1902 JSlider slider = (JSlider)evt.getSource(); |
|
1903 BasicSliderUI ui = (BasicSliderUI)BasicLookAndFeel.getUIOfType( |
|
1904 slider.getUI(), BasicSliderUI.class); |
|
1905 if (ui == null) { |
|
1906 return; |
|
1907 } |
|
1908 SHARED_ACTION.scroll(slider, ui, dir, block); |
|
1909 } |
|
1910 } |
|
1911 |
|
1912 private static class Actions extends UIAction { |
|
1913 public static final String POSITIVE_UNIT_INCREMENT = |
|
1914 "positiveUnitIncrement"; |
|
1915 public static final String POSITIVE_BLOCK_INCREMENT = |
|
1916 "positiveBlockIncrement"; |
|
1917 public static final String NEGATIVE_UNIT_INCREMENT = |
|
1918 "negativeUnitIncrement"; |
|
1919 public static final String NEGATIVE_BLOCK_INCREMENT = |
|
1920 "negativeBlockIncrement"; |
|
1921 public static final String MIN_SCROLL_INCREMENT = "minScroll"; |
|
1922 public static final String MAX_SCROLL_INCREMENT = "maxScroll"; |
|
1923 |
|
1924 |
|
1925 Actions() { |
|
1926 super(null); |
|
1927 } |
|
1928 |
|
1929 public Actions(String name) { |
|
1930 super(name); |
|
1931 } |
|
1932 |
|
1933 public void actionPerformed(ActionEvent evt) { |
|
1934 JSlider slider = (JSlider)evt.getSource(); |
|
1935 BasicSliderUI ui = (BasicSliderUI)BasicLookAndFeel.getUIOfType( |
|
1936 slider.getUI(), BasicSliderUI.class); |
|
1937 String name = getName(); |
|
1938 |
|
1939 if (ui == null) { |
|
1940 return; |
|
1941 } |
|
1942 if (POSITIVE_UNIT_INCREMENT == name) { |
|
1943 scroll(slider, ui, POSITIVE_SCROLL, false); |
|
1944 } else if (NEGATIVE_UNIT_INCREMENT == name) { |
|
1945 scroll(slider, ui, NEGATIVE_SCROLL, false); |
|
1946 } else if (POSITIVE_BLOCK_INCREMENT == name) { |
|
1947 scroll(slider, ui, POSITIVE_SCROLL, true); |
|
1948 } else if (NEGATIVE_BLOCK_INCREMENT == name) { |
|
1949 scroll(slider, ui, NEGATIVE_SCROLL, true); |
|
1950 } else if (MIN_SCROLL_INCREMENT == name) { |
|
1951 scroll(slider, ui, MIN_SCROLL, false); |
|
1952 } else if (MAX_SCROLL_INCREMENT == name) { |
|
1953 scroll(slider, ui, MAX_SCROLL, false); |
|
1954 } |
|
1955 } |
|
1956 |
|
1957 private void scroll(JSlider slider, BasicSliderUI ui, int direction, |
|
1958 boolean isBlock) { |
|
1959 boolean invert = slider.getInverted(); |
|
1960 |
|
1961 if (direction == NEGATIVE_SCROLL || direction == POSITIVE_SCROLL) { |
|
1962 if (invert) { |
|
1963 direction = (direction == POSITIVE_SCROLL) ? |
|
1964 NEGATIVE_SCROLL : POSITIVE_SCROLL; |
|
1965 } |
|
1966 |
|
1967 if (isBlock) { |
|
1968 ui.scrollByBlock(direction); |
|
1969 } else { |
|
1970 ui.scrollByUnit(direction); |
|
1971 } |
|
1972 } else { // MIN or MAX |
|
1973 if (invert) { |
|
1974 direction = (direction == MIN_SCROLL) ? |
|
1975 MAX_SCROLL : MIN_SCROLL; |
|
1976 } |
|
1977 |
|
1978 slider.setValue((direction == MIN_SCROLL) ? |
|
1979 slider.getMinimum() : slider.getMaximum()); |
|
1980 } |
|
1981 } |
|
1982 } |
|
1983 } |