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