1. /*
  2. * @(#)MetalSliderUI.java 1.32 03/01/23
  3. *
  4. * Copyright 2003 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
  31. * appropriate for short term storage or RMI between applications running
  32. * the same version of Swing. As of 1.4, support for long term storage
  33. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  34. * has been added to the <code>java.beans</code> package.
  35. * Please see {@link java.beans.XMLEncoder}.
  36. *
  37. * @version 1.32 01/23/03
  38. * @author Tom Santos
  39. */
  40. public class MetalSliderUI extends BasicSliderUI {
  41. protected final int TICK_BUFFER = 4;
  42. protected boolean filledSlider = false;
  43. protected static Color thumbColor;
  44. protected static Color highlightColor;
  45. protected static Color darkShadowColor;
  46. protected static int trackWidth;
  47. protected static int tickLength;
  48. protected static Icon horizThumbIcon;
  49. protected static Icon vertThumbIcon;
  50. protected final String SLIDER_FILL = "JSlider.isFilled";
  51. public static ComponentUI createUI(JComponent c) {
  52. return new MetalSliderUI();
  53. }
  54. public MetalSliderUI() {
  55. super( null );
  56. }
  57. public void installUI( JComponent c ) {
  58. trackWidth = ((Integer)UIManager.get( "Slider.trackWidth" )).intValue();
  59. tickLength = ((Integer)UIManager.get( "Slider.majorTickLength" )).intValue();
  60. horizThumbIcon = UIManager.getIcon( "Slider.horizontalThumbIcon" );
  61. vertThumbIcon = UIManager.getIcon( "Slider.verticalThumbIcon" );
  62. super.installUI( c );
  63. thumbColor = UIManager.getColor("Slider.thumb");
  64. highlightColor = UIManager.getColor("Slider.highlight");
  65. darkShadowColor = UIManager.getColor("Slider.darkShadow");
  66. scrollListener.setScrollByBlock( false );
  67. Object sliderFillProp = c.getClientProperty( SLIDER_FILL );
  68. if ( sliderFillProp != null ) {
  69. filledSlider = ((Boolean)sliderFillProp).booleanValue();
  70. }
  71. }
  72. protected PropertyChangeListener createPropertyChangeListener( JSlider slider ) {
  73. return new MetalPropertyListener();
  74. }
  75. protected class MetalPropertyListener extends BasicSliderUI.PropertyChangeHandler {
  76. public void propertyChange( PropertyChangeEvent e ) { // listen for slider fill
  77. super.propertyChange( e );
  78. String name = e.getPropertyName();
  79. if ( name.equals( SLIDER_FILL ) ) {
  80. if ( e.getNewValue() != null ) {
  81. filledSlider = ((Boolean)e.getNewValue()).booleanValue();
  82. }
  83. else {
  84. filledSlider = false;
  85. }
  86. }
  87. }
  88. }
  89. public void paintThumb(Graphics g) {
  90. Rectangle knobBounds = thumbRect;
  91. g.translate( knobBounds.x, knobBounds.y );
  92. if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
  93. horizThumbIcon.paintIcon( slider, g, 0, 0 );
  94. }
  95. else {
  96. vertThumbIcon.paintIcon( slider, g, 0, 0 );
  97. }
  98. g.translate( -knobBounds.x, -knobBounds.y );
  99. }
  100. public void paintTrack(Graphics g) {
  101. Color trackColor = !slider.isEnabled() ? MetalLookAndFeel.getControlShadow() :
  102. slider.getForeground();
  103. boolean leftToRight = MetalUtils.isLeftToRight(slider);
  104. g.translate( trackRect.x, trackRect.y );
  105. int trackLeft = 0;
  106. int trackTop = 0;
  107. int trackRight = 0;
  108. int trackBottom = 0;
  109. // Draw the track
  110. if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
  111. trackBottom = (trackRect.height - 1) - getThumbOverhang();
  112. trackTop = trackBottom - (getTrackWidth() - 1);
  113. trackRight = trackRect.width - 1;
  114. }
  115. else {
  116. if (leftToRight) {
  117. trackLeft = (trackRect.width - getThumbOverhang()) -
  118. getTrackWidth();
  119. trackRight = (trackRect.width - getThumbOverhang()) - 1;
  120. }
  121. else {
  122. trackLeft = getThumbOverhang();
  123. trackRight = getThumbOverhang() + getTrackWidth() - 1;
  124. }
  125. trackBottom = trackRect.height - 1;
  126. }
  127. if ( slider.isEnabled() ) {
  128. g.setColor( MetalLookAndFeel.getControlDarkShadow() );
  129. g.drawRect( trackLeft, trackTop,
  130. (trackRight - trackLeft) - 1, (trackBottom - trackTop) - 1 );
  131. g.setColor( MetalLookAndFeel.getControlHighlight() );
  132. g.drawLine( trackLeft + 1, trackBottom, trackRight, trackBottom );
  133. g.drawLine( trackRight, trackTop + 1, trackRight, trackBottom );
  134. g.setColor( MetalLookAndFeel.getControlShadow() );
  135. g.drawLine( trackLeft + 1, trackTop + 1, trackRight - 2, trackTop + 1 );
  136. g.drawLine( trackLeft + 1, trackTop + 1, trackLeft + 1, trackBottom - 2 );
  137. }
  138. else {
  139. g.setColor( MetalLookAndFeel.getControlShadow() );
  140. g.drawRect( trackLeft, trackTop,
  141. (trackRight - trackLeft) - 1, (trackBottom - trackTop) - 1 );
  142. }
  143. // Draw the fill
  144. if ( filledSlider ) {
  145. int middleOfThumb = 0;
  146. int fillTop = 0;
  147. int fillLeft = 0;
  148. int fillBottom = 0;
  149. int fillRight = 0;
  150. if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
  151. middleOfThumb = thumbRect.x + (thumbRect.width / 2);
  152. middleOfThumb -= trackRect.x; // To compensate for the g.translate()
  153. fillTop = !slider.isEnabled() ? trackTop : trackTop + 1;
  154. fillBottom = !slider.isEnabled() ? trackBottom - 1 : trackBottom - 2;
  155. if ( !drawInverted() ) {
  156. fillLeft = !slider.isEnabled() ? trackLeft : trackLeft + 1;
  157. fillRight = middleOfThumb;
  158. }
  159. else {
  160. fillLeft = middleOfThumb;
  161. fillRight = !slider.isEnabled() ? trackRight - 1 : trackRight - 2;
  162. }
  163. }
  164. else {
  165. middleOfThumb = thumbRect.y + (thumbRect.height / 2);
  166. middleOfThumb -= trackRect.y; // To compensate for the g.translate()
  167. fillLeft = !slider.isEnabled() ? trackLeft : trackLeft + 1;
  168. fillRight = !slider.isEnabled() ? trackRight - 1 : trackRight - 2;
  169. if ( !drawInverted() ) {
  170. fillTop = middleOfThumb;
  171. fillBottom = !slider.isEnabled() ? trackBottom - 1 : trackBottom - 2;
  172. }
  173. else {
  174. fillTop = !slider.isEnabled() ? trackTop : trackTop + 1;
  175. fillBottom = middleOfThumb;
  176. }
  177. }
  178. if ( slider.isEnabled() ) {
  179. g.setColor( slider.getBackground() );
  180. g.drawLine( fillLeft, fillTop, fillRight, fillTop );
  181. g.drawLine( fillLeft, fillTop, fillLeft, fillBottom );
  182. g.setColor( MetalLookAndFeel.getControlShadow() );
  183. g.fillRect( fillLeft + 1, fillTop + 1,
  184. fillRight - fillLeft, fillBottom - fillTop );
  185. }
  186. else {
  187. g.setColor( MetalLookAndFeel.getControlShadow() );
  188. g.fillRect( fillLeft, fillTop,
  189. fillRight - fillLeft, trackBottom - trackTop );
  190. }
  191. }
  192. g.translate( -trackRect.x, -trackRect.y );
  193. }
  194. public void paintFocus(Graphics g) {
  195. }
  196. protected Dimension getThumbSize() {
  197. Dimension size = new Dimension();
  198. if ( slider.getOrientation() == JSlider.VERTICAL ) {
  199. size.width = vertThumbIcon.getIconWidth();
  200. size.height = vertThumbIcon.getIconHeight();
  201. }
  202. else {
  203. size.width = horizThumbIcon.getIconWidth();
  204. size.height = horizThumbIcon.getIconHeight();
  205. }
  206. return size;
  207. }
  208. /**
  209. * Gets the height of the tick area for horizontal sliders and the width of the
  210. * tick area for vertical sliders. BasicSliderUI uses the returned value to
  211. * determine the tick area rectangle.
  212. */
  213. public int getTickLength() {
  214. return slider.getOrientation() == JSlider.HORIZONTAL ? tickLength + TICK_BUFFER + 1 :
  215. tickLength + TICK_BUFFER + 3;
  216. }
  217. /**
  218. * Returns the shorter dimension of the track.
  219. */
  220. protected int getTrackWidth() {
  221. // This strange calculation is here to keep the
  222. // track in proportion to the thumb.
  223. final double kIdealTrackWidth = 7.0;
  224. final double kIdealThumbHeight = 16.0;
  225. final double kWidthScalar = kIdealTrackWidth / kIdealThumbHeight;
  226. if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
  227. return (int)(kWidthScalar * thumbRect.height);
  228. }
  229. else {
  230. return (int)(kWidthScalar * thumbRect.width);
  231. }
  232. }
  233. /**
  234. * Returns the longer dimension of the slide bar. (The slide bar is only the
  235. * part that runs directly under the thumb)
  236. */
  237. protected int getTrackLength() {
  238. if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
  239. return trackRect.width;
  240. }
  241. return trackRect.height;
  242. }
  243. /**
  244. * Returns the amount that the thumb goes past the slide bar.
  245. */
  246. protected int getThumbOverhang() {
  247. return (int)(getThumbSize().getHeight()-getTrackWidth())/2;
  248. }
  249. protected void scrollDueToClickInTrack( int dir ) {
  250. scrollByUnit( dir );
  251. }
  252. protected void paintMinorTickForHorizSlider( Graphics g, Rectangle tickBounds, int x ) {
  253. g.setColor( slider.isEnabled() ? slider.getForeground() : MetalLookAndFeel.getControlShadow() );
  254. g.drawLine( x, TICK_BUFFER, x, TICK_BUFFER + (tickLength / 2) );
  255. }
  256. protected void paintMajorTickForHorizSlider( Graphics g, Rectangle tickBounds, int x ) {
  257. g.setColor( slider.isEnabled() ? slider.getForeground() : MetalLookAndFeel.getControlShadow() );
  258. g.drawLine( x, TICK_BUFFER , x, TICK_BUFFER + (tickLength - 1) );
  259. }
  260. protected void paintMinorTickForVertSlider( Graphics g, Rectangle tickBounds, int y ) {
  261. g.setColor( slider.isEnabled() ? slider.getForeground() : MetalLookAndFeel.getControlShadow() );
  262. if (MetalUtils.isLeftToRight(slider)) {
  263. g.drawLine( TICK_BUFFER, y, TICK_BUFFER + (tickLength / 2), y );
  264. }
  265. else {
  266. g.drawLine( 0, y, tickLength2, y );
  267. }
  268. }
  269. protected void paintMajorTickForVertSlider( Graphics g, Rectangle tickBounds, int y ) {
  270. g.setColor( slider.isEnabled() ? slider.getForeground() : MetalLookAndFeel.getControlShadow() );
  271. if (MetalUtils.isLeftToRight(slider)) {
  272. g.drawLine( TICK_BUFFER, y, TICK_BUFFER + tickLength, y );
  273. }
  274. else {
  275. g.drawLine( 0, y, tickLength, y );
  276. }
  277. }
  278. }