1. /*
  2. * @(#)MetalScrollBarUI.java 1.30 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 java.awt.Component;
  9. import java.awt.Container;
  10. import java.awt.LayoutManager;
  11. import java.awt.Adjustable;
  12. import java.awt.event.AdjustmentListener;
  13. import java.awt.event.AdjustmentEvent;
  14. import java.awt.event.ActionListener;
  15. import java.awt.event.ActionEvent;
  16. import java.awt.event.MouseListener;
  17. import java.awt.event.MouseMotionListener;
  18. import java.awt.event.MouseAdapter;
  19. import java.awt.event.MouseEvent;
  20. import java.awt.Graphics;
  21. import java.awt.Dimension;
  22. import java.awt.Rectangle;
  23. import java.awt.Point;
  24. import java.awt.Insets;
  25. import java.awt.Color;
  26. import java.awt.IllegalComponentStateException;
  27. import java.beans.*;
  28. import javax.swing.*;
  29. import javax.swing.event.*;
  30. import javax.swing.plaf.*;
  31. import javax.swing.plaf.basic.BasicScrollBarUI;
  32. /**
  33. * Implementation of ScrollBarUI for the Metal Look and Feel
  34. * <p>
  35. *
  36. * @version 1.21 08/26/98
  37. * @author Tom Santos
  38. * @author Steve Wilson
  39. */
  40. public class MetalScrollBarUI extends BasicScrollBarUI
  41. {
  42. private static Color shadowColor;
  43. private static Color highlightColor;
  44. private static Color darkShadowColor;
  45. private static Color thumbColor;
  46. private static Color thumbShadow;
  47. private static Color thumbHighlightColor;
  48. protected MetalBumps bumps;
  49. protected MetalScrollButton increaseButton;
  50. protected MetalScrollButton decreaseButton;
  51. protected int scrollBarWidth;
  52. public static final String FREE_STANDING_PROP = "JScrollBar.isFreeStanding";
  53. protected boolean isFreeStanding = true;
  54. public static ComponentUI createUI( JComponent c )
  55. {
  56. return new MetalScrollBarUI();
  57. }
  58. protected void installDefaults() {
  59. scrollBarWidth = ((Integer)(UIManager.get( "ScrollBar.width" ))).intValue();
  60. super.installDefaults();
  61. bumps = new MetalBumps( 10, 10, thumbHighlightColor, thumbShadow, thumbColor );
  62. }
  63. protected void installListeners(){
  64. super.installListeners();
  65. ((ScrollBarListener)propertyChangeListener).handlePropertyChange( scrollbar.getClientProperty( FREE_STANDING_PROP ) );
  66. }
  67. protected PropertyChangeListener createPropertyChangeListener(){
  68. return new ScrollBarListener();
  69. }
  70. protected void configureScrollBarColors()
  71. {
  72. super.configureScrollBarColors();
  73. shadowColor = UIManager.getColor("ScrollBar.shadow");
  74. highlightColor = UIManager.getColor("ScrollBar.highlight");
  75. darkShadowColor = UIManager.getColor("ScrollBar.darkShadow");
  76. thumbColor = UIManager.getColor("ScrollBar.thumb");
  77. thumbShadow = UIManager.getColor("ScrollBar.thumbShadow");
  78. thumbHighlightColor = UIManager.getColor("ScrollBar.thumbHighlight");
  79. }
  80. public Dimension getPreferredSize( JComponent c )
  81. {
  82. if ( scrollbar.getOrientation() == JScrollBar.VERTICAL )
  83. {
  84. return new Dimension( scrollBarWidth, scrollBarWidth * 3 + 10 );
  85. }
  86. else // Horizontal
  87. {
  88. return new Dimension( scrollBarWidth * 3 + 10, scrollBarWidth );
  89. }
  90. }
  91. /** Returns the view that represents the decrease view.
  92. */
  93. protected JButton createDecreaseButton( int orientation )
  94. {
  95. decreaseButton = new MetalScrollButton( orientation, scrollBarWidth, isFreeStanding );
  96. return decreaseButton;
  97. }
  98. /** Returns the view that represents the increase view. */
  99. protected JButton createIncreaseButton( int orientation )
  100. {
  101. increaseButton = new MetalScrollButton( orientation, scrollBarWidth, isFreeStanding );
  102. return increaseButton;
  103. }
  104. protected void paintTrack( Graphics g, JComponent c, Rectangle trackBounds )
  105. {
  106. g.translate( trackBounds.x, trackBounds.y );
  107. boolean leftToRight = MetalUtils.isLeftToRight(c);
  108. if ( scrollbar.getOrientation() == JScrollBar.VERTICAL )
  109. {
  110. if ( !isFreeStanding ) {
  111. if ( !leftToRight ) {
  112. trackBounds.width += 1;
  113. g.translate( -1, 0 );
  114. } else {
  115. trackBounds.width += 2;
  116. }
  117. }
  118. if ( c.isEnabled() ) {
  119. g.setColor( darkShadowColor );
  120. g.drawLine( 0, 0, 0, trackBounds.height - 1 );
  121. g.drawLine( trackBounds.width - 2, 0, trackBounds.width - 2, trackBounds.height - 1 );
  122. g.drawLine( 2, trackBounds.height - 1, trackBounds.width - 1, trackBounds.height - 1);
  123. g.drawLine( 2, 0, trackBounds.width - 2, 0 );
  124. g.setColor( shadowColor );
  125. // g.setColor( Color.red);
  126. g.drawLine( 1, 1, 1, trackBounds.height - 2 );
  127. g.drawLine( 1, 1, trackBounds.width - 3, 1 );
  128. if (scrollbar.getValue() != scrollbar.getMaximum()) { // thumb shadow
  129. int y = thumbRect.y + thumbRect.height - trackBounds.y;
  130. g.drawLine( 1, y, trackBounds.width-1, y);
  131. }
  132. g.setColor(highlightColor);
  133. g.drawLine( trackBounds.width - 1, 0, trackBounds.width - 1, trackBounds.height - 1 );
  134. } else {
  135. MetalUtils.drawDisabledBorder(g, 0, 0, trackBounds.width, trackBounds.height );
  136. }
  137. if ( !isFreeStanding ) {
  138. if ( !leftToRight ) {
  139. trackBounds.width -= 1;
  140. g.translate( 1, 0 );
  141. } else {
  142. trackBounds.width -= 2;
  143. }
  144. }
  145. }
  146. else // HORIZONTAL
  147. {
  148. if ( !isFreeStanding ) {
  149. trackBounds.height += 2;
  150. }
  151. if ( c.isEnabled() ) {
  152. g.setColor( darkShadowColor );
  153. g.drawLine( 0, 0, trackBounds.width - 1, 0 ); // top
  154. g.drawLine( 0, 2, 0, trackBounds.height - 2 ); // left
  155. g.drawLine( 0, trackBounds.height - 2, trackBounds.width - 1, trackBounds.height - 2 ); // bottom
  156. g.drawLine( trackBounds.width - 1, 2, trackBounds.width - 1, trackBounds.height - 1 ); // right
  157. g.setColor( shadowColor );
  158. // g.setColor( Color.red);
  159. g.drawLine( 1, 1, trackBounds.width - 2, 1 ); // top
  160. g.drawLine( 1, 1, 1, trackBounds.height - 3 ); // left
  161. g.drawLine( 0, trackBounds.height - 1, trackBounds.width - 1, trackBounds.height - 1 ); // bottom
  162. if (scrollbar.getValue() != scrollbar.getMaximum()) { // thumb shadow
  163. int x = thumbRect.x + thumbRect.width - trackBounds.x;
  164. g.drawLine( x, 1, x, trackBounds.height-1);
  165. }
  166. } else {
  167. MetalUtils.drawDisabledBorder(g, 0, 0, trackBounds.width, trackBounds.height );
  168. }
  169. if ( !isFreeStanding ) {
  170. trackBounds.height -= 2;
  171. }
  172. }
  173. g.translate( -trackBounds.x, -trackBounds.y );
  174. }
  175. protected void paintThumb( Graphics g, JComponent c, Rectangle thumbBounds )
  176. {
  177. if (!c.isEnabled()) {
  178. return;
  179. }
  180. boolean leftToRight = MetalUtils.isLeftToRight(c);
  181. g.translate( thumbBounds.x, thumbBounds.y );
  182. if ( scrollbar.getOrientation() == JScrollBar.VERTICAL )
  183. {
  184. if ( !isFreeStanding ) {
  185. if ( !leftToRight ) {
  186. thumbBounds.width += 1;
  187. g.translate( -1, 0 );
  188. } else {
  189. thumbBounds.width += 2;
  190. }
  191. }
  192. g.setColor( thumbColor );
  193. g.fillRect( 0, 0, thumbBounds.width - 2, thumbBounds.height - 1 );
  194. g.setColor( thumbShadow );
  195. g.drawRect( 0, 0, thumbBounds.width - 2, thumbBounds.height - 1 );
  196. g.setColor( thumbHighlightColor );
  197. g.drawLine( 1, 1, thumbBounds.width - 3, 1 );
  198. g.drawLine( 1, 1, 1, thumbBounds.height - 2 );
  199. bumps.setBumpArea( thumbBounds.width - 6, thumbBounds.height - 7 );
  200. bumps.paintIcon( c, g, 3, 4 );
  201. if ( !isFreeStanding ) {
  202. if ( !leftToRight ) {
  203. thumbBounds.width -= 1;
  204. g.translate( 1, 0 );
  205. } else {
  206. thumbBounds.width -= 2;
  207. }
  208. }
  209. }
  210. else // HORIZONTAL
  211. {
  212. if ( !isFreeStanding ) {
  213. thumbBounds.height += 2;
  214. }
  215. g.setColor( thumbColor );
  216. g.fillRect( 0, 0, thumbBounds.width - 1, thumbBounds.height - 2 );
  217. g.setColor( thumbShadow );
  218. g.drawRect( 0, 0, thumbBounds.width - 1, thumbBounds.height - 2 );
  219. g.setColor( thumbHighlightColor );
  220. g.drawLine( 1, 1, thumbBounds.width - 3, 1 );
  221. g.drawLine( 1, 1, 1, thumbBounds.height - 3 );
  222. bumps.setBumpArea( thumbBounds.width - 7, thumbBounds.height - 6 );
  223. bumps.paintIcon( c, g, 4, 3 );
  224. if ( !isFreeStanding ) {
  225. thumbBounds.height -= 2;
  226. }
  227. }
  228. g.translate( -thumbBounds.x, -thumbBounds.y );
  229. }
  230. protected Dimension getMinimumThumbSize()
  231. {
  232. return new Dimension( scrollBarWidth, scrollBarWidth );
  233. }
  234. /**
  235. * This is overridden only to increase the invalid area. This
  236. * ensures that the "Shadow" below the thumb is invalidated
  237. */
  238. protected void setThumbBounds(int x, int y, int width, int height)
  239. {
  240. /* If the thumbs bounds haven't changed, we're done.
  241. */
  242. if ((thumbRect.x == x) &&
  243. (thumbRect.y == y) &&
  244. (thumbRect.width == width) &&
  245. (thumbRect.height == height)) {
  246. return;
  247. }
  248. /* Update thumbRect, and repaint the union of x,y,w,h and
  249. * the old thumbRect.
  250. */
  251. int minX = Math.min(x, thumbRect.x);
  252. int minY = Math.min(y, thumbRect.y);
  253. int maxX = Math.max(x + width, thumbRect.x + thumbRect.width);
  254. int maxY = Math.max(y + height, thumbRect.y + thumbRect.height);
  255. thumbRect.setBounds(x, y, width, height);
  256. scrollbar.repaint(minX, minY, (maxX - minX)+1, (maxY - minY)+1);
  257. }
  258. class ScrollBarListener extends BasicScrollBarUI.PropertyChangeHandler
  259. {
  260. public void propertyChange(PropertyChangeEvent e)
  261. {
  262. String name = e.getPropertyName();
  263. if ( name.equals( FREE_STANDING_PROP ) )
  264. {
  265. handlePropertyChange( e.getNewValue() );
  266. }
  267. else {
  268. super.propertyChange( e );
  269. }
  270. }
  271. public void handlePropertyChange( Object newValue )
  272. {
  273. if ( newValue != null )
  274. {
  275. boolean temp = ((Boolean)newValue).booleanValue();
  276. boolean becameFlush = temp == false && isFreeStanding == true;
  277. boolean becameNormal = temp == true && isFreeStanding == false;
  278. isFreeStanding = temp;
  279. if ( becameFlush ) {
  280. toFlush();
  281. }
  282. else if ( becameNormal ) {
  283. toFreeStanding();
  284. }
  285. }
  286. else
  287. {
  288. if ( !isFreeStanding ) {
  289. isFreeStanding = true;
  290. toFreeStanding();
  291. }
  292. // This commented-out block is used for testing flush scrollbars.
  293. /*
  294. if ( isFreeStanding ) {
  295. isFreeStanding = false;
  296. toFlush();
  297. }
  298. */
  299. }
  300. if ( increaseButton != null )
  301. {
  302. increaseButton.setFreeStanding( isFreeStanding );
  303. }
  304. if ( decreaseButton != null )
  305. {
  306. decreaseButton.setFreeStanding( isFreeStanding );
  307. }
  308. }
  309. protected void toFlush() {
  310. scrollBarWidth -= 2;
  311. }
  312. protected void toFreeStanding() {
  313. scrollBarWidth += 2;
  314. }
  315. } // end class ScrollBarListener
  316. }