1. /*
  2. * @(#)MetalSplitPaneDivider.java 1.21 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 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.21 12/19/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. UIManager.getColor("SplitPane.dividerFocusColor"));
  38. private int inset = 2;
  39. private Color controlColor = MetalLookAndFeel.getControl();
  40. private Color primaryControlColor = UIManager.getColor(
  41. "SplitPane.dividerFocusColor");
  42. public MetalSplitPaneDivider(BasicSplitPaneUI ui) {
  43. super(ui);
  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. if (isOpaque()) {
  103. g.fillRect(0, 0, this.getWidth(),
  104. this.getHeight());
  105. }
  106. // ... then draw the arrow.
  107. if (getModel().isPressed()) {
  108. // Adjust color mapping for pressed button state
  109. colors[1] = colors[2];
  110. }
  111. if(orientation == JSplitPane.VERTICAL_SPLIT) {
  112. // Draw the image for a vertical split
  113. for (int i=1; i<=buffer[0].length; i++) {
  114. for (int j=1; j<blockSize; j++) {
  115. if (buffer[j-1][i-1] == 0) {
  116. continue;
  117. }
  118. else {
  119. g.setColor(
  120. colors[buffer[j-1][i-1]]);
  121. }
  122. g.drawLine(i, j, i, j);
  123. }
  124. }
  125. }
  126. else {
  127. // Draw the image for a horizontal split
  128. // by simply swaping the i and j axis.
  129. // Except the drawLine() call this code is
  130. // identical to the code block above. This was done
  131. // in order to remove the additional orientation
  132. // check for each pixel.
  133. for (int i=1; i<=buffer[0].length; i++) {
  134. for (int j=1; j<blockSize; j++) {
  135. if (buffer[j-1][i-1] == 0) {
  136. // Nothing needs
  137. // to be drawn
  138. continue;
  139. }
  140. else {
  141. // Set the color from the
  142. // color map
  143. g.setColor(
  144. colors[buffer[j-1][i-1]]);
  145. }
  146. // Draw a pixel
  147. g.drawLine(j, i, j, i);
  148. }
  149. }
  150. }
  151. }
  152. }
  153. // Don't want the button to participate in focus traversable.
  154. public boolean isFocusTraversable() {
  155. return false;
  156. }
  157. };
  158. b.setRequestFocusEnabled(false);
  159. b.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
  160. b.setFocusPainted(false);
  161. b.setBorderPainted(false);
  162. maybeMakeButtonOpaque(b);
  163. return b;
  164. }
  165. /**
  166. * If necessary <code>c</code> is made opaque.
  167. */
  168. private void maybeMakeButtonOpaque(JComponent c) {
  169. Object opaque = UIManager.get("SplitPane.oneTouchButtonsOpaque");
  170. if (opaque != null) {
  171. c.setOpaque(((Boolean)opaque).booleanValue());
  172. }
  173. }
  174. /**
  175. * Creates and return an instance of JButton that can be used to
  176. * collapse the right component in the metal split pane.
  177. */
  178. protected JButton createRightOneTouchButton() {
  179. JButton b = new JButton() {
  180. // Sprite buffer for the arrow image of the right button
  181. int[][] buffer = {{2, 2, 2, 2, 2, 2, 2, 2},
  182. {0, 1, 1, 1, 1, 1, 1, 3},
  183. {0, 0, 1, 1, 1, 1, 3, 0},
  184. {0, 0, 0, 1, 1, 3, 0, 0},
  185. {0, 0, 0, 0, 3, 0, 0, 0}};
  186. public void setBorder(Border border) {
  187. }
  188. public void paint(Graphics g) {
  189. JSplitPane splitPane = getSplitPaneFromSuper();
  190. if(splitPane != null) {
  191. int oneTouchSize = getOneTouchSizeFromSuper();
  192. int orientation = getOrientationFromSuper();
  193. int blockSize = Math.min(getDividerSize(),
  194. oneTouchSize);
  195. // Initialize the color array
  196. Color[] colors = {
  197. this.getBackground(),
  198. MetalLookAndFeel.getPrimaryControlDarkShadow(),
  199. MetalLookAndFeel.getPrimaryControlInfo(),
  200. MetalLookAndFeel.getPrimaryControlHighlight()};
  201. // Fill the background first ...
  202. g.setColor(this.getBackground());
  203. if (isOpaque()) {
  204. g.fillRect(0, 0, this.getWidth(),
  205. this.getHeight());
  206. }
  207. // ... then draw the arrow.
  208. if (getModel().isPressed()) {
  209. // Adjust color mapping for pressed button state
  210. colors[1] = colors[2];
  211. }
  212. if(orientation == JSplitPane.VERTICAL_SPLIT) {
  213. // Draw the image for a vertical split
  214. for (int i=1; i<=buffer[0].length; i++) {
  215. for (int j=1; j<blockSize; j++) {
  216. if (buffer[j-1][i-1] == 0) {
  217. continue;
  218. }
  219. else {
  220. g.setColor(
  221. colors[buffer[j-1][i-1]]);
  222. }
  223. g.drawLine(i, j, i, j);
  224. }
  225. }
  226. }
  227. else {
  228. // Draw the image for a horizontal split
  229. // by simply swaping the i and j axis.
  230. // Except the drawLine() call this code is
  231. // identical to the code block above. This was done
  232. // in order to remove the additional orientation
  233. // check for each pixel.
  234. for (int i=1; i<=buffer[0].length; i++) {
  235. for (int j=1; j<blockSize; j++) {
  236. if (buffer[j-1][i-1] == 0) {
  237. // Nothing needs
  238. // to be drawn
  239. continue;
  240. }
  241. else {
  242. // Set the color from the
  243. // color map
  244. g.setColor(
  245. colors[buffer[j-1][i-1]]);
  246. }
  247. // Draw a pixel
  248. g.drawLine(j, i, j, i);
  249. }
  250. }
  251. }
  252. }
  253. }
  254. // Don't want the button to participate in focus traversable.
  255. public boolean isFocusTraversable() {
  256. return false;
  257. }
  258. };
  259. b.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
  260. b.setFocusPainted(false);
  261. b.setBorderPainted(false);
  262. b.setRequestFocusEnabled(false);
  263. maybeMakeButtonOpaque(b);
  264. return b;
  265. }
  266. /**
  267. * Used to layout a MetalSplitPaneDivider. Layout for the divider
  268. * involves appropriately moving the left/right buttons around.
  269. * <p>
  270. * This class should be treated as a "protected" inner class.
  271. * Instantiate it only within subclasses of MetalSplitPaneDivider.
  272. */
  273. public class MetalDividerLayout implements LayoutManager {
  274. // NOTE NOTE NOTE NOTE NOTE
  275. // This class is no longer used, the functionality has
  276. // been rolled into BasicSplitPaneDivider.DividerLayout as a
  277. // defaults property
  278. public void layoutContainer(Container c) {
  279. JButton leftButton = getLeftButtonFromSuper();
  280. JButton rightButton = getRightButtonFromSuper();
  281. JSplitPane splitPane = getSplitPaneFromSuper();
  282. int orientation = getOrientationFromSuper();
  283. int oneTouchSize = getOneTouchSizeFromSuper();
  284. int oneTouchOffset = getOneTouchOffsetFromSuper();
  285. Insets insets = getInsets();
  286. // This layout differs from the one used in BasicSplitPaneDivider.
  287. // It does not center justify the oneTouchExpadable buttons.
  288. // This was necessary in order to meet the spec of the Metal
  289. // splitpane divider.
  290. if (leftButton != null && rightButton != null &&
  291. c == MetalSplitPaneDivider.this) {
  292. if (splitPane.isOneTouchExpandable()) {
  293. if (orientation == JSplitPane.VERTICAL_SPLIT) {
  294. int extraY = (insets != null) ? insets.top : 0;
  295. int blockSize = getDividerSize();
  296. if (insets != null) {
  297. blockSize -= (insets.top + insets.bottom);
  298. }
  299. blockSize = Math.min(blockSize, oneTouchSize);
  300. leftButton.setBounds(oneTouchOffset, extraY,
  301. blockSize * 2, blockSize);
  302. rightButton.setBounds(oneTouchOffset +
  303. oneTouchSize * 2, extraY,
  304. blockSize * 2, blockSize);
  305. }
  306. else {
  307. int blockSize = getDividerSize();
  308. int extraX = (insets != null) ? insets.left : 0;
  309. if (insets != null) {
  310. blockSize -= (insets.left + insets.right);
  311. }
  312. blockSize = Math.min(blockSize, oneTouchSize);
  313. leftButton.setBounds(extraX, oneTouchOffset,
  314. blockSize, blockSize * 2);
  315. rightButton.setBounds(extraX, oneTouchOffset +
  316. oneTouchSize * 2, blockSize,
  317. blockSize * 2);
  318. }
  319. }
  320. else {
  321. leftButton.setBounds(-5, -5, 1, 1);
  322. rightButton.setBounds(-5, -5, 1, 1);
  323. }
  324. }
  325. }
  326. public Dimension minimumLayoutSize(Container c) {
  327. return new Dimension(0,0);
  328. }
  329. public Dimension preferredLayoutSize(Container c) {
  330. return new Dimension(0, 0);
  331. }
  332. public void removeLayoutComponent(Component c) {}
  333. public void addLayoutComponent(String string, Component c) {}
  334. }
  335. /*
  336. * The following methods only exist in order to be able to access protected
  337. * members in the superclass, because these are otherwise not available
  338. * in any inner class.
  339. */
  340. int getOneTouchSizeFromSuper() {
  341. return super.ONE_TOUCH_SIZE;
  342. }
  343. int getOneTouchOffsetFromSuper() {
  344. return super.ONE_TOUCH_OFFSET;
  345. }
  346. int getOrientationFromSuper() {
  347. return super.orientation;
  348. }
  349. JSplitPane getSplitPaneFromSuper() {
  350. return super.splitPane;
  351. }
  352. JButton getLeftButtonFromSuper() {
  353. return super.leftButton;
  354. }
  355. JButton getRightButtonFromSuper() {
  356. return super.rightButton;
  357. }
  358. }