1. /*
  2. * @(#)BasicSliderUI.java 1.75 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing.plaf.basic;
  8. import java.awt.Component;
  9. import java.awt.Container;
  10. import java.awt.Adjustable;
  11. import java.awt.event.*;
  12. import java.awt.Graphics;
  13. import java.awt.Dimension;
  14. import java.awt.Rectangle;
  15. import java.awt.Point;
  16. import java.awt.Insets;
  17. import java.awt.Color;
  18. import java.awt.IllegalComponentStateException;
  19. import java.awt.Polygon;
  20. import java.beans.*;
  21. import java.util.*;
  22. import javax.swing.border.AbstractBorder;
  23. import javax.swing.*;
  24. import javax.swing.event.*;
  25. import javax.swing.plaf.*;
  26. /**
  27. * A Basic L&F implementation of SliderUI.
  28. *
  29. * @version 1.75 11/29/01
  30. * @author Tom Santos
  31. */
  32. public class BasicSliderUI extends SliderUI{
  33. public final int POSITIVE_SCROLL = +1;
  34. public final int NEGATIVE_SCROLL = -1;
  35. public final int MIN_SCROLL = -2;
  36. public final int MAX_SCROLL = +2;
  37. protected Timer scrollTimer;
  38. protected JSlider slider;
  39. protected Insets focusInsets = null;
  40. protected Insets insetCache = null;
  41. protected Rectangle focusRect = null;
  42. protected Rectangle contentRect = null;
  43. protected Rectangle labelRect = null;
  44. protected Rectangle tickRect = null;
  45. protected Rectangle trackRect = null;
  46. protected Rectangle thumbRect = null;
  47. protected int trackBuffer = 0; // The distance that the track is from the side of the control
  48. private static final Dimension PREFERRED_HORIZONTAL_SIZE = new Dimension(200, 21);
  49. private static final Dimension PREFERRED_VERTICAL_SIZE = new Dimension(21, 200);
  50. private static final Dimension MINIMUM_HORIZONTAL_SIZE = new Dimension(36, 21);
  51. private static final Dimension MINIMUM_VERTICAL_SIZE = new Dimension(21, 36);
  52. private transient boolean isDragging;
  53. protected TrackListener trackListener;
  54. protected ChangeListener changeListener;
  55. protected ComponentListener componentListener;
  56. protected FocusListener focusListener;
  57. protected ScrollListener scrollListener;
  58. protected PropertyChangeListener propertyChangeListener;
  59. // Colors
  60. private Color shadowColor;
  61. private Color highlightColor;
  62. private Color focusColor;
  63. protected Color getShadowColor() {
  64. return shadowColor;
  65. }
  66. protected Color getHighlightColor() {
  67. return highlightColor;
  68. }
  69. protected Color getFocusColor() {
  70. return focusColor;
  71. }
  72. /////////////////////////////////////////////////////////////////////////////
  73. // ComponentUI Interface Implementation methods
  74. /////////////////////////////////////////////////////////////////////////////
  75. public static ComponentUI createUI(JComponent b) {
  76. return new BasicSliderUI((JSlider)b);
  77. }
  78. public BasicSliderUI(JSlider b) {
  79. }
  80. public void installUI(JComponent c) {
  81. slider = (JSlider) c;
  82. slider.setEnabled(slider.isEnabled());
  83. slider.setOpaque(true);
  84. isDragging = false;
  85. trackListener = createTrackListener( slider );
  86. changeListener = createChangeListener( slider );
  87. componentListener = createComponentListener( slider );
  88. focusListener = createFocusListener( slider );
  89. scrollListener = createScrollListener( slider );
  90. propertyChangeListener = createPropertyChangeListener( slider );
  91. installDefaults( slider );
  92. installListeners( slider );
  93. installKeyboardActions( slider );
  94. scrollTimer = new Timer( 100, scrollListener );
  95. scrollTimer.setInitialDelay( 300 );
  96. insetCache = slider.getInsets();
  97. focusRect = new Rectangle();
  98. contentRect = new Rectangle();
  99. labelRect = new Rectangle();
  100. tickRect = new Rectangle();
  101. trackRect = new Rectangle();
  102. thumbRect = new Rectangle();
  103. calculateGeometry(); // This figures out where the labels, ticks, track, and thumb are.
  104. }
  105. public void uninstallUI(JComponent c) {
  106. if ( c != slider )
  107. throw new IllegalComponentStateException(
  108. this + " was asked to deinstall() "
  109. + c + " when it only knows about "
  110. + slider + ".");
  111. LookAndFeel.uninstallBorder(slider);
  112. scrollTimer.stop();
  113. scrollTimer = null;
  114. uninstallListeners( slider );
  115. uninstallKeyboardActions(slider);
  116. focusInsets = null;
  117. insetCache = null;
  118. focusRect = null;
  119. contentRect = null;
  120. labelRect = null;
  121. tickRect = null;
  122. trackRect = null;
  123. thumbRect = null;
  124. trackListener = null;
  125. changeListener = null;
  126. componentListener = null;
  127. focusListener = null;
  128. scrollListener = null;
  129. propertyChangeListener = null;
  130. slider = null;
  131. }
  132. protected void installDefaults( JSlider slider ) {
  133. LookAndFeel.installBorder(slider, "Slider.border");
  134. LookAndFeel.installColors(slider, "Slider.background", "Slider.foreground");
  135. highlightColor = UIManager.getColor("Slider.highlight");
  136. shadowColor = UIManager.getColor("Slider.shadow");
  137. focusColor = UIManager.getColor("Slider.focus");
  138. focusInsets = (Insets)UIManager.get( "Slider.focusInsets" );
  139. }
  140. protected TrackListener createTrackListener( JSlider slider ) {
  141. return new TrackListener();
  142. }
  143. protected ChangeListener createChangeListener( JSlider slider ) {
  144. return new ChangeHandler();
  145. }
  146. protected ComponentListener createComponentListener( JSlider slider ) {
  147. return new ComponentHandler();
  148. }
  149. protected FocusListener createFocusListener( JSlider slider ) {
  150. return new FocusHandler();
  151. }
  152. protected ScrollListener createScrollListener( JSlider slider ) {
  153. return new ScrollListener();
  154. }
  155. protected PropertyChangeListener createPropertyChangeListener( JSlider slider ) {
  156. return new PropertyChangeHandler();
  157. }
  158. protected void installListeners( JSlider slider ) {
  159. slider.addMouseListener(trackListener);
  160. slider.addMouseMotionListener(trackListener);
  161. slider.addFocusListener(focusListener);
  162. slider.addComponentListener(componentListener);
  163. slider.addPropertyChangeListener( propertyChangeListener );
  164. slider.getModel().addChangeListener(changeListener);
  165. }
  166. protected void uninstallListeners( JSlider slider ) {
  167. slider.removeMouseListener(trackListener);
  168. slider.removeMouseMotionListener(trackListener);
  169. slider.removeFocusListener(focusListener);
  170. slider.removeComponentListener(componentListener);
  171. slider.removePropertyChangeListener( propertyChangeListener );
  172. slider.getModel().removeChangeListener(changeListener);
  173. }
  174. protected void installKeyboardActions( JSlider slider ) {
  175. slider.registerKeyboardAction(new ActionScroller(slider, POSITIVE_SCROLL, false),
  176. KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT,0),
  177. JComponent.WHEN_FOCUSED);
  178. slider.registerKeyboardAction(new ActionScroller(slider, POSITIVE_SCROLL, false),
  179. KeyStroke.getKeyStroke("KP_RIGHT"),
  180. JComponent.WHEN_FOCUSED);
  181. slider.registerKeyboardAction(new ActionScroller(slider, NEGATIVE_SCROLL, false),
  182. KeyStroke.getKeyStroke(KeyEvent.VK_DOWN,0),
  183. JComponent.WHEN_FOCUSED);
  184. slider.registerKeyboardAction(new ActionScroller(slider, NEGATIVE_SCROLL, false),
  185. KeyStroke.getKeyStroke("KP_DOWN"),
  186. JComponent.WHEN_FOCUSED);
  187. slider.registerKeyboardAction(new ActionScroller(slider, NEGATIVE_SCROLL, true),
  188. KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN,0),
  189. JComponent.WHEN_FOCUSED);
  190. slider.registerKeyboardAction(new ActionScroller(slider, NEGATIVE_SCROLL, false),
  191. KeyStroke.getKeyStroke(KeyEvent.VK_LEFT,0),
  192. JComponent.WHEN_FOCUSED);
  193. slider.registerKeyboardAction(new ActionScroller(slider, NEGATIVE_SCROLL, false),
  194. KeyStroke.getKeyStroke("KP_LEFT"),
  195. JComponent.WHEN_FOCUSED);
  196. slider.registerKeyboardAction(new ActionScroller(slider, POSITIVE_SCROLL, false),
  197. KeyStroke.getKeyStroke(KeyEvent.VK_UP,0),
  198. JComponent.WHEN_FOCUSED);
  199. slider.registerKeyboardAction(new ActionScroller(slider, POSITIVE_SCROLL, false),
  200. KeyStroke.getKeyStroke("KP_UP"),
  201. JComponent.WHEN_FOCUSED);
  202. slider.registerKeyboardAction(new ActionScroller(slider, POSITIVE_SCROLL, true),
  203. KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP,0),
  204. JComponent.WHEN_FOCUSED);
  205. slider.registerKeyboardAction(new ActionScroller(slider, MIN_SCROLL, true),
  206. KeyStroke.getKeyStroke(KeyEvent.VK_HOME,0),
  207. JComponent.WHEN_FOCUSED);
  208. slider.registerKeyboardAction(new ActionScroller(slider, MAX_SCROLL, true),
  209. KeyStroke.getKeyStroke(KeyEvent.VK_END,0),
  210. JComponent.WHEN_FOCUSED);
  211. }
  212. protected void uninstallKeyboardActions( JSlider slider ) {
  213. slider.unregisterKeyboardAction( KeyStroke.getKeyStroke( KeyEvent.VK_RIGHT, 0 ) );
  214. slider.unregisterKeyboardAction( KeyStroke.getKeyStroke( "KP_RIGHT" ) );
  215. slider.unregisterKeyboardAction( KeyStroke.getKeyStroke( KeyEvent.VK_DOWN, 0 ) );
  216. slider.unregisterKeyboardAction( KeyStroke.getKeyStroke( "KP_DOWN" ) );
  217. slider.unregisterKeyboardAction( KeyStroke.getKeyStroke( KeyEvent.VK_PAGE_DOWN, 0 ) );
  218. slider.unregisterKeyboardAction( KeyStroke.getKeyStroke( KeyEvent.VK_LEFT, 0 ) );
  219. slider.unregisterKeyboardAction( KeyStroke.getKeyStroke( "KP_LEFT" ) );
  220. slider.unregisterKeyboardAction( KeyStroke.getKeyStroke( KeyEvent.VK_UP, 0 ) );
  221. slider.unregisterKeyboardAction( KeyStroke.getKeyStroke( "KP_UP" ) );
  222. slider.unregisterKeyboardAction( KeyStroke.getKeyStroke( KeyEvent.VK_PAGE_UP, 0 ) );
  223. slider.unregisterKeyboardAction( KeyStroke.getKeyStroke( KeyEvent.VK_HOME, 0 ) );
  224. slider.unregisterKeyboardAction( KeyStroke.getKeyStroke( KeyEvent.VK_END, 0 ) );
  225. }
  226. public Dimension getPreferredHorizontalSize() {
  227. return PREFERRED_HORIZONTAL_SIZE;
  228. }
  229. public Dimension getPreferredVerticalSize() {
  230. return PREFERRED_VERTICAL_SIZE;
  231. }
  232. public Dimension getMinimumHorizontalSize() {
  233. return MINIMUM_HORIZONTAL_SIZE;
  234. }
  235. public Dimension getMinimumVerticalSize() {
  236. return MINIMUM_VERTICAL_SIZE;
  237. }
  238. public Dimension getPreferredSize(JComponent c) {
  239. recalculateIfInsetsChanged();
  240. Dimension d;
  241. if ( slider.getOrientation() == JSlider.VERTICAL ) {
  242. d = new Dimension(getPreferredVerticalSize());
  243. d.width = insetCache.left + insetCache.right;
  244. d.width += focusInsets.left + focusInsets.right;
  245. d.width += trackRect.width + tickRect.width + labelRect.width;
  246. }
  247. else {
  248. d = new Dimension(getPreferredHorizontalSize());
  249. d.height = insetCache.top + insetCache.bottom;
  250. d.height += focusInsets.top + focusInsets.bottom;
  251. d.height += trackRect.height + tickRect.height + labelRect.height;
  252. }
  253. return d;
  254. }
  255. public Dimension getMinimumSize(JComponent c) {
  256. recalculateIfInsetsChanged();
  257. Dimension d;
  258. if ( slider.getOrientation() == JSlider.VERTICAL ) {
  259. d = new Dimension(getMinimumVerticalSize());
  260. d.width = insetCache.left + insetCache.right;
  261. d.width += focusInsets.left + focusInsets.right;
  262. d.width += trackRect.width + tickRect.width + labelRect.width;
  263. }
  264. else {
  265. d = new Dimension(getMinimumHorizontalSize());
  266. d.height = insetCache.top + insetCache.bottom;
  267. d.height += focusInsets.top + focusInsets.bottom;
  268. d.height += trackRect.height + tickRect.height + labelRect.height;
  269. }
  270. return d;
  271. }
  272. public Dimension getMaximumSize(JComponent c) {
  273. Dimension d = getPreferredSize(c);
  274. if ( slider.getOrientation() == JSlider.VERTICAL ) {
  275. d.height = Short.MAX_VALUE;
  276. }
  277. else {
  278. d.width = Short.MAX_VALUE;
  279. }
  280. return d;
  281. }
  282. protected void calculateGeometry() {
  283. calculateFocusRect();
  284. calculateContentRect();
  285. calculateThumbSize();
  286. calculateTrackBuffer();
  287. calculateTrackRect();
  288. calculateTickRect();
  289. calculateLabelRect();
  290. calculateThumbLocation();
  291. }
  292. protected void calculateFocusRect() {
  293. focusRect.x = insetCache.left;
  294. focusRect.y = insetCache.top;
  295. focusRect.width = slider.getWidth() - (insetCache.left + insetCache.right);
  296. focusRect.height = slider.getHeight() - (insetCache.top + insetCache.bottom);
  297. }
  298. protected void calculateThumbSize() {
  299. Dimension size = getThumbSize();
  300. thumbRect.setSize( size.width, size.height );
  301. }
  302. protected void calculateContentRect() {
  303. contentRect.x = focusRect.x + focusInsets.left;
  304. contentRect.y = focusRect.y + focusInsets.top;
  305. contentRect.width = focusRect.width - (focusInsets.left + focusInsets.right);
  306. contentRect.height = focusRect.height - (focusInsets.top + focusInsets.bottom);
  307. }
  308. protected void calculateThumbLocation() {
  309. if ( slider.getSnapToTicks() ) {
  310. int sliderValue = slider.getValue();
  311. int snappedValue = sliderValue;
  312. int majorTickSpacing = slider.getMajorTickSpacing();
  313. int minorTickSpacing = slider.getMinorTickSpacing();
  314. int tickSpacing = 0;
  315. if ( minorTickSpacing > 0 ) {
  316. tickSpacing = minorTickSpacing;
  317. }
  318. else if ( majorTickSpacing > 0 ) {
  319. tickSpacing = majorTickSpacing;
  320. }
  321. if ( tickSpacing != 0 ) {
  322. // If it's not on a tick, change the value
  323. if ( (sliderValue - slider.getMinimum()) % tickSpacing != 0 ) {
  324. float temp = (float)(sliderValue - slider.getMinimum()) / (float)tickSpacing;
  325. int whichTick = Math.round( temp );
  326. snappedValue = slider.getMinimum() + (whichTick * tickSpacing);
  327. }
  328. if( snappedValue != sliderValue ) {
  329. slider.setValue( snappedValue );
  330. }
  331. }
  332. }
  333. if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
  334. int valuePosition = xPositionForValue(slider.getValue());
  335. thumbRect.x = valuePosition - (thumbRect.width / 2);
  336. thumbRect.y = trackRect.y;
  337. }
  338. else {
  339. int valuePosition = yPositionForValue(slider.getValue());
  340. thumbRect.x = trackRect.x;
  341. thumbRect.y = valuePosition - (thumbRect.height / 2);
  342. }
  343. }
  344. protected void calculateTrackBuffer() {
  345. if ( slider.getPaintLabels() && slider.getLabelTable() != null ) {
  346. Component highLabel = getHighestValueLabel();
  347. Component lowLabel = getLowestValueLabel();
  348. if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
  349. trackBuffer = Math.max( highLabel.getBounds().width, lowLabel.getBounds().width ) / 2;
  350. trackBuffer = Math.max( trackBuffer, thumbRect.width / 2 );
  351. }
  352. else {
  353. trackBuffer = Math.max( highLabel.getBounds().height, lowLabel.getBounds().height ) / 2;
  354. trackBuffer = Math.max( trackBuffer, thumbRect.height / 2 );
  355. }
  356. }
  357. else {
  358. if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
  359. trackBuffer = thumbRect.width / 2;
  360. }
  361. else {
  362. trackBuffer = thumbRect.height / 2;
  363. }
  364. }
  365. }
  366. protected void calculateTrackRect() {
  367. if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
  368. trackRect.x = contentRect.x + trackBuffer;
  369. trackRect.y = contentRect.y;
  370. trackRect.width = contentRect.width - (trackBuffer * 2);
  371. trackRect.height = thumbRect.height;
  372. }
  373. else {
  374. trackRect.x = contentRect.x;
  375. trackRect.y = contentRect.y + trackBuffer;
  376. trackRect.width = thumbRect.width;
  377. trackRect.height = contentRect.height - (trackBuffer * 2);
  378. }
  379. }
  380. /**
  381. * Gets the height of the tick area for horizontal sliders and the width of the
  382. * tick area for vertical sliders. BasicSliderUI uses the returned value to
  383. * determine the tick area rectangle. If you want to give your ticks some room,
  384. * make this larger than you need and paint your ticks away from the sides in paintTicks().
  385. */
  386. protected int getTickLength() {
  387. return 8;
  388. }
  389. protected void calculateTickRect() {
  390. if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
  391. tickRect.x = trackRect.x;
  392. tickRect.y = trackRect.y + trackRect.height;
  393. tickRect.width = trackRect.width;
  394. tickRect.height = getTickLength();
  395. if ( !slider.getPaintTicks() ) {
  396. --tickRect.y;
  397. tickRect.height = 0;
  398. }
  399. }
  400. else {
  401. tickRect.x = trackRect.x + trackRect.width;
  402. tickRect.y = trackRect.y;
  403. tickRect.width = getTickLength();
  404. tickRect.height = trackRect.height;
  405. if ( !slider.getPaintTicks() ) {
  406. --tickRect.x;
  407. tickRect.width = 0;
  408. }
  409. }
  410. }
  411. protected void calculateLabelRect() {
  412. if ( slider.getPaintLabels() ) {
  413. if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
  414. labelRect.x = tickRect.x - trackBuffer;
  415. labelRect.y = tickRect.y + tickRect.height;
  416. labelRect.width = tickRect.width + (trackBuffer * 2);
  417. labelRect.height = getHeightOfTallestLabel();
  418. }
  419. else {
  420. labelRect.x = tickRect.x + tickRect.width;
  421. labelRect.y = tickRect.y - trackBuffer;
  422. labelRect.width = getWidthOfWidestLabel();
  423. labelRect.height = tickRect.height + (trackBuffer * 2);
  424. }
  425. }
  426. else {
  427. if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
  428. labelRect.x = tickRect.x;
  429. labelRect.y = tickRect.y + tickRect.height;
  430. labelRect.width = tickRect.width;
  431. labelRect.height = 0;
  432. }
  433. else {
  434. labelRect.x = tickRect.x + tickRect.width;
  435. labelRect.y = tickRect.y;
  436. labelRect.width = 0;
  437. labelRect.height = tickRect.height;
  438. }
  439. }
  440. }
  441. protected Dimension getThumbSize() {
  442. Dimension size = new Dimension();
  443. if ( slider.getOrientation() == JSlider.VERTICAL ) {
  444. size.width = 20;
  445. size.height = 11;
  446. }
  447. else {
  448. size.width = 11;
  449. size.height = 20;
  450. }
  451. return size;
  452. }
  453. public class PropertyChangeHandler implements PropertyChangeListener {
  454. public void propertyChange( PropertyChangeEvent e ) {
  455. String propertyName = e.getPropertyName();
  456. if (propertyName.equals( "orientation" ) ||
  457. propertyName.equals( "inverted" ) ||
  458. propertyName.equals( "labelTable" ) ||
  459. propertyName.equals( "majorTickSpacing" ) ||
  460. propertyName.equals( "minorTickSpacing" ) ||
  461. propertyName.equals( "paintTicks" ) ||
  462. propertyName.equals( "paintTrack" ) ||
  463. propertyName.equals( "paintLabels" ) ) {
  464. calculateGeometry();
  465. }
  466. else if ( propertyName.equals( "model" ) ) {
  467. ((BoundedRangeModel)e.getOldValue()).removeChangeListener( changeListener );
  468. ((BoundedRangeModel)e.getNewValue()).addChangeListener( changeListener );
  469. calculateThumbLocation();
  470. slider.repaint();
  471. }
  472. }
  473. }
  474. protected int getWidthOfWidestLabel() {
  475. Dictionary dictionary = slider.getLabelTable();
  476. int widest = 0;
  477. if ( dictionary != null ) {
  478. Enumeration keys = dictionary.keys();
  479. while ( keys.hasMoreElements() ) {
  480. Component label = (Component)dictionary.get( keys.nextElement() );
  481. widest = Math.max( label.getPreferredSize().width, widest );
  482. }
  483. }
  484. return widest;
  485. }
  486. protected int getHeightOfTallestLabel() {
  487. Dictionary dictionary = slider.getLabelTable();
  488. int tallest = 0;
  489. if ( dictionary != null ) {
  490. Enumeration keys = dictionary.keys();
  491. while ( keys.hasMoreElements() ) {
  492. Component label = (Component)dictionary.get( keys.nextElement() );
  493. tallest = Math.max( label.getPreferredSize().height, tallest );
  494. }
  495. }
  496. return tallest;
  497. }
  498. protected int getWidthOfHighValueLabel() {
  499. Component label = getHighestValueLabel();
  500. int width = 0;
  501. if ( label != null ) {
  502. width = label.getPreferredSize().width;
  503. }
  504. return width;
  505. }
  506. protected int getWidthOfLowValueLabel() {
  507. Component label = getLowestValueLabel();
  508. int width = 0;
  509. if ( label != null ) {
  510. width = label.getPreferredSize().width;
  511. }
  512. return width;
  513. }
  514. protected int getHeightOfHighValueLabel() {
  515. Component label = getHighestValueLabel();
  516. int height = 0;
  517. if ( label != null ) {
  518. height = label.getPreferredSize().height;
  519. }
  520. return height;
  521. }
  522. protected int getHeightOfLowValueLabel() {
  523. Component label = getLowestValueLabel();
  524. int height = 0;
  525. if ( label != null ) {
  526. height = label.getPreferredSize().height;
  527. }
  528. return height;
  529. }
  530. /**
  531. * Returns the label that corresponds to the highest slider value in the label table.
  532. * @see JSlider#setLabelTable
  533. */
  534. protected Component getLowestValueLabel() {
  535. Dictionary dictionary = slider.getLabelTable();
  536. Component label = null;
  537. if ( dictionary != null ) {
  538. Enumeration keys = dictionary.keys();
  539. if ( keys.hasMoreElements() ) {
  540. int lowestValue = ((Integer)keys.nextElement()).intValue();
  541. while ( keys.hasMoreElements() ) {
  542. int value = ((Integer)keys.nextElement()).intValue();
  543. lowestValue = Math.min( value, lowestValue );
  544. }
  545. label = (Component)dictionary.get( new Integer( lowestValue ) );
  546. }
  547. }
  548. return label;
  549. }
  550. /**
  551. * Returns the label that corresponds to the lowest slider value in the label table.
  552. * @see JSlider#setLabelTable
  553. */
  554. protected Component getHighestValueLabel() {
  555. Dictionary dictionary = slider.getLabelTable();
  556. Component label = null;
  557. if ( dictionary != null ) {
  558. Enumeration keys = dictionary.keys();
  559. if ( keys.hasMoreElements() ) {
  560. int highestValue = ((Integer)keys.nextElement()).intValue();
  561. while ( keys.hasMoreElements() ) {
  562. int value = ((Integer)keys.nextElement()).intValue();
  563. highestValue = Math.max( value, highestValue );
  564. }
  565. label = (Component)dictionary.get( new Integer( highestValue ) );
  566. }
  567. }
  568. return label;
  569. }
  570. public void paint( Graphics g, JComponent c ) {
  571. recalculateIfInsetsChanged();
  572. Rectangle clip = g.getClipBounds();
  573. if ( slider.getPaintTrack() && clip.intersects( trackRect ) ) {
  574. paintTrack( g );
  575. }
  576. if ( slider.getPaintTicks() && clip.intersects( tickRect ) ) {
  577. paintTicks( g );
  578. }
  579. if ( slider.getPaintLabels() && clip.intersects( labelRect ) ) {
  580. paintLabels( g );
  581. }
  582. if ( slider.hasFocus() && clip.intersects( focusRect ) ) {
  583. paintFocus( g );
  584. }
  585. if ( clip.intersects( thumbRect ) ) {
  586. paintThumb( g );
  587. }
  588. }
  589. protected void recalculateIfInsetsChanged() {
  590. Insets newInsets = slider.getInsets();
  591. if ( !newInsets.equals( insetCache ) ) {
  592. insetCache = newInsets;
  593. calculateGeometry();
  594. }
  595. }
  596. public void paintFocus(Graphics g) {
  597. g.setColor( getFocusColor() );
  598. BasicGraphicsUtils.drawDashedRect( g, focusRect.x, focusRect.y,
  599. focusRect.width, focusRect.height );
  600. }
  601. public void paintTrack(Graphics g) {
  602. int cx, cy, cw, ch;
  603. int pad;
  604. Rectangle trackBounds = trackRect;
  605. if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
  606. pad = trackBuffer;
  607. cx = pad;
  608. cy = (trackBounds.height / 2) - 2;
  609. cw = trackBounds.width;
  610. g.translate(trackBounds.x, trackBounds.y + cy);
  611. g.setColor(getShadowColor());
  612. g.drawLine(0, 0, cw - 1, 0);
  613. g.drawLine(0, 1, 0, 2);
  614. g.setColor(getHighlightColor());
  615. g.drawLine(0, 3, cw, 3);
  616. g.drawLine(cw, 0, cw, 3);
  617. g.setColor(Color.black);
  618. g.drawLine(1, 1, cw-2, 1);
  619. g.translate(-trackBounds.x, -(trackBounds.y + cy));
  620. }
  621. else {
  622. pad = trackBuffer;
  623. cx = (trackBounds.width / 2) - 2;
  624. cy = pad;
  625. ch = trackBounds.height;
  626. g.translate(trackBounds.x + cx, trackBounds.y);
  627. g.setColor(getShadowColor());
  628. g.drawLine(0, 0, 0, ch - 1);
  629. g.drawLine(1, 0, 2, 0);
  630. g.setColor(getHighlightColor());
  631. g.drawLine(3, 0, 3, ch);
  632. g.drawLine(0, ch, 3, ch);
  633. g.setColor(Color.black);
  634. g.drawLine(1, 1, 1, ch-2);
  635. g.translate(-(trackBounds.x + cx), -trackBounds.y);
  636. }
  637. }
  638. public void paintTicks(Graphics g) {
  639. Rectangle tickBounds = tickRect;
  640. int i;
  641. int maj, min, max;
  642. int w = tickBounds.width;
  643. int h = tickBounds.height;
  644. int centerEffect, tickHeight;
  645. g.setColor(slider.getBackground());
  646. g.fillRect(tickBounds.x, tickBounds.y, tickBounds.width, tickBounds.height);
  647. g.setColor(Color.black);
  648. maj = slider.getMajorTickSpacing();
  649. min = slider.getMinorTickSpacing();
  650. if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
  651. g.translate( 0, tickBounds.y);
  652. int value = slider.getMinimum();
  653. int xPos = 0;
  654. if ( slider.getMinorTickSpacing() > 0 ) {
  655. while ( value <= slider.getMaximum() ) {
  656. xPos = xPositionForValue( value );
  657. paintMinorTickForHorizSlider( g, tickBounds, xPos );
  658. value += slider.getMinorTickSpacing();
  659. }
  660. }
  661. if ( slider.getMajorTickSpacing() > 0 ) {
  662. value = slider.getMinimum();
  663. while ( value <= slider.getMaximum() ) {
  664. xPos = xPositionForValue( value );
  665. paintMajorTickForHorizSlider( g, tickBounds, xPos );
  666. value += slider.getMajorTickSpacing();
  667. }
  668. }
  669. g.translate( 0, -tickBounds.y);
  670. }
  671. else {
  672. g.translate(tickBounds.x, 0);
  673. int value = slider.getMinimum();
  674. int yPos = 0;
  675. if ( slider.getMinorTickSpacing() > 0 ) {
  676. while ( value <= slider.getMaximum() ) {
  677. yPos = yPositionForValue( value );
  678. paintMinorTickForVertSlider( g, tickBounds, yPos );
  679. value += slider.getMinorTickSpacing();
  680. }
  681. }
  682. if ( slider.getMajorTickSpacing() > 0 ) {
  683. value = slider.getMinimum();
  684. while ( value <= slider.getMaximum() ) {
  685. yPos = yPositionForValue( value );
  686. paintMajorTickForVertSlider( g, tickBounds, yPos );
  687. value += slider.getMajorTickSpacing();
  688. }
  689. }
  690. g.translate(-tickBounds.x, 0);
  691. }
  692. }
  693. protected void paintMinorTickForHorizSlider( Graphics g, Rectangle tickBounds, int x ) {
  694. g.drawLine( x, 0, x, tickBounds.height / 2 - 1 );
  695. }
  696. protected void paintMajorTickForHorizSlider( Graphics g, Rectangle tickBounds, int x ) {
  697. g.drawLine( x, 0, x, tickBounds.height - 2 );
  698. }
  699. protected void paintMinorTickForVertSlider( Graphics g, Rectangle tickBounds, int y ) {
  700. g.drawLine( 0, y, tickBounds.width / 2 - 1, y );
  701. }
  702. protected void paintMajorTickForVertSlider( Graphics g, Rectangle tickBounds, int y ) {
  703. g.drawLine( 0, y, tickBounds.width - 2, y );
  704. }
  705. public void paintLabels( Graphics g ) {
  706. Rectangle labelBounds = labelRect;
  707. Dictionary dictionary = slider.getLabelTable();
  708. if ( dictionary != null ) {
  709. Enumeration keys = dictionary.keys();
  710. while ( keys.hasMoreElements() ) {
  711. Integer key = (Integer)keys.nextElement();
  712. Component label = (Component)dictionary.get( key );
  713. if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
  714. g.translate( 0, labelBounds.y );
  715. paintHorizontalLabel( g, key.intValue(), label );
  716. g.translate( 0, -labelBounds.y );
  717. }
  718. else {
  719. g.translate( labelBounds.x, 0 );
  720. paintVerticalLabel( g, key.intValue(), label );
  721. g.translate( -labelBounds.x, 0 );
  722. }
  723. }
  724. }
  725. }
  726. /**
  727. * Called for every label in the label table. Used to draw the labels for horizontal sliders.
  728. * The graphics have been translated to labelRect.y already.
  729. * @see JSlider#setLabelTable
  730. */
  731. protected void paintHorizontalLabel( Graphics g, int value, Component label ) {
  732. int labelCenter = xPositionForValue( value );
  733. int labelLeft = labelCenter - (label.getPreferredSize().width / 2);
  734. g.translate( labelLeft, 0 );
  735. label.paint( g );
  736. g.translate( -labelLeft, 0 );
  737. }
  738. /**
  739. * Called for every label in the label table. Used to draw the labels for vertical sliders.
  740. * The graphics have been translated to labelRect.x already.
  741. * @see JSlider#setLabelTable
  742. */
  743. protected void paintVerticalLabel( Graphics g, int value, Component label ) {
  744. int labelCenter = yPositionForValue( value );
  745. int labelTop = labelCenter - (label.getPreferredSize().height / 2);
  746. g.translate( 0, labelTop );
  747. label.paint( g );
  748. g.translate( 0, -labelTop );
  749. }
  750. public void paintThumb(Graphics g) {
  751. Rectangle knobBounds = thumbRect;
  752. int w = knobBounds.width;
  753. int h = knobBounds.height;
  754. g.translate(knobBounds.x, knobBounds.y);
  755. if ( slider.isEnabled() ) {
  756. g.setColor(slider.getBackground());
  757. }
  758. else {
  759. g.setColor(slider.getBackground().darker());
  760. }
  761. if ( !slider.getPaintTicks() ) {
  762. g.fillRect(0, 0, w, h);
  763. g.setColor(Color.black);
  764. g.drawLine(0, h-1, w-1, h-1);
  765. g.drawLine(w-1, 0, w-1, h-1);
  766. g.setColor(highlightColor);
  767. g.drawLine(0, 0, 0, h-2);
  768. g.drawLine(1, 0, w-2, 0);
  769. g.setColor(shadowColor);
  770. g.drawLine(1, h-2, w-2, h-2);
  771. g.drawLine(w-2, 1, w-2, h-3);
  772. }
  773. else if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
  774. int cw = w / 2;
  775. g.fillRect(1, 1, w-3, h-1-cw);
  776. Polygon p = new Polygon();
  777. p.addPoint(1, h-cw);
  778. p.addPoint(cw-1, h-1);
  779. p.addPoint(w-2, h-1-cw);
  780. g.fillPolygon(p);
  781. g.setColor(highlightColor);
  782. g.drawLine(0, 0, w-2, 0);
  783. g.drawLine(0, 1, 0, h-1-cw);
  784. g.drawLine(0, h-cw, cw-1, h-1);
  785. g.setColor(Color.black);
  786. g.drawLine(w-1, 0, w-1, h-2-cw);
  787. g.drawLine(w-1, h-1-cw, w-1-cw, h-1);
  788. g.setColor(shadowColor);
  789. g.drawLine(w-2, 1, w-2, h-2-cw);
  790. g.drawLine(w-2, h-1-cw, w-1-cw, h-2);
  791. }
  792. else {
  793. int cw = h / 2;
  794. g.fillRect(1, 1, w-1-cw, h-3);
  795. Polygon p = new Polygon();
  796. p.addPoint(w-cw-1, 0);
  797. p.addPoint(w-1, cw);
  798. p.addPoint(w-1-cw, h-2);
  799. g.fillPolygon(p);
  800. g.setColor(highlightColor);
  801. g.drawLine(0, 0, 0, h - 2);
  802. g.drawLine(1, 0, w-1-cw, 0);
  803. g.drawLine(w-cw-1, 0, w-1, cw);
  804. g.setColor(Color.black);
  805. g.drawLine(0, h-1, w-2-cw, h-1);
  806. g.drawLine(w-1-cw, h-1, w-1, h-1-cw);
  807. g.setColor(shadowColor);
  808. g.drawLine(1, h-2, w-2-cw, h-2 );
  809. g.drawLine(w-1-cw, h-2, w-2, h-cw-1 );
  810. }
  811. g.translate(-knobBounds.x, -knobBounds.y);
  812. }
  813. // Used exclusively by setThumbLocation()
  814. private static Rectangle unionRect = new Rectangle();
  815. public void setThumbLocation(int x, int y) {
  816. unionRect.setBounds( thumbRect );
  817. thumbRect.setLocation( x, y );
  818. SwingUtilities.computeUnion( thumbRect.x, thumbRect.y, thumbRect.width, thumbRect.height, unionRect );
  819. slider.repaint( unionRect.x, unionRect.y, unionRect.width, unionRect.height );
  820. }
  821. public void scrollByBlock(int direction) {
  822. synchronized(slider) {
  823. int oldValue = slider.getValue();
  824. int blockIncrement = slider.getMaximum() / 10;
  825. int delta = blockIncrement * ((direction > 0) ? POSITIVE_SCROLL : NEGATIVE_SCROLL);
  826. slider.setValue(oldValue + delta);
  827. }
  828. }
  829. public void scrollByUnit(int direction) {
  830. synchronized(slider) {
  831. int oldValue = slider.getValue();
  832. int delta = 1 * ((direction > 0) ? POSITIVE_SCROLL : NEGATIVE_SCROLL);
  833. slider.setValue(oldValue + delta);
  834. }
  835. }
  836. /**
  837. * This function is called when a mousePressed was detected in the track, not
  838. * in the thumb. The default behavior is to scroll by block. You can
  839. * override this method to stop it from scrolling or to add additional behavior.
  840. */
  841. protected void scrollDueToClickInTrack( int dir ) {
  842. scrollByBlock( dir );
  843. }
  844. protected int xPositionForValue( int value ) {
  845. int min = slider.getMinimum();
  846. int max = slider.getMaximum();
  847. int trackLength = trackRect.width;
  848. int valueRange = slider.getMaximum() - slider.getMinimum();
  849. double pixelsPerValue = (double)trackLength / (double)valueRange;
  850. int trackLeft = trackRect.x;
  851. int trackRight = trackRect.x + (trackRect.width - 1);
  852. int xPosition;
  853. if ( !slider.getInverted() ) {
  854. xPosition = trackLeft;
  855. xPosition += Math.round( pixelsPerValue * (double)(value - min) );
  856. }
  857. else {
  858. xPosition = trackRight;
  859. xPosition -= Math.round( pixelsPerValue * (double)(value - min) );
  860. }
  861. xPosition = Math.max( trackLeft, xPosition );
  862. xPosition = Math.min( trackRight, xPosition );
  863. return xPosition;
  864. }
  865. protected int yPositionForValue( int value ) {
  866. int min = slider.getMinimum();
  867. int max = slider.getMaximum();
  868. int trackLength = trackRect.height;
  869. int valueRange = slider.getMaximum() - slider.getMinimum();
  870. double pixelsPerValue = (double)trackLength / (double)valueRange;
  871. int trackTop = trackRect.y;
  872. int trackBottom = trackRect.y + (trackRect.height - 1);
  873. int yPosition;
  874. if ( !slider.getInverted() ) {
  875. yPosition = trackTop;
  876. yPosition += Math.round( pixelsPerValue * (double)(max - value ) );
  877. }
  878. else {
  879. yPosition = trackTop;
  880. yPosition += Math.round( pixelsPerValue * (double)(value - min) );
  881. }
  882. yPosition = Math.max( trackTop, yPosition );
  883. yPosition = Math.min( trackBottom, yPosition );
  884. return yPosition;
  885. }
  886. /**
  887. * Returns a value give a y position. If yPos is past the track at the top or the
  888. * bottom it will set the value to the min or max of the slider, depending if the
  889. * slider is inverted or not.
  890. */
  891. public int valueForYPosition( int yPos ) {
  892. int value;
  893. final int minValue = slider.getMinimum();
  894. final int maxValue = slider.getMaximum();
  895. final int trackLength = trackRect.height;
  896. final int trackTop = trackRect.y;
  897. final int trackBottom = trackRect.y + (trackRect.height - 1);
  898. if ( yPos <= trackTop ) {
  899. value = slider.getInverted() ? minValue : maxValue;
  900. }
  901. else if ( yPos >= trackBottom ) {
  902. value = slider.getInverted() ? maxValue : minValue;
  903. }
  904. else {
  905. int distanceFromTrackTop = yPos - trackTop;
  906. int valueRange = maxValue - minValue;
  907. double valuePerPixel = (double)valueRange / (double)trackLength;
  908. int valueFromTrackTop = (int)Math.round( distanceFromTrackTop * valuePerPixel );
  909. value = slider.getInverted() ? minValue + valueFromTrackTop : maxValue - valueFromTrackTop;
  910. }
  911. return value;
  912. }
  913. /**
  914. * Returns a value give an x position. If xPos is past the track at the left or the
  915. * right it will set the value to the min or max of the slider, depending if the
  916. * slider is inverted or not.
  917. */
  918. public int valueForXPosition( int xPos ) {
  919. int value;
  920. final int minValue = slider.getMinimum();
  921. final int maxValue = slider.getMaximum();
  922. final int trackLength = trackRect.width;
  923. final int trackLeft = trackRect.x;
  924. final int trackRight = trackRect.x + (trackRect.width - 1);
  925. if ( xPos <= trackLeft ) {
  926. value = slider.getInverted() ? maxValue : minValue;
  927. }
  928. else if ( xPos >= trackRight ) {
  929. value = slider.getInverted() ? minValue : maxValue;
  930. }
  931. else {
  932. int distanceFromTrackLeft = xPos - trackLeft;
  933. int valueRange = maxValue - minValue;
  934. double valuePerPixel = (double)valueRange / (double)trackLength;
  935. int valueFromTrackLeft = (int)Math.round( distanceFromTrackLeft * valuePerPixel );
  936. value = slider.getInverted() ? maxValue - valueFromTrackLeft :
  937. minValue + valueFromTrackLeft;
  938. }
  939. return value;
  940. }
  941. /////////////////////////////////////////////////////////////////////////
  942. /// Model Listener Class
  943. /////////////////////////////////////////////////////////////////////////
  944. /**
  945. * Data model listener.
  946. *
  947. * This inner class is marked "public" due to a compiler bug.
  948. * This class should be treated as a "protected" inner class.
  949. * Instantiate it only within subclasses of <Foo>.
  950. */
  951. public class ChangeHandler implements ChangeListener {
  952. public void stateChanged(ChangeEvent e) {
  953. if ( !isDragging ) {
  954. calculateThumbLocation();
  955. slider.repaint();
  956. }
  957. }
  958. }
  959. /////////////////////////////////////////////////////////////////////////
  960. /// Track Listener Class
  961. /////////////////////////////////////////////////////////////////////////
  962. /**
  963. * Track mouse movements.
  964. *
  965. * This inner class is marked "public" due to a compiler bug.
  966. * This class should be treated as a "protected" inner class.
  967. * Instantiate it only within subclasses of <Foo>.
  968. */
  969. public class TrackListener extends MouseInputAdapter {
  970. protected transient int offset;
  971. protected transient int currentMouseX, currentMouseY;
  972. public void mouseReleased(MouseEvent e) {
  973. if ( !slider.isEnabled() )
  974. return;
  975. offset = 0;
  976. scrollTimer.stop();
  977. // This is the way we have to determine snap-to-ticks. It's hard to explain
  978. // but since ChangeEvents don't give us any idea what has changed we don't
  979. // have a way to stop the thumb bounds from being recalculated. Recalculating
  980. // the thumb bounds moves the thumb over the current value (i.e., snapping
  981. // to the ticks).
  982. if ( slider.getSnapToTicks() /*|| slider.getSnapToValue()*/ ) {
  983. isDragging = false;
  984. slider.setValueIsAdjusting(false);
  985. }
  986. else {
  987. slider.setValueIsAdjusting(false);
  988. isDragging = false;
  989. }
  990. slider.repaint();
  991. }
  992. /**
  993. * If the mouse is pressed above the "thumb" component
  994. * then reduce the scrollbars value by one page ("page up"),
  995. * otherwise increase it by one page. If there is no
  996. * thumb then page up if the mouse is in the upper half
  997. * of the track.
  998. */
  999. public void mousePressed(MouseEvent e) {
  1000. if ( !slider.isEnabled() )
  1001. return;
  1002. currentMouseX = e.getX();
  1003. currentMouseY = e.getY();
  1004. slider.requestFocus();
  1005. // Clicked in the Thumb area?
  1006. if ( thumbRect.contains(currentMouseX, currentMouseY) ) {
  1007. switch ( slider.getOrientation() ) {
  1008. case JSlider.VERTICAL:
  1009. offset = currentMouseY - thumbRect.y;
  1010. break;
  1011. case JSlider.HORIZONTAL:
  1012. offset = currentMouseX - thumbRect.x;
  1013. break;
  1014. }
  1015. isDragging = true;
  1016. slider.setValueIsAdjusting(true);
  1017. return;
  1018. }
  1019. isDragging = false;
  1020. slider.setValueIsAdjusting(true);
  1021. Dimension sbSize = slider.getSize();
  1022. int direction = POSITIVE_SCROLL;
  1023. switch ( slider.getOrientation() ) {
  1024. case JSlider.VERTICAL:
  1025. if ( thumbRect.isEmpty() ) {
  1026. int scrollbarCenter = sbSize.height / 2;
  1027. if ( !slider.getInverted() ) {
  1028. direction = (currentMouseY < scrollbarCenter) ? POSITIVE_SCROLL : NEGATIVE_SCROLL;
  1029. }
  1030. else {
  1031. direction = (currentMouseY < scrollbarCenter) ? NEGATIVE_SCROLL : POSITIVE_SCROLL;
  1032. }
  1033. }
  1034. else {
  1035. int thumbY = thumbRect.y;
  1036. if ( !slider.getInverted() ) {
  1037. direction = (currentMouseY < thumbY) ? POSITIVE_SCROLL : NEGATIVE_SCROLL;
  1038. }
  1039. else {
  1040. direction = (currentMouseY < thumbY) ? NEGATIVE_SCROLL : POSITIVE_SCROLL;
  1041. }
  1042. }
  1043. break;
  1044. case JSlider.HORIZONTAL:
  1045. if ( thumbRect.isEmpty() ) {
  1046. int scrollbarCenter = sbSize.width / 2;
  1047. if ( !slider.getInverted() ) {
  1048. direction = (currentMouseX < scrollbarCenter) ? NEGATIVE_SCROLL : POSITIVE_SCROLL;
  1049. }
  1050. else {
  1051. direction = (currentMouseX < scrollbarCenter) ? POSITIVE_SCROLL : NEGATIVE_SCROLL;
  1052. }
  1053. }
  1054. else {
  1055. int thumbX = thumbRect.x;
  1056. if ( !slider.getInverted() ) {
  1057. direction = (currentMouseX < thumbX) ? NEGATIVE_SCROLL : POSITIVE_SCROLL;
  1058. }
  1059. else {
  1060. direction = (currentMouseX < thumbX) ? POSITIVE_SCROLL : NEGATIVE_SCROLL;
  1061. }
  1062. }
  1063. break;
  1064. }
  1065. scrollDueToClickInTrack(direction);
  1066. Rectangle r = thumbRect;
  1067. if ( !r.contains(currentMouseX, currentMouseY) ) {
  1068. if ( shouldScroll(direction) ) {
  1069. scrollTimer.stop();
  1070. scrollListener.setDirection(direction);
  1071. scrollTimer.start();
  1072. }
  1073. }
  1074. }
  1075. public boolean shouldScroll(int direction) {
  1076. Rectangle r = thumbRect;
  1077. if ( slider.getOrientation() == JSlider.VERTICAL ) {
  1078. if ( slider.getInverted() ? direction < 0 : direction > 0 ) {
  1079. if ( r.y + r.height <= currentMouseY ) {
  1080. return false;
  1081. }
  1082. }
  1083. else if ( r.y >= currentMouseY ) {
  1084. return false;
  1085. }
  1086. }
  1087. else {
  1088. if ( slider.getInverted() ? direction < 0 : direction > 0 ) {
  1089. if ( r.x + r.width >= currentMouseX ) {
  1090. return false;
  1091. }
  1092. }
  1093. else if ( r.x <= currentMouseX ) {
  1094. return false;
  1095. }
  1096. }
  1097. if ( direction > 0 && slider.getValue() + slider.getExtent() >= slider.getMaximum() ) {
  1098. return false;
  1099. }
  1100. else if ( direction < 0 && slider.getValue() <= slider.getMinimum() ) {
  1101. return false;
  1102. }
  1103. return true;
  1104. }
  1105. /**
  1106. * Set the models value to the position of the top/left
  1107. * of the thumb relative to the origin of the track.
  1108. */
  1109. public void mouseDragged( MouseEvent e ) {
  1110. BasicScrollBarUI ui;
  1111. int thumbMiddle = 0;
  1112. if ( !slider.isEnabled() )
  1113. return;
  1114. currentMouseX = e.getX();
  1115. currentMouseY = e.getY();
  1116. if ( !isDragging )
  1117. return;
  1118. switch ( slider.getOrientation() ) {
  1119. case JSlider.VERTICAL:
  1120. int halfThumbHeight = thumbRect.height / 2;
  1121. int thumbTop = e.getY() - offset;
  1122. int trackTop = trackRect.y;
  1123. int trackBottom = trackRect.y + (trackRect.height - 1);
  1124. thumbTop = Math.max( thumbTop, trackTop - halfThumbHeight );
  1125. thumbTop = Math.min( thumbTop, trackBottom - halfThumbHeight );
  1126. setThumbLocation(thumbRect.x, thumbTop);
  1127. thumbMiddle = thumbTop + halfThumbHeight;
  1128. slider.setValue( valueForYPosition( thumbMiddle ) );
  1129. break;
  1130. case JSlider.HORIZONTAL:
  1131. int halfThumbWidth = thumbRect.width / 2;
  1132. int thumbLeft = e.getX() - offset;
  1133. int trackLeft = trackRect.x;
  1134. int trackRight = trackRect.x + (trackRect.width - 1);
  1135. thumbLeft = Math.max( thumbLeft, trackLeft - halfThumbWidth );
  1136. thumbLeft = Math.min( thumbLeft, trackRight - halfThumbWidth );
  1137. setThumbLocation( thumbLeft, thumbRect.y);
  1138. thumbMiddle = thumbLeft + halfThumbWidth;
  1139. slider.setValue( valueForXPosition( thumbMiddle ) );
  1140. break;
  1141. default:
  1142. return;
  1143. }
  1144. }
  1145. public void mouseMoved(MouseEvent e) {}
  1146. }
  1147. /**
  1148. * Scroll-event listener.
  1149. *
  1150. * This inner class is marked "public" due to a compiler bug.
  1151. * This class should be treated as a "protected" inner class.
  1152. * Instantiate it only within subclasses of <Foo>.
  1153. */
  1154. public class ScrollListener implements ActionListener {
  1155. // changed this class to public to avoid bogus IllegalAccessException bug i
  1156. // InternetExplorer browser. It was protected. Work around for 4109432
  1157. int direction = POSITIVE_SCROLL;
  1158. boolean useBlockIncrement;
  1159. public ScrollListener() {
  1160. direction = POSITIVE_SCROLL;
  1161. useBlockIncrement = true;
  1162. }
  1163. public ScrollListener(int dir, boolean block) {
  1164. direction = dir;
  1165. useBlockIncrement = block;
  1166. }
  1167. public void setDirection(int direction) { this.direction = direction;}
  1168. public void setScrollByBlock(boolean block) { this.useBlockIncrement = block;}
  1169. public void actionPerformed(ActionEvent e) {
  1170. if ( useBlockIncrement ) {
  1171. scrollByBlock(direction);
  1172. }
  1173. else {
  1174. scrollByUnit(direction);
  1175. }
  1176. if ( !trackListener.shouldScroll(direction) ) {
  1177. ((Timer)e.getSource()).stop();
  1178. }
  1179. }
  1180. };
  1181. /**
  1182. * Listener for resizing events.
  1183. * <p>
  1184. * This inner class is marked "public" due to a compiler bug.
  1185. * This class should be treated as a "protected" inner class.
  1186. * Instantiate it only within subclasses of <Foo>.
  1187. */
  1188. public class ComponentHandler extends ComponentAdapter {
  1189. public void componentResized(ComponentEvent e) {
  1190. calculateGeometry();
  1191. slider.repaint();
  1192. }
  1193. };
  1194. /**
  1195. * Focus-change listener.
  1196. * <p>
  1197. * This inner class is marked "public" due to a compiler bug.
  1198. * This class should be treated as a "protected" inner class.
  1199. * Instantiate it only within subclasses of <Foo>.
  1200. */
  1201. public class FocusHandler implements FocusListener {
  1202. public void focusGained(FocusEvent e) { slider.repaint();}
  1203. public void focusLost(FocusEvent e) { slider.repaint();}
  1204. };
  1205. /**
  1206. * Defines the action to take when scrolled.
  1207. * <p>
  1208. * This inner class is marked "public" due to a compiler bug.
  1209. * This class should be treated as a "protected" inner class.
  1210. * Instantiate it only within subclasses of <Foo>.
  1211. */
  1212. public class ActionScroller extends AbstractAction {
  1213. int dir;
  1214. boolean block;
  1215. JSlider slider;
  1216. public ActionScroller( JSlider slider, int dir, boolean block) {
  1217. this.dir = dir;
  1218. this.block = block;
  1219. this.slider = slider;
  1220. }
  1221. public void actionPerformed(ActionEvent e) {
  1222. if ( dir == NEGATIVE_SCROLL || dir == POSITIVE_SCROLL ) {
  1223. int realDir = dir;
  1224. if ( slider.getInverted() ) {
  1225. realDir = dir == NEGATIVE_SCROLL ? POSITIVE_SCROLL : NEGATIVE_SCROLL;
  1226. }
  1227. if ( block )
  1228. scrollByBlock(realDir);
  1229. else
  1230. scrollByUnit(realDir);
  1231. }
  1232. else {
  1233. if ( slider.getInverted() ) {
  1234. if ( dir == MIN_SCROLL )
  1235. slider.setValue(slider.getMaximum());
  1236. else if ( dir == MAX_SCROLL )
  1237. slider.setValue(slider.getMinimum());
  1238. }
  1239. else {
  1240. if ( dir == MIN_SCROLL )
  1241. slider.setValue(slider.getMinimum());
  1242. else if ( dir == MAX_SCROLL )
  1243. slider.setValue(slider.getMaximum());
  1244. }
  1245. }
  1246. }
  1247. public boolean isEnabled() {
  1248. boolean b = true;
  1249. if (slider != null) {
  1250. b = slider.isEnabled();
  1251. }
  1252. return b;
  1253. }
  1254. };
  1255. }