1. /*
  2. * @(#)WindowsScrollBarUI.java 1.16 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 com.sun.java.swing.plaf.windows;
  8. import java.awt.*;
  9. import java.awt.image.*;
  10. import java.lang.ref.*;
  11. import java.util.*;
  12. import javax.swing.plaf.basic.*;
  13. import javax.swing.*;
  14. import javax.swing.plaf.ComponentUI;
  15. /**
  16. * Windows rendition of the component.
  17. * <p>
  18. * <strong>Warning:</strong>
  19. * Serialized objects of this class will not be compatible with
  20. * future Swing releases. The current serialization support is appropriate
  21. * for short term storage or RMI between applications running the same
  22. * version of Swing. A future release of Swing will provide support for
  23. * long term persistence.
  24. */
  25. public class WindowsScrollBarUI extends BasicScrollBarUI {
  26. private Grid thumbGrid;
  27. private Grid highlightGrid;
  28. /**
  29. * Creates a UI for a JScrollBar.
  30. *
  31. * @param c the text field
  32. * @return the UI
  33. */
  34. public static ComponentUI createUI(JComponent c) {
  35. return new WindowsScrollBarUI();
  36. }
  37. protected void installDefaults() {
  38. super.installDefaults();
  39. if (XPStyle.getXP() != null) {
  40. scrollbar.setBorder(null);
  41. }
  42. }
  43. public Dimension getPreferredSize(JComponent c) {
  44. Dimension d = super.getPreferredSize(c);
  45. XPStyle xp = XPStyle.getXP();
  46. if (xp != null) {
  47. if (scrollbar.getOrientation() == JScrollBar.VERTICAL) {
  48. d.width = xp.getInt("sysmetrics.scrollbarwidth", 17);
  49. } else {
  50. d.height = xp.getInt("sysmetrics.scrollbarheight", 17);
  51. }
  52. }
  53. return d;
  54. }
  55. public void uninstallUI(JComponent c) {
  56. super.uninstallUI(c);
  57. thumbGrid = highlightGrid = null;
  58. }
  59. protected void configureScrollBarColors() {
  60. super.configureScrollBarColors();
  61. Color color = UIManager.getColor("ScrollBar.trackForeground");
  62. if (color != null && trackColor != null) {
  63. thumbGrid = Grid.getGrid(color, trackColor);
  64. }
  65. color = UIManager.getColor("ScrollBar.trackHighlightForeground");
  66. if (color != null && trackHighlightColor != null) {
  67. highlightGrid = Grid.getGrid(color, trackHighlightColor);
  68. }
  69. }
  70. protected JButton createDecreaseButton(int orientation) {
  71. return new WindowsArrowButton(orientation,
  72. UIManager.getColor("ScrollBar.thumb"),
  73. UIManager.getColor("ScrollBar.thumbShadow"),
  74. UIManager.getColor("ScrollBar.thumbDarkShadow"),
  75. UIManager.getColor("ScrollBar.thumbHighlight"));
  76. }
  77. protected JButton createIncreaseButton(int orientation) {
  78. return new WindowsArrowButton(orientation,
  79. UIManager.getColor("ScrollBar.thumb"),
  80. UIManager.getColor("ScrollBar.thumbShadow"),
  81. UIManager.getColor("ScrollBar.thumbDarkShadow"),
  82. UIManager.getColor("ScrollBar.thumbHighlight"));
  83. }
  84. protected void paintTrack(Graphics g, JComponent c, Rectangle trackBounds){
  85. boolean v = (scrollbar.getOrientation() == JScrollBar.VERTICAL);
  86. XPStyle xp = XPStyle.getXP();
  87. if (xp != null) {
  88. JScrollBar sb = (JScrollBar)c;
  89. int index = 0;
  90. // Pending: Implement rollover 1 and pressed 2
  91. if (!sb.isEnabled()) {
  92. index = 3;
  93. }
  94. String category = v ? "scrollbar.lowertrackvert" : "scrollbar.lowertrackhorz";
  95. xp.getSkin(category).paintSkin(g, trackBounds, index);
  96. } else if (thumbGrid == null) {
  97. super.paintTrack(g, c, trackBounds);
  98. }
  99. else {
  100. thumbGrid.paint(g, trackBounds.x, trackBounds.y, trackBounds.width,
  101. trackBounds.height);
  102. if (trackHighlight == DECREASE_HIGHLIGHT) {
  103. paintDecreaseHighlight(g);
  104. }
  105. else if (trackHighlight == INCREASE_HIGHLIGHT) {
  106. paintIncreaseHighlight(g);
  107. }
  108. }
  109. }
  110. protected void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds) {
  111. boolean v = (scrollbar.getOrientation() == JScrollBar.VERTICAL);
  112. XPStyle xp = XPStyle.getXP();
  113. if (xp != null) {
  114. JScrollBar sb = (JScrollBar)c;
  115. int index = 0;
  116. // Pending: Implement rollover 1
  117. if (!sb.isEnabled()) {
  118. index = 3;
  119. } else if (isDragging) {
  120. index = 2;
  121. }
  122. // Paint thumb
  123. XPStyle.Skin skin = xp.getSkin(v ? "scrollbar.thumbbtnvert" : "scrollbar.thumbbtnhorz");
  124. skin.paintSkin(g, thumbBounds, index);
  125. // Paint gripper
  126. skin = xp.getSkin(v ? "scrollbar.grippervert" : "scrollbar.gripperhorz");
  127. skin.paintSkin(g,
  128. thumbBounds.x + (thumbBounds.width - skin.getWidth()) / 2,
  129. thumbBounds.y + (thumbBounds.height - skin.getHeight()) / 2,
  130. skin.getWidth(), skin.getHeight(), index);
  131. } else {
  132. super.paintThumb(g, c, thumbBounds);
  133. }
  134. }
  135. protected void paintDecreaseHighlight(Graphics g) {
  136. if (highlightGrid == null) {
  137. super.paintDecreaseHighlight(g);
  138. }
  139. else {
  140. Insets insets = scrollbar.getInsets();
  141. Rectangle thumbR = getThumbBounds();
  142. int x, y, w, h;
  143. if (scrollbar.getOrientation() == JScrollBar.VERTICAL) {
  144. x = insets.left;
  145. y = decrButton.getY() + decrButton.getHeight();
  146. w = scrollbar.getWidth() - (insets.left + insets.right);
  147. h = thumbR.y - y;
  148. }
  149. else {
  150. x = decrButton.getX() + decrButton.getHeight();
  151. y = insets.top;
  152. w = thumbR.x - x;
  153. h = scrollbar.getHeight() - (insets.top + insets.bottom);
  154. }
  155. highlightGrid.paint(g, x, y, w, h);
  156. }
  157. }
  158. protected void paintIncreaseHighlight(Graphics g) {
  159. if (highlightGrid == null) {
  160. super.paintDecreaseHighlight(g);
  161. }
  162. else {
  163. Insets insets = scrollbar.getInsets();
  164. Rectangle thumbR = getThumbBounds();
  165. int x, y, w, h;
  166. if (scrollbar.getOrientation() == JScrollBar.VERTICAL) {
  167. x = insets.left;
  168. y = thumbR.y + thumbR.height;
  169. w = scrollbar.getWidth() - (insets.left + insets.right);
  170. h = incrButton.getY() - y;
  171. }
  172. else {
  173. x = thumbR.x + thumbR.width;
  174. y = insets.top;
  175. w = incrButton.getX() - x;
  176. h = scrollbar.getHeight() - (insets.top + insets.bottom);
  177. }
  178. highlightGrid.paint(g, x, y, w, h);
  179. }
  180. }
  181. /**
  182. * WindowsArrowButton is used for the buttons to position the
  183. * document up/down. It differs from BasicArrowButton in that the
  184. * preferred size is always a square.
  185. */
  186. private class WindowsArrowButton extends BasicArrowButton {
  187. public WindowsArrowButton(int direction, Color background, Color shadow,
  188. Color darkShadow, Color highlight) {
  189. super(direction, background, shadow, darkShadow, highlight);
  190. }
  191. public WindowsArrowButton(int direction) {
  192. super(direction);
  193. }
  194. public void paint(Graphics g) {
  195. XPStyle xp = XPStyle.getXP();
  196. if (xp != null) {
  197. XPStyle.Skin skin = xp.getSkin("scrollbar.arrowbtn");
  198. int index = 0;
  199. switch (direction) {
  200. case NORTH: index = 0; break;
  201. case SOUTH: index = 4; break;
  202. case WEST: index = 8; break;
  203. case EAST: index = 12; break;
  204. }
  205. skin.paintSkin(g, 0, 0, getSize().width, getSize().height, index);
  206. } else {
  207. super.paint(g);
  208. }
  209. }
  210. public Dimension getPreferredSize() {
  211. int size = 16;
  212. if (scrollbar != null) {
  213. switch (scrollbar.getOrientation()) {
  214. case JScrollBar.VERTICAL:
  215. size = scrollbar.getWidth();
  216. break;
  217. case JScrollBar.HORIZONTAL:
  218. size = scrollbar.getHeight();
  219. break;
  220. }
  221. size = Math.max(size, 5);
  222. }
  223. return new Dimension(size, size);
  224. }
  225. }
  226. /**
  227. * This should be pulled out into its own class if more classes need to
  228. * use it.
  229. * <p>
  230. * Grid is used to draw the track for windows scrollbars. Grids
  231. * are cached in a HashMap, with the key being the rgb components
  232. * of the foreground/background colors. Further the Grid is held through
  233. * a WeakRef so that it can be freed when no longer needed. As the
  234. * Grid is rather expensive to draw, it is drawn in a BufferedImage.
  235. */
  236. private static class Grid {
  237. private static final int BUFFER_SIZE = 64;
  238. private static HashMap map;
  239. private BufferedImage image;
  240. static {
  241. map = new HashMap();
  242. }
  243. public static Grid getGrid(Color fg, Color bg) {
  244. String key = fg.getRGB() + " " + bg.getRGB();
  245. WeakReference ref = (WeakReference)map.get(key);
  246. Grid grid = (ref == null) ? null : (Grid)ref.get();
  247. if (grid == null) {
  248. grid = new Grid(fg, bg);
  249. map.put(key, new WeakReference(grid));
  250. }
  251. return grid;
  252. }
  253. public Grid(Color fg, Color bg) {
  254. int cmap[] = { fg.getRGB(), bg.getRGB() };
  255. IndexColorModel icm = new IndexColorModel(8, 2, cmap, 0, false, -1,
  256. DataBuffer.TYPE_BYTE);
  257. image = new BufferedImage(BUFFER_SIZE, BUFFER_SIZE,
  258. BufferedImage.TYPE_BYTE_INDEXED, icm);
  259. Graphics g = image.getGraphics();
  260. try {
  261. g.setClip(0, 0, BUFFER_SIZE, BUFFER_SIZE);
  262. paintGrid(g, fg, bg);
  263. }
  264. finally {
  265. g.dispose();
  266. }
  267. }
  268. /**
  269. * Paints the grid into the specified Graphics at the specified
  270. * location.
  271. */
  272. public void paint(Graphics g, int x, int y, int w, int h) {
  273. Rectangle clipRect = g.getClipBounds();
  274. int minX = Math.max(x, clipRect.x);
  275. int minY = Math.max(y, clipRect.y);
  276. int maxX = Math.min(clipRect.x + clipRect.width, x + w);
  277. int maxY = Math.min(clipRect.y + clipRect.height, y + h);
  278. if (maxX <= minX || maxY <= minY) {
  279. return;
  280. }
  281. int xOffset = (minX - x) % 2;
  282. for (int xCounter = minX; xCounter < maxX;
  283. xCounter += BUFFER_SIZE) {
  284. int yOffset = (minY - y) % 2;
  285. int width = Math.min(BUFFER_SIZE - xOffset,
  286. maxX - xCounter);
  287. for (int yCounter = minY; yCounter < maxY;
  288. yCounter += BUFFER_SIZE) {
  289. int height = Math.min(BUFFER_SIZE - yOffset,
  290. maxY - yCounter);
  291. g.drawImage(image, xCounter, yCounter,
  292. xCounter + width, yCounter + height,
  293. xOffset, yOffset,
  294. xOffset + width, yOffset + height, null);
  295. if (yOffset != 0) {
  296. yCounter -= yOffset;
  297. yOffset = 0;
  298. }
  299. }
  300. if (xOffset != 0) {
  301. xCounter -= xOffset;
  302. xOffset = 0;
  303. }
  304. }
  305. }
  306. /**
  307. * Actually renders the grid into the Graphics <code>g</code>.
  308. */
  309. private void paintGrid(Graphics g, Color fg, Color bg) {
  310. Rectangle clipRect = g.getClipBounds();
  311. g.setColor(bg);
  312. g.fillRect(clipRect.x, clipRect.y, clipRect.width,
  313. clipRect.height);
  314. g.setColor(fg);
  315. g.translate(clipRect.x, clipRect.y);
  316. int width = clipRect.width;
  317. int height = clipRect.height;
  318. int xCounter = clipRect.x % 2;
  319. for (int end = width - height; xCounter < end; xCounter += 2) {
  320. g.drawLine(xCounter, 0, xCounter + height, height);
  321. }
  322. for (int end = width; xCounter < end; xCounter += 2) {
  323. g.drawLine(xCounter, 0, width, width - xCounter);
  324. }
  325. int yCounter = ((clipRect.x % 2) == 0) ? 2 : 1;
  326. for (int end = height - width; yCounter < end; yCounter += 2) {
  327. g.drawLine(0, yCounter, width, yCounter + width);
  328. }
  329. for (int end = height; yCounter < end; yCounter += 2) {
  330. g.drawLine(0, yCounter, height - yCounter, height);
  331. }
  332. g.translate(-clipRect.x, -clipRect.y);
  333. }
  334. }
  335. }