1. /*
  2. * @(#)MetalSliderUI.java 1.25 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.metal;
  8. import javax.swing.plaf.basic.BasicSliderUI;
  9. import java.awt.Component;
  10. import java.awt.Container;
  11. import java.awt.Graphics;
  12. import java.awt.Dimension;
  13. import java.awt.Rectangle;
  14. import java.awt.Point;
  15. import java.awt.Insets;
  16. import java.awt.Color;
  17. import java.io.Serializable;
  18. import java.awt.IllegalComponentStateException;
  19. import java.awt.Polygon;
  20. import java.beans.*;
  21. import javax.swing.border.AbstractBorder;
  22. import javax.swing.*;
  23. import javax.swing.event.*;
  24. import javax.swing.plaf.*;
  25. /**
  26. * A Java L&F implementation of SliderUI.
  27. * <p>
  28. * <strong>Warning:</strong>
  29. * Serialized objects of this class will not be compatible with
  30. * future Swing releases. The current serialization support is appropriate
  31. * for short term storage or RMI between applications running the same
  32. * version of Swing. A future release of Swing will provide support for
  33. * long term persistence.
  34. *
  35. * @version 1.25 11/29/01
  36. * @author Tom Santos
  37. */
  38. public class MetalSliderUI extends BasicSliderUI {
  39. protected final int TICK_BUFFER = 4;
  40. protected boolean filledSlider = false;
  41. protected static Color thumbColor;
  42. protected static Color highlightColor;
  43. protected static Color darkShadowColor;
  44. protected static int trackWidth;
  45. protected static int tickLength;
  46. protected static Icon horizThumbIcon;
  47. protected static Icon vertThumbIcon;
  48. protected final String SLIDER_FILL = "JSlider.isFilled";
  49. public static ComponentUI createUI(JComponent c) {
  50. return new MetalSliderUI();
  51. }
  52. public MetalSliderUI() {
  53. super( null );
  54. }
  55. public void installUI( JComponent c ) {
  56. trackWidth = ((Integer)UIManager.get( "Slider.trackWidth" )).intValue();
  57. tickLength = ((Integer)UIManager.get( "Slider.majorTickLength" )).intValue();
  58. horizThumbIcon = UIManager.getIcon( "Slider.horizontalThumbIcon" );
  59. vertThumbIcon = UIManager.getIcon( "Slider.verticalThumbIcon" );
  60. super.installUI( c );
  61. thumbColor = UIManager.getColor("Slider.thumb");
  62. highlightColor = UIManager.getColor("Slider.highlight");
  63. darkShadowColor = UIManager.getColor("Slider.darkShadow");
  64. scrollListener.setScrollByBlock( false );
  65. Object sliderFillProp = c.getClientProperty( SLIDER_FILL );
  66. if ( sliderFillProp != null ) {
  67. filledSlider = ((Boolean)sliderFillProp).booleanValue();
  68. }
  69. }
  70. protected PropertyChangeListener createPropertyChangeListener( JSlider slider ) {
  71. return new MetalPropertyListener();
  72. }
  73. protected class MetalPropertyListener extends BasicSliderUI.PropertyChangeHandler {
  74. public void propertyChange( PropertyChangeEvent e ) { // listen for slider fill
  75. super.propertyChange( e );
  76. String name = e.getPropertyName();
  77. if ( name.equals( SLIDER_FILL ) ) {
  78. if ( e.getNewValue() != null ) {
  79. filledSlider = ((Boolean)e.getNewValue()).booleanValue();
  80. }
  81. else {
  82. filledSlider = false;
  83. }
  84. }
  85. }
  86. }
  87. public void paintThumb(Graphics g) {
  88. Rectangle knobBounds = thumbRect;
  89. g.translate( knobBounds.x, knobBounds.y );
  90. if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
  91. horizThumbIcon.paintIcon( slider, g, 0, 0 );
  92. }
  93. else {
  94. vertThumbIcon.paintIcon( slider, g, 0, 0 );
  95. }
  96. g.translate( -knobBounds.x, -knobBounds.y );
  97. }
  98. public void paintTrack(Graphics g) {
  99. Color trackColor = !slider.isEnabled() ? MetalLookAndFeel.getControlShadow() :
  100. slider.getForeground();
  101. g.translate( trackRect.x, trackRect.y );
  102. int trackLeft = 0;
  103. int trackTop = 0;
  104. int trackRight = 0;
  105. int trackBottom = 0;
  106. // Draw the track
  107. if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
  108. trackBottom = (trackRect.height - 1) - getThumbOverhang();
  109. trackTop = trackBottom - (getTrackWidth() - 1);
  110. trackRight = trackRect.width - 1;
  111. }
  112. else {
  113. trackLeft = (trackRect.width - getThumbOverhang()) - getTrackWidth();
  114. trackRight = (trackRect.width - getThumbOverhang()) - 1;
  115. trackBottom = trackRect.height - 1;
  116. }
  117. if ( slider.isEnabled() ) {
  118. g.setColor( MetalLookAndFeel.getControlDarkShadow() );
  119. g.drawRect( trackLeft, trackTop,
  120. (trackRight - trackLeft) - 1, (trackBottom - trackTop) - 1 );
  121. g.setColor( MetalLookAndFeel.getControlHighlight() );
  122. g.drawLine( trackLeft + 1, trackBottom, trackRight, trackBottom );
  123. g.drawLine( trackRight, trackTop + 1, trackRight, trackBottom );
  124. g.setColor( MetalLookAndFeel.getControlShadow() );
  125. g.drawLine( trackLeft + 1, trackTop + 1, trackRight - 2, trackTop + 1 );
  126. g.drawLine( trackLeft + 1, trackTop + 1, trackLeft + 1, trackBottom - 2 );
  127. }
  128. else {
  129. g.setColor( MetalLookAndFeel.getControlShadow() );
  130. g.drawRect( trackLeft, trackTop,
  131. (trackRight - trackLeft) - 1, (trackBottom - trackTop) - 1 );
  132. }
  133. // Draw the fill
  134. if ( filledSlider ) {
  135. int middleOfThumb = 0;
  136. int fillTop = 0;
  137. int fillLeft = 0;
  138. int fillBottom = 0;
  139. int fillRight = 0;
  140. if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
  141. middleOfThumb = thumbRect.x + (thumbRect.width / 2);
  142. middleOfThumb -= trackRect.x; // To compensate for the g.translate()
  143. fillTop = !slider.isEnabled() ? trackTop : trackTop + 1;
  144. fillBottom = !slider.isEnabled() ? trackBottom - 1 : trackBottom - 2;
  145. if ( !slider.getInverted() ) {
  146. fillLeft = !slider.isEnabled() ? trackLeft : trackLeft + 1;
  147. fillRight = middleOfThumb;
  148. }
  149. else {
  150. fillLeft = middleOfThumb;
  151. fillRight = !slider.isEnabled() ? trackRight - 1 : trackRight - 2;
  152. }
  153. }
  154. else {
  155. middleOfThumb = thumbRect.y + (thumbRect.height / 2);
  156. middleOfThumb -= trackRect.y; // To compensate for the g.translate()
  157. fillLeft = !slider.isEnabled() ? trackLeft : trackLeft + 1;
  158. fillRight = !slider.isEnabled() ? trackRight - 1 : trackRight - 2;
  159. if ( !slider.getInverted() ) {
  160. fillTop = middleOfThumb;
  161. fillBottom = !slider.isEnabled() ? trackBottom - 1 : trackBottom - 2;
  162. }
  163. else {
  164. fillTop = !slider.isEnabled() ? trackTop : trackTop + 1;
  165. fillBottom = middleOfThumb;
  166. }
  167. }
  168. if ( slider.isEnabled() ) {
  169. g.setColor( slider.getBackground() );
  170. g.drawLine( fillLeft, fillTop, fillRight, fillTop );
  171. g.drawLine( fillLeft, fillTop, fillLeft, fillBottom );
  172. g.setColor( MetalLookAndFeel.getControlShadow() );
  173. g.fillRect( fillLeft + 1, fillTop + 1,
  174. fillRight - fillLeft, fillBottom - fillTop );
  175. }
  176. else {
  177. g.setColor( MetalLookAndFeel.getControlShadow() );
  178. g.fillRect( fillLeft, fillTop,
  179. fillRight - fillLeft, trackBottom - trackTop );
  180. }
  181. }
  182. g.translate( -trackRect.x, -trackRect.y );
  183. }
  184. public void paintFocus(Graphics g) {
  185. }
  186. protected Dimension getThumbSize() {
  187. Dimension size = new Dimension();
  188. if ( slider.getOrientation() == JSlider.VERTICAL ) {
  189. size.width = 16;
  190. size.height = 15;
  191. }
  192. else {
  193. size.width = 15;
  194. size.height = 16;
  195. }
  196. return size;
  197. }
  198. /**
  199. * Gets the height of the tick area for horizontal sliders and the width of the
  200. * tick area for vertical sliders. BasicSliderUI uses the returned value to
  201. * determine the tick area rectangle.
  202. */
  203. public int getTickLength() {
  204. return slider.getOrientation() == JSlider.HORIZONTAL ? tickLength + TICK_BUFFER + 1 :
  205. tickLength + TICK_BUFFER + 3;
  206. }
  207. /**
  208. * Returns the shorter dimension of the track.
  209. */
  210. protected int getTrackWidth() {
  211. // This strange calculation is here to keep the
  212. // track in proportion to the thumb.
  213. final double kIdealTrackWidth = 7.0;
  214. final double kIdealThumbHeight = 16.0;
  215. final double kWidthScalar = kIdealTrackWidth / kIdealThumbHeight;
  216. if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
  217. return (int)(kWidthScalar * thumbRect.height);
  218. }
  219. else {
  220. return (int)(kWidthScalar * thumbRect.width);
  221. }
  222. }
  223. /**
  224. * Returns the longer dimension of the slide bar. (The slide bar is only the
  225. * part that runs directly under the thumb)
  226. */
  227. protected int getTrackLength() {
  228. if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
  229. return trackRect.width;
  230. }
  231. return trackRect.height;
  232. }
  233. /**
  234. * Returns the amount that the thumb goes past the slide bar.
  235. */
  236. protected int getThumbOverhang() {
  237. return 5;
  238. }
  239. protected void scrollDueToClickInTrack( int dir ) {
  240. scrollByUnit( dir );
  241. }
  242. protected void paintMinorTickForHorizSlider( Graphics g, Rectangle tickBounds, int x ) {
  243. g.setColor( slider.isEnabled() ? slider.getForeground() : MetalLookAndFeel.getControlShadow() );
  244. g.drawLine( x, TICK_BUFFER, x, TICK_BUFFER + (tickLength / 2) );
  245. }
  246. protected void paintMajorTickForHorizSlider( Graphics g, Rectangle tickBounds, int x ) {
  247. g.setColor( slider.isEnabled() ? slider.getForeground() : MetalLookAndFeel.getControlShadow() );
  248. g.drawLine( x, TICK_BUFFER , x, TICK_BUFFER + (tickLength - 1) );
  249. }
  250. protected void paintMinorTickForVertSlider( Graphics g, Rectangle tickBounds, int y ) {
  251. g.setColor( slider.isEnabled() ? slider.getForeground() : MetalLookAndFeel.getControlShadow() );
  252. g.drawLine( TICK_BUFFER, y, TICK_BUFFER + (tickLength / 2), y );
  253. }
  254. protected void paintMajorTickForVertSlider( Graphics g, Rectangle tickBounds, int y ) {
  255. g.setColor( slider.isEnabled() ? slider.getForeground() : MetalLookAndFeel.getControlShadow() );
  256. g.drawLine( TICK_BUFFER, y, TICK_BUFFER + tickLength, y );
  257. }
  258. }