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