1. /*
  2. * @(#)MetalSplitPaneDivider.java 1.14 00/02/02
  3. *
  4. * Copyright 1998-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package javax.swing.plaf.metal;
  11. import java.awt.*;
  12. import javax.swing.*;
  13. import javax.swing.border.*;
  14. import javax.swing.plaf.basic.*;
  15. /**
  16. * Metal's split pane divider
  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. * @version 1.14 02/02/00
  26. * @author Steve Wilson
  27. * @author Ralph kar
  28. */
  29. class MetalSplitPaneDivider extends BasicSplitPaneDivider
  30. {
  31. private MetalBumps bumps = new MetalBumps(10, 10,
  32. MetalLookAndFeel.getControlHighlight(),
  33. MetalLookAndFeel.getControlDarkShadow(),
  34. MetalLookAndFeel.getControl() );
  35. private MetalBumps focusBumps = new MetalBumps(10, 10,
  36. MetalLookAndFeel.getPrimaryControlHighlight(),
  37. MetalLookAndFeel.getPrimaryControlDarkShadow(),
  38. MetalLookAndFeel.getPrimaryControl() );
  39. private int inset = 2;
  40. private Color controlColor = MetalLookAndFeel.getControl();
  41. private Color primaryControlColor = MetalLookAndFeel.getPrimaryControl();
  42. public MetalSplitPaneDivider(BasicSplitPaneUI ui) {
  43. super(ui);
  44. setLayout(new MetalDividerLayout());
  45. }
  46. public void paint(Graphics g) {
  47. MetalBumps usedBumps;
  48. if (splitPane.hasFocus()) {
  49. usedBumps = focusBumps;
  50. g.setColor(primaryControlColor);
  51. }
  52. else {
  53. usedBumps = bumps;
  54. g.setColor(controlColor);
  55. }
  56. Rectangle clip = g.getClipBounds();
  57. Insets insets = getInsets();
  58. g.fillRect(clip.x, clip.y, clip.width, clip.height);
  59. Dimension size = getSize();
  60. size.width -= inset * 2;
  61. size.height -= inset * 2;
  62. int drawX = inset;
  63. int drawY = inset;
  64. if (insets != null) {
  65. size.width -= (insets.left + insets.right);
  66. size.height -= (insets.top + insets.bottom);
  67. drawX += insets.left;
  68. drawY += insets.top;
  69. }
  70. usedBumps.setBumpArea(size);
  71. usedBumps.paintIcon(this, g, drawX, drawY);
  72. super.paint(g);
  73. }
  74. /**
  75. * Creates and return an instance of JButton that can be used to
  76. * collapse the left component in the metal split pane.
  77. */
  78. protected JButton createLeftOneTouchButton() {
  79. JButton b = new JButton() {
  80. // Sprite buffer for the arrow image of the left button
  81. int[][] buffer = {{0, 0, 0, 2, 2, 0, 0, 0, 0},
  82. {0, 0, 2, 1, 1, 1, 0, 0, 0},
  83. {0, 2, 1, 1, 1, 1, 1, 0, 0},
  84. {2, 1, 1, 1, 1, 1, 1, 1, 0},
  85. {0, 3, 3, 3, 3, 3, 3, 3, 3}};
  86. public void setBorder(Border b) {
  87. }
  88. public void paint(Graphics g) {
  89. JSplitPane splitPane = getSplitPaneFromSuper();
  90. if(splitPane != null) {
  91. int oneTouchSize = getOneTouchSizeFromSuper();
  92. int orientation = getOrientationFromSuper();
  93. int blockSize = Math.min(getDividerSize(),
  94. oneTouchSize);
  95. // Initialize the color array
  96. Color[] colors = {
  97. this.getBackground(),
  98. MetalLookAndFeel.getPrimaryControlDarkShadow(),
  99. MetalLookAndFeel.getPrimaryControlInfo(),
  100. MetalLookAndFeel.getPrimaryControlHighlight()};
  101. // Fill the background first ...
  102. g.setColor(this.getBackground());
  103. g.fillRect(0, 0, this.getWidth(),
  104. this.getHeight());
  105. // ... then draw the arrow.
  106. if (getModel().isPressed()) {
  107. // Adjust color mapping for pressed button state
  108. colors[1] = colors[2];
  109. }
  110. if(orientation == JSplitPane.VERTICAL_SPLIT) {
  111. // Draw the image for a vertical split
  112. for (int i=1; i<=buffer[0].length; i++) {
  113. for (int j=1; j<blockSize; j++) {
  114. if (buffer[j-1][i-1] == 0) {
  115. continue;
  116. }
  117. else {
  118. g.setColor(
  119. colors[buffer[j-1][i-1]]);
  120. }
  121. g.drawLine(i, j, i, j);
  122. }
  123. }
  124. }
  125. else {
  126. // Draw the image for a horizontal split
  127. // by simply swaping the i and j axis.
  128. // Except the drawLine() call this code is
  129. // identical to the code block above. This was done
  130. // in order to remove the additional orientation
  131. // check for each pixel.
  132. for (int i=1; i<=buffer[0].length; i++) {
  133. for (int j=1; j<blockSize; j++) {
  134. if (buffer[j-1][i-1] == 0) {
  135. // Nothing needs
  136. // to be drawn
  137. continue;
  138. }
  139. else {
  140. // Set the color from the
  141. // color map
  142. g.setColor(
  143. colors[buffer[j-1][i-1]]);
  144. }
  145. // Draw a pixel
  146. g.drawLine(j, i, j, i);
  147. }
  148. }
  149. }
  150. }
  151. }
  152. // Don't want the button to participate in focus traversable.
  153. public boolean isFocusTraversable() {
  154. return false;
  155. }
  156. };
  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. return b;
  249. }
  250. /**
  251. * Used to layout a MetalSplitPaneDivider. Layout for the divider
  252. * involves appropriately moving the left/right buttons around.
  253. * <p>
  254. * This inner class is marked "public" due to a compiler bug.
  255. * This class should be treated as a "protected" inner class.
  256. * Instantiate it only within subclasses of MetalSplitPaneDivider.
  257. */
  258. public class MetalDividerLayout implements LayoutManager {
  259. public void layoutContainer(Container c) {
  260. JButton leftButton = getLeftButtonFromSuper();
  261. JButton rightButton = getRightButtonFromSuper();
  262. JSplitPane splitPane = getSplitPaneFromSuper();
  263. int orientation = getOrientationFromSuper();
  264. int oneTouchSize = getOneTouchSizeFromSuper();
  265. int oneTouchOffset = getOneTouchOffsetFromSuper();
  266. Insets insets = getInsets();
  267. // This layout differs from the one used in BasicSplitPaneDivider.
  268. // It does not center justify the oneTouchExpadable buttons.
  269. // This was necessary in order to meet the spec of the Metal
  270. // splitpane divider.
  271. if (leftButton != null && rightButton != null &&
  272. c == MetalSplitPaneDivider.this) {
  273. if (splitPane.isOneTouchExpandable()) {
  274. if (orientation == JSplitPane.VERTICAL_SPLIT) {
  275. int extraY = (insets != null) ? insets.top : 0;
  276. int blockSize = getDividerSize();
  277. if (insets != null) {
  278. blockSize -= (insets.top + insets.bottom);
  279. }
  280. blockSize = Math.min(blockSize, oneTouchSize);
  281. leftButton.setBounds(oneTouchOffset, extraY,
  282. blockSize * 2, blockSize);
  283. rightButton.setBounds(oneTouchOffset +
  284. oneTouchSize * 2, extraY,
  285. blockSize * 2, blockSize);
  286. }
  287. else {
  288. int blockSize = getDividerSize();
  289. int extraX = (insets != null) ? insets.left : 0;
  290. if (insets != null) {
  291. blockSize -= (insets.left + insets.right);
  292. }
  293. blockSize = Math.min(blockSize, oneTouchSize);
  294. leftButton.setBounds(extraX, oneTouchOffset,
  295. blockSize, blockSize * 2);
  296. rightButton.setBounds(extraX, oneTouchOffset +
  297. oneTouchSize * 2, blockSize,
  298. blockSize * 2);
  299. }
  300. }
  301. else {
  302. leftButton.setBounds(-5, -5, 1, 1);
  303. rightButton.setBounds(-5, -5, 1, 1);
  304. }
  305. }
  306. }
  307. public Dimension minimumLayoutSize(Container c) {
  308. return new Dimension(0,0);
  309. }
  310. public Dimension preferredLayoutSize(Container c) {
  311. return new Dimension(0, 0);
  312. }
  313. public void removeLayoutComponent(Component c) {}
  314. public void addLayoutComponent(String string, Component c) {}
  315. }
  316. /*
  317. * The following methods only exist in order to be able to access protected
  318. * members in the superclass, because these are otherwise not available
  319. * in any inner class.
  320. */
  321. int getOneTouchSizeFromSuper() {
  322. return super.ONE_TOUCH_SIZE;
  323. }
  324. int getOneTouchOffsetFromSuper() {
  325. return super.ONE_TOUCH_OFFSET;
  326. }
  327. int getOrientationFromSuper() {
  328. return super.orientation;
  329. }
  330. JSplitPane getSplitPaneFromSuper() {
  331. return super.splitPane;
  332. }
  333. JButton getLeftButtonFromSuper() {
  334. return super.leftButton;
  335. }
  336. JButton getRightButtonFromSuper() {
  337. return super.rightButton;
  338. }
  339. }