1. /*
  2. * @(#)MetalSplitPaneDivider.java 1.18 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.*;
  9. import javax.swing.*;
  10. import javax.swing.border.*;
  11. import javax.swing.plaf.basic.*;
  12. /**
  13. * Metal's split pane divider
  14. * <p>
  15. * <strong>Warning:</strong>
  16. * Serialized objects of this class will not be compatible with
  17. * future Swing releases. The current serialization support is
  18. * appropriate for short term storage or RMI between applications running
  19. * the same version of Swing. As of 1.4, support for long term storage
  20. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  21. * has been added to the <code>java.beans</code> package.
  22. * Please see {@link java.beans.XMLEncoder}.
  23. *
  24. * @version 1.18 01/23/03
  25. * @author Steve Wilson
  26. * @author Ralph kar
  27. */
  28. class MetalSplitPaneDivider extends BasicSplitPaneDivider
  29. {
  30. private MetalBumps bumps = new MetalBumps(10, 10,
  31. MetalLookAndFeel.getControlHighlight(),
  32. MetalLookAndFeel.getControlDarkShadow(),
  33. MetalLookAndFeel.getControl() );
  34. private MetalBumps focusBumps = new MetalBumps(10, 10,
  35. MetalLookAndFeel.getPrimaryControlHighlight(),
  36. MetalLookAndFeel.getPrimaryControlDarkShadow(),
  37. MetalLookAndFeel.getPrimaryControl() );
  38. private int inset = 2;
  39. private Color controlColor = MetalLookAndFeel.getControl();
  40. private Color primaryControlColor = MetalLookAndFeel.getPrimaryControl();
  41. public MetalSplitPaneDivider(BasicSplitPaneUI ui) {
  42. super(ui);
  43. setLayout(new MetalDividerLayout());
  44. }
  45. public void paint(Graphics g) {
  46. MetalBumps usedBumps;
  47. if (splitPane.hasFocus()) {
  48. usedBumps = focusBumps;
  49. g.setColor(primaryControlColor);
  50. }
  51. else {
  52. usedBumps = bumps;
  53. g.setColor(controlColor);
  54. }
  55. Rectangle clip = g.getClipBounds();
  56. Insets insets = getInsets();
  57. g.fillRect(clip.x, clip.y, clip.width, clip.height);
  58. Dimension size = getSize();
  59. size.width -= inset * 2;
  60. size.height -= inset * 2;
  61. int drawX = inset;
  62. int drawY = inset;
  63. if (insets != null) {
  64. size.width -= (insets.left + insets.right);
  65. size.height -= (insets.top + insets.bottom);
  66. drawX += insets.left;
  67. drawY += insets.top;
  68. }
  69. usedBumps.setBumpArea(size);
  70. usedBumps.paintIcon(this, g, drawX, drawY);
  71. super.paint(g);
  72. }
  73. /**
  74. * Creates and return an instance of JButton that can be used to
  75. * collapse the left component in the metal split pane.
  76. */
  77. protected JButton createLeftOneTouchButton() {
  78. JButton b = new JButton() {
  79. // Sprite buffer for the arrow image of the left button
  80. int[][] buffer = {{0, 0, 0, 2, 2, 0, 0, 0, 0},
  81. {0, 0, 2, 1, 1, 1, 0, 0, 0},
  82. {0, 2, 1, 1, 1, 1, 1, 0, 0},
  83. {2, 1, 1, 1, 1, 1, 1, 1, 0},
  84. {0, 3, 3, 3, 3, 3, 3, 3, 3}};
  85. public void setBorder(Border b) {
  86. }
  87. public void paint(Graphics g) {
  88. JSplitPane splitPane = getSplitPaneFromSuper();
  89. if(splitPane != null) {
  90. int oneTouchSize = getOneTouchSizeFromSuper();
  91. int orientation = getOrientationFromSuper();
  92. int blockSize = Math.min(getDividerSize(),
  93. oneTouchSize);
  94. // Initialize the color array
  95. Color[] colors = {
  96. this.getBackground(),
  97. MetalLookAndFeel.getPrimaryControlDarkShadow(),
  98. MetalLookAndFeel.getPrimaryControlInfo(),
  99. MetalLookAndFeel.getPrimaryControlHighlight()};
  100. // Fill the background first ...
  101. g.setColor(this.getBackground());
  102. g.fillRect(0, 0, this.getWidth(),
  103. this.getHeight());
  104. // ... then draw the arrow.
  105. if (getModel().isPressed()) {
  106. // Adjust color mapping for pressed button state
  107. colors[1] = colors[2];
  108. }
  109. if(orientation == JSplitPane.VERTICAL_SPLIT) {
  110. // Draw the image for a vertical split
  111. for (int i=1; i<=buffer[0].length; i++) {
  112. for (int j=1; j<blockSize; j++) {
  113. if (buffer[j-1][i-1] == 0) {
  114. continue;
  115. }
  116. else {
  117. g.setColor(
  118. colors[buffer[j-1][i-1]]);
  119. }
  120. g.drawLine(i, j, i, j);
  121. }
  122. }
  123. }
  124. else {
  125. // Draw the image for a horizontal split
  126. // by simply swaping the i and j axis.
  127. // Except the drawLine() call this code is
  128. // identical to the code block above. This was done
  129. // in order to remove the additional orientation
  130. // check for each pixel.
  131. for (int i=1; i<=buffer[0].length; i++) {
  132. for (int j=1; j<blockSize; j++) {
  133. if (buffer[j-1][i-1] == 0) {
  134. // Nothing needs
  135. // to be drawn
  136. continue;
  137. }
  138. else {
  139. // Set the color from the
  140. // color map
  141. g.setColor(
  142. colors[buffer[j-1][i-1]]);
  143. }
  144. // Draw a pixel
  145. g.drawLine(j, i, j, i);
  146. }
  147. }
  148. }
  149. }
  150. }
  151. // Don't want the button to participate in focus traversable.
  152. public boolean isFocusTraversable() {
  153. return false;
  154. }
  155. };
  156. b.setRequestFocusEnabled(false);
  157. b.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
  158. b.setFocusPainted(false);
  159. b.setBorderPainted(false);
  160. return b;
  161. }
  162. /**
  163. * Creates and return an instance of JButton that can be used to
  164. * collapse the right component in the metal split pane.
  165. */
  166. protected JButton createRightOneTouchButton() {
  167. JButton b = new JButton() {
  168. // Sprite buffer for the arrow image of the right button
  169. int[][] buffer = {{2, 2, 2, 2, 2, 2, 2, 2},
  170. {0, 1, 1, 1, 1, 1, 1, 3},
  171. {0, 0, 1, 1, 1, 1, 3, 0},
  172. {0, 0, 0, 1, 1, 3, 0, 0},
  173. {0, 0, 0, 0, 3, 0, 0, 0}};
  174. public void setBorder(Border border) {
  175. }
  176. public void paint(Graphics g) {
  177. JSplitPane splitPane = getSplitPaneFromSuper();
  178. if(splitPane != null) {
  179. int oneTouchSize = getOneTouchSizeFromSuper();
  180. int orientation = getOrientationFromSuper();
  181. int blockSize = Math.min(getDividerSize(),
  182. oneTouchSize);
  183. // Initialize the color array
  184. Color[] colors = {
  185. this.getBackground(),
  186. MetalLookAndFeel.getPrimaryControlDarkShadow(),
  187. MetalLookAndFeel.getPrimaryControlInfo(),
  188. MetalLookAndFeel.getPrimaryControlHighlight()};
  189. // Fill the background first ...
  190. g.setColor(this.getBackground());
  191. g.fillRect(0, 0, this.getWidth(),
  192. this.getHeight());
  193. // ... then draw the arrow.
  194. if (getModel().isPressed()) {
  195. // Adjust color mapping for pressed button state
  196. colors[1] = colors[2];
  197. }
  198. if(orientation == JSplitPane.VERTICAL_SPLIT) {
  199. // Draw the image for a vertical split
  200. for (int i=1; i<=buffer[0].length; i++) {
  201. for (int j=1; j<blockSize; j++) {
  202. if (buffer[j-1][i-1] == 0) {
  203. continue;
  204. }
  205. else {
  206. g.setColor(
  207. colors[buffer[j-1][i-1]]);
  208. }
  209. g.drawLine(i, j, i, j);
  210. }
  211. }
  212. }
  213. else {
  214. // Draw the image for a horizontal split
  215. // by simply swaping the i and j axis.
  216. // Except the drawLine() call this code is
  217. // identical to the code block above. This was done
  218. // in order to remove the additional orientation
  219. // check for each pixel.
  220. for (int i=1; i<=buffer[0].length; i++) {
  221. for (int j=1; j<blockSize; j++) {
  222. if (buffer[j-1][i-1] == 0) {
  223. // Nothing needs
  224. // to be drawn
  225. continue;
  226. }
  227. else {
  228. // Set the color from the
  229. // color map
  230. g.setColor(
  231. colors[buffer[j-1][i-1]]);
  232. }
  233. // Draw a pixel
  234. g.drawLine(j, i, j, i);
  235. }
  236. }
  237. }
  238. }
  239. }
  240. // Don't want the button to participate in focus traversable.
  241. public boolean isFocusTraversable() {
  242. return false;
  243. }
  244. };
  245. b.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
  246. b.setFocusPainted(false);
  247. b.setBorderPainted(false);
  248. b.setRequestFocusEnabled(false);
  249. return b;
  250. }
  251. /**
  252. * Used to layout a MetalSplitPaneDivider. Layout for the divider
  253. * involves appropriately moving the left/right buttons around.
  254. * <p>
  255. * This inner class is marked "public" due to a compiler bug.
  256. * This class should be treated as a "protected" inner class.
  257. * Instantiate it only within subclasses of MetalSplitPaneDivider.
  258. */
  259. public class MetalDividerLayout implements LayoutManager {
  260. public void layoutContainer(Container c) {
  261. JButton leftButton = getLeftButtonFromSuper();
  262. JButton rightButton = getRightButtonFromSuper();
  263. JSplitPane splitPane = getSplitPaneFromSuper();
  264. int orientation = getOrientationFromSuper();
  265. int oneTouchSize = getOneTouchSizeFromSuper();
  266. int oneTouchOffset = getOneTouchOffsetFromSuper();
  267. Insets insets = getInsets();
  268. // This layout differs from the one used in BasicSplitPaneDivider.
  269. // It does not center justify the oneTouchExpadable buttons.
  270. // This was necessary in order to meet the spec of the Metal
  271. // splitpane divider.
  272. if (leftButton != null && rightButton != null &&
  273. c == MetalSplitPaneDivider.this) {
  274. if (splitPane.isOneTouchExpandable()) {
  275. if (orientation == JSplitPane.VERTICAL_SPLIT) {
  276. int extraY = (insets != null) ? insets.top : 0;
  277. int blockSize = getDividerSize();
  278. if (insets != null) {
  279. blockSize -= (insets.top + insets.bottom);
  280. }
  281. blockSize = Math.min(blockSize, oneTouchSize);
  282. leftButton.setBounds(oneTouchOffset, extraY,
  283. blockSize * 2, blockSize);
  284. rightButton.setBounds(oneTouchOffset +
  285. oneTouchSize * 2, extraY,
  286. blockSize * 2, blockSize);
  287. }
  288. else {
  289. int blockSize = getDividerSize();
  290. int extraX = (insets != null) ? insets.left : 0;
  291. if (insets != null) {
  292. blockSize -= (insets.left + insets.right);
  293. }
  294. blockSize = Math.min(blockSize, oneTouchSize);
  295. leftButton.setBounds(extraX, oneTouchOffset,
  296. blockSize, blockSize * 2);
  297. rightButton.setBounds(extraX, oneTouchOffset +
  298. oneTouchSize * 2, blockSize,
  299. blockSize * 2);
  300. }
  301. }
  302. else {
  303. leftButton.setBounds(-5, -5, 1, 1);
  304. rightButton.setBounds(-5, -5, 1, 1);
  305. }
  306. }
  307. }
  308. public Dimension minimumLayoutSize(Container c) {
  309. return new Dimension(0,0);
  310. }
  311. public Dimension preferredLayoutSize(Container c) {
  312. return new Dimension(0, 0);
  313. }
  314. public void removeLayoutComponent(Component c) {}
  315. public void addLayoutComponent(String string, Component c) {}
  316. }
  317. /*
  318. * The following methods only exist in order to be able to access protected
  319. * members in the superclass, because these are otherwise not available
  320. * in any inner class.
  321. */
  322. int getOneTouchSizeFromSuper() {
  323. return super.ONE_TOUCH_SIZE;
  324. }
  325. int getOneTouchOffsetFromSuper() {
  326. return super.ONE_TOUCH_OFFSET;
  327. }
  328. int getOrientationFromSuper() {
  329. return super.orientation;
  330. }
  331. JSplitPane getSplitPaneFromSuper() {
  332. return super.splitPane;
  333. }
  334. JButton getLeftButtonFromSuper() {
  335. return super.leftButton;
  336. }
  337. JButton getRightButtonFromSuper() {
  338. return super.rightButton;
  339. }
  340. }