1. /*
  2. * @(#)MetalScrollBarUI.java 1.34 04/03/03
  3. *
  4. * Copyright 2004 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. trackBounds.width += 2;
  112. if ( !leftToRight ) {
  113. g.translate( -1, 0 );
  114. }
  115. }
  116. if ( c.isEnabled() ) {
  117. g.setColor( darkShadowColor );
  118. g.drawLine( 0, 0, 0, trackBounds.height - 1 );
  119. g.drawLine( trackBounds.width - 2, 0, trackBounds.width - 2, trackBounds.height - 1 );
  120. g.drawLine( 2, trackBounds.height - 1, trackBounds.width - 1, trackBounds.height - 1);
  121. g.drawLine( 2, 0, trackBounds.width - 2, 0 );
  122. g.setColor( shadowColor );
  123. // g.setColor( Color.red);
  124. g.drawLine( 1, 1, 1, trackBounds.height - 2 );
  125. g.drawLine( 1, 1, trackBounds.width - 3, 1 );
  126. if (scrollbar.getValue() != scrollbar.getMaximum()) { // thumb shadow
  127. int y = thumbRect.y + thumbRect.height - trackBounds.y;
  128. g.drawLine( 1, y, trackBounds.width-1, y);
  129. }
  130. g.setColor(highlightColor);
  131. g.drawLine( trackBounds.width - 1, 0, trackBounds.width - 1, trackBounds.height - 1 );
  132. } else {
  133. MetalUtils.drawDisabledBorder(g, 0, 0, trackBounds.width, trackBounds.height );
  134. }
  135. if ( !isFreeStanding ) {
  136. trackBounds.width -= 2;
  137. if ( !leftToRight ) {
  138. g.translate( 1, 0 );
  139. }
  140. }
  141. }
  142. else // HORIZONTAL
  143. {
  144. if ( !isFreeStanding ) {
  145. trackBounds.height += 2;
  146. }
  147. if ( c.isEnabled() ) {
  148. g.setColor( darkShadowColor );
  149. g.drawLine( 0, 0, trackBounds.width - 1, 0 ); // top
  150. g.drawLine( 0, 2, 0, trackBounds.height - 2 ); // left
  151. g.drawLine( 0, trackBounds.height - 2, trackBounds.width - 1, trackBounds.height - 2 ); // bottom
  152. g.drawLine( trackBounds.width - 1, 2, trackBounds.width - 1, trackBounds.height - 1 ); // right
  153. g.setColor( shadowColor );
  154. // g.setColor( Color.red);
  155. g.drawLine( 1, 1, trackBounds.width - 2, 1 ); // top
  156. g.drawLine( 1, 1, 1, trackBounds.height - 3 ); // left
  157. g.drawLine( 0, trackBounds.height - 1, trackBounds.width - 1, trackBounds.height - 1 ); // bottom
  158. if (scrollbar.getValue() != scrollbar.getMaximum()) { // thumb shadow
  159. int x = thumbRect.x + thumbRect.width - trackBounds.x;
  160. g.drawLine( x, 1, x, trackBounds.height-1);
  161. }
  162. } else {
  163. MetalUtils.drawDisabledBorder(g, 0, 0, trackBounds.width, trackBounds.height );
  164. }
  165. if ( !isFreeStanding ) {
  166. trackBounds.height -= 2;
  167. }
  168. }
  169. g.translate( -trackBounds.x, -trackBounds.y );
  170. }
  171. protected void paintThumb( Graphics g, JComponent c, Rectangle thumbBounds )
  172. {
  173. if (!c.isEnabled()) {
  174. return;
  175. }
  176. if (MetalLookAndFeel.usingOcean()) {
  177. oceanPaintThumb(g, c, thumbBounds);
  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. thumbBounds.width += 2;
  186. if ( !leftToRight ) {
  187. g.translate( -1, 0 );
  188. }
  189. }
  190. g.setColor( thumbColor );
  191. g.fillRect( 0, 0, thumbBounds.width - 2, thumbBounds.height - 1 );
  192. g.setColor( thumbShadow );
  193. g.drawRect( 0, 0, thumbBounds.width - 2, thumbBounds.height - 1 );
  194. g.setColor( thumbHighlightColor );
  195. g.drawLine( 1, 1, thumbBounds.width - 3, 1 );
  196. g.drawLine( 1, 1, 1, thumbBounds.height - 2 );
  197. bumps.setBumpArea( thumbBounds.width - 6, thumbBounds.height - 7 );
  198. bumps.paintIcon( c, g, 3, 4 );
  199. if ( !isFreeStanding ) {
  200. thumbBounds.width -= 2;
  201. if ( !leftToRight ) {
  202. g.translate( 1, 0 );
  203. }
  204. }
  205. }
  206. else // HORIZONTAL
  207. {
  208. if ( !isFreeStanding ) {
  209. thumbBounds.height += 2;
  210. }
  211. g.setColor( thumbColor );
  212. g.fillRect( 0, 0, thumbBounds.width - 1, thumbBounds.height - 2 );
  213. g.setColor( thumbShadow );
  214. g.drawRect( 0, 0, thumbBounds.width - 1, thumbBounds.height - 2 );
  215. g.setColor( thumbHighlightColor );
  216. g.drawLine( 1, 1, thumbBounds.width - 3, 1 );
  217. g.drawLine( 1, 1, 1, thumbBounds.height - 3 );
  218. bumps.setBumpArea( thumbBounds.width - 7, thumbBounds.height - 6 );
  219. bumps.paintIcon( c, g, 4, 3 );
  220. if ( !isFreeStanding ) {
  221. thumbBounds.height -= 2;
  222. }
  223. }
  224. g.translate( -thumbBounds.x, -thumbBounds.y );
  225. }
  226. private void oceanPaintThumb(Graphics g, JComponent c,
  227. Rectangle thumbBounds) {
  228. boolean leftToRight = MetalUtils.isLeftToRight(c);
  229. g.translate(thumbBounds.x, thumbBounds.y);
  230. if (scrollbar.getOrientation() == JScrollBar.VERTICAL) {
  231. if (!isFreeStanding) {
  232. thumbBounds.width += 2;
  233. if (!leftToRight) {
  234. g.translate(-1, 0);
  235. }
  236. }
  237. if (thumbColor != null) {
  238. g.setColor(thumbColor);
  239. g.fillRect(0, 0, thumbBounds.width - 2,thumbBounds.height - 1);
  240. }
  241. g.setColor(thumbShadow);
  242. g.drawRect(0, 0, thumbBounds.width - 2, thumbBounds.height - 1);
  243. g.setColor(thumbHighlightColor);
  244. g.drawLine(1, 1, thumbBounds.width - 3, 1);
  245. g.drawLine(1, 1, 1, thumbBounds.height - 2);
  246. MetalUtils.drawGradient(c, g, "ScrollBar.gradient", 2, 2,
  247. thumbBounds.width - 4,
  248. thumbBounds.height - 3, false);
  249. int gripSize = thumbBounds.width - 8;
  250. if (gripSize > 2 && thumbBounds.height >= 10) {
  251. g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow());
  252. int gripY = thumbBounds.height / 2 - 2;
  253. for (int counter = 0; counter < 6; counter += 2) {
  254. g.fillRect(4, counter + gripY, gripSize, 1);
  255. }
  256. g.setColor(MetalLookAndFeel.getWhite());
  257. gripY++;
  258. for (int counter = 0; counter < 6; counter += 2) {
  259. g.fillRect(5, counter + gripY, gripSize, 1);
  260. }
  261. }
  262. if (!isFreeStanding) {
  263. thumbBounds.width -= 2;
  264. if (!leftToRight) {
  265. g.translate(1, 0);
  266. }
  267. }
  268. }
  269. else { // HORIZONTAL
  270. if (!isFreeStanding) {
  271. thumbBounds.height += 2;
  272. }
  273. if (thumbColor != null) {
  274. g.setColor(thumbColor);
  275. g.fillRect(0, 0, thumbBounds.width - 1,thumbBounds.height - 2);
  276. }
  277. g.setColor(thumbShadow);
  278. g.drawRect(0, 0, thumbBounds.width - 1, thumbBounds.height - 2);
  279. g.setColor(thumbHighlightColor);
  280. g.drawLine(1, 1, thumbBounds.width - 2, 1);
  281. g.drawLine(1, 1, 1, thumbBounds.height - 3);
  282. MetalUtils.drawGradient(c, g, "ScrollBar.gradient", 2, 2,
  283. thumbBounds.width - 3,
  284. thumbBounds.height - 4, true);
  285. int gripSize = thumbBounds.height - 8;
  286. if (gripSize > 2 && thumbBounds.width >= 10) {
  287. g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow());
  288. int gripX = thumbBounds.width / 2 - 2;
  289. for (int counter = 0; counter < 6; counter += 2) {
  290. g.fillRect(gripX + counter, 4, 1, gripSize);
  291. }
  292. g.setColor(MetalLookAndFeel.getWhite());
  293. gripX++;
  294. for (int counter = 0; counter < 6; counter += 2) {
  295. g.fillRect(gripX + counter, 5, 1, gripSize);
  296. }
  297. }
  298. if (!isFreeStanding) {
  299. thumbBounds.height -= 2;
  300. }
  301. }
  302. g.translate( -thumbBounds.x, -thumbBounds.y );
  303. }
  304. protected Dimension getMinimumThumbSize()
  305. {
  306. return new Dimension( scrollBarWidth, scrollBarWidth );
  307. }
  308. /**
  309. * This is overridden only to increase the invalid area. This
  310. * ensures that the "Shadow" below the thumb is invalidated
  311. */
  312. protected void setThumbBounds(int x, int y, int width, int height)
  313. {
  314. /* If the thumbs bounds haven't changed, we're done.
  315. */
  316. if ((thumbRect.x == x) &&
  317. (thumbRect.y == y) &&
  318. (thumbRect.width == width) &&
  319. (thumbRect.height == height)) {
  320. return;
  321. }
  322. /* Update thumbRect, and repaint the union of x,y,w,h and
  323. * the old thumbRect.
  324. */
  325. int minX = Math.min(x, thumbRect.x);
  326. int minY = Math.min(y, thumbRect.y);
  327. int maxX = Math.max(x + width, thumbRect.x + thumbRect.width);
  328. int maxY = Math.max(y + height, thumbRect.y + thumbRect.height);
  329. thumbRect.setBounds(x, y, width, height);
  330. scrollbar.repaint(minX, minY, (maxX - minX)+1, (maxY - minY)+1);
  331. }
  332. class ScrollBarListener extends BasicScrollBarUI.PropertyChangeHandler
  333. {
  334. public void propertyChange(PropertyChangeEvent e)
  335. {
  336. String name = e.getPropertyName();
  337. if ( name.equals( FREE_STANDING_PROP ) )
  338. {
  339. handlePropertyChange( e.getNewValue() );
  340. }
  341. else {
  342. super.propertyChange( e );
  343. }
  344. }
  345. public void handlePropertyChange( Object newValue )
  346. {
  347. if ( newValue != null )
  348. {
  349. boolean temp = ((Boolean)newValue).booleanValue();
  350. boolean becameFlush = temp == false && isFreeStanding == true;
  351. boolean becameNormal = temp == true && isFreeStanding == false;
  352. isFreeStanding = temp;
  353. if ( becameFlush ) {
  354. toFlush();
  355. }
  356. else if ( becameNormal ) {
  357. toFreeStanding();
  358. }
  359. }
  360. else
  361. {
  362. if ( !isFreeStanding ) {
  363. isFreeStanding = true;
  364. toFreeStanding();
  365. }
  366. // This commented-out block is used for testing flush scrollbars.
  367. /*
  368. if ( isFreeStanding ) {
  369. isFreeStanding = false;
  370. toFlush();
  371. }
  372. */
  373. }
  374. if ( increaseButton != null )
  375. {
  376. increaseButton.setFreeStanding( isFreeStanding );
  377. }
  378. if ( decreaseButton != null )
  379. {
  380. decreaseButton.setFreeStanding( isFreeStanding );
  381. }
  382. }
  383. protected void toFlush() {
  384. scrollBarWidth -= 2;
  385. }
  386. protected void toFreeStanding() {
  387. scrollBarWidth += 2;
  388. }
  389. } // end class ScrollBarListener
  390. }