1. /*
  2. * @(#)BasicBorders.java 1.30 03/04/22
  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.basic;
  8. import javax.swing.*;
  9. import javax.swing.border.*;
  10. import javax.swing.plaf.*;
  11. import javax.swing.text.JTextComponent;
  12. import java.awt.Component;
  13. import java.awt.Insets;
  14. import java.awt.Dimension;
  15. import java.awt.Rectangle;
  16. import java.awt.Color;
  17. import java.awt.Graphics;
  18. import java.io.Serializable;
  19. /**
  20. * Factory object that can vend Borders appropriate for the basic L & F.
  21. * @version 1.30 04/22/03
  22. * @author Georges Saab
  23. * @author Amy Fowler
  24. */
  25. public class BasicBorders {
  26. public static Border getButtonBorder() {
  27. UIDefaults table = UIManager.getLookAndFeelDefaults();
  28. Border buttonBorder = new BorderUIResource.CompoundBorderUIResource(
  29. new BasicBorders.ButtonBorder(
  30. table.getColor("Button.shadow"),
  31. table.getColor("Button.darkShadow"),
  32. table.getColor("Button.light"),
  33. table.getColor("Button.highlight")),
  34. new MarginBorder());
  35. return buttonBorder;
  36. }
  37. public static Border getRadioButtonBorder() {
  38. UIDefaults table = UIManager.getLookAndFeelDefaults();
  39. Border radioButtonBorder = new BorderUIResource.CompoundBorderUIResource(
  40. new BasicBorders.RadioButtonBorder(
  41. table.getColor("RadioButton.shadow"),
  42. table.getColor("RadioButton.darkShadow"),
  43. table.getColor("RadioButton.light"),
  44. table.getColor("RadioButton.highlight")),
  45. new MarginBorder());
  46. return radioButtonBorder;
  47. }
  48. public static Border getToggleButtonBorder() {
  49. UIDefaults table = UIManager.getLookAndFeelDefaults();
  50. Border toggleButtonBorder = new BorderUIResource.CompoundBorderUIResource(
  51. new BasicBorders.ToggleButtonBorder(
  52. table.getColor("ToggleButton.shadow"),
  53. table.getColor("ToggleButton.darkShadow"),
  54. table.getColor("ToggleButton.light"),
  55. table.getColor("ToggleButton.highlight")),
  56. new MarginBorder());
  57. return toggleButtonBorder;
  58. }
  59. public static Border getMenuBarBorder() {
  60. UIDefaults table = UIManager.getLookAndFeelDefaults();
  61. Border menuBarBorder = new BasicBorders.MenuBarBorder(
  62. table.getColor("MenuBar.shadow"),
  63. table.getColor("MenuBar.highlight")
  64. );
  65. return menuBarBorder;
  66. }
  67. public static Border getSplitPaneBorder() {
  68. UIDefaults table = UIManager.getLookAndFeelDefaults();
  69. Border splitPaneBorder = new BasicBorders.SplitPaneBorder(
  70. table.getColor("SplitPane.highlight"),
  71. table.getColor("SplitPane.darkShadow"));
  72. return splitPaneBorder;
  73. }
  74. /**
  75. * Returns a border instance for a JSplitPane divider
  76. * @since 1.3
  77. */
  78. public static Border getSplitPaneDividerBorder() {
  79. UIDefaults table = UIManager.getLookAndFeelDefaults();
  80. Border splitPaneBorder = new BasicBorders.SplitPaneDividerBorder(
  81. table.getColor("SplitPane.highlight"),
  82. table.getColor("SplitPane.darkShadow"));
  83. return splitPaneBorder;
  84. }
  85. public static Border getTextFieldBorder() {
  86. UIDefaults table = UIManager.getLookAndFeelDefaults();
  87. Border textFieldBorder = new BasicBorders.FieldBorder(
  88. table.getColor("TextField.shadow"),
  89. table.getColor("TextField.darkShadow"),
  90. table.getColor("TextField.light"),
  91. table.getColor("TextField.highlight"));
  92. return textFieldBorder;
  93. }
  94. public static Border getProgressBarBorder() {
  95. UIDefaults table = UIManager.getLookAndFeelDefaults();
  96. Border progressBarBorder = new BorderUIResource.LineBorderUIResource(Color.green, 2);
  97. return progressBarBorder;
  98. }
  99. public static Border getInternalFrameBorder() {
  100. UIDefaults table = UIManager.getLookAndFeelDefaults();
  101. Border internalFrameBorder = new BorderUIResource.CompoundBorderUIResource(
  102. new BevelBorder(BevelBorder.RAISED,
  103. table.getColor("InternalFrame.borderLight"),
  104. table.getColor("InternalFrame.borderHighlight"),
  105. table.getColor("InternalFrame.borderDarkShadow"),
  106. table.getColor("InternalFrame.borderShadow")),
  107. BorderFactory.createLineBorder(
  108. table.getColor("InternalFrame.borderColor"), 1));
  109. return internalFrameBorder;
  110. }
  111. /**
  112. * Special thin border for rollover toolbar buttons.
  113. */
  114. public static class RolloverButtonBorder extends ButtonBorder {
  115. public RolloverButtonBorder(Color shadow, Color darkShadow,
  116. Color highlight, Color lightHighlight) {
  117. super(shadow, darkShadow, highlight, lightHighlight);
  118. }
  119. public void paintBorder( Component c, Graphics g, int x, int y, int w, int h ) {
  120. AbstractButton b = (AbstractButton) c;
  121. ButtonModel model = b.getModel();
  122. Color shade = shadow;
  123. Component p = b.getParent();
  124. if (p != null && p.getBackground().equals(shadow)) {
  125. shade = darkShadow;
  126. }
  127. if ((model.isRollover() && !(model.isPressed() && !model.isArmed())) ||
  128. model.isSelected()) {
  129. Color oldColor = g.getColor();
  130. g.translate(x, y);
  131. if (model.isPressed() && model.isArmed() || model.isSelected()) {
  132. // Draw the pressd button
  133. g.setColor(shade);
  134. g.drawRect(0, 0, w-1, h-1);
  135. g.setColor(lightHighlight);
  136. g.drawLine(w-1, 0, w-1, h-1);
  137. g.drawLine(0, h-1, w-1, h-1);
  138. } else {
  139. // Draw a rollover button
  140. g.setColor(lightHighlight);
  141. g.drawRect(0, 0, w-1, h-1);
  142. g.setColor(shade);
  143. g.drawLine(w-1, 0, w-1, h-1);
  144. g.drawLine(0, h-1, w-1, h-1);
  145. }
  146. g.translate(-x, -y);
  147. g.setColor(oldColor);
  148. }
  149. }
  150. }
  151. /**
  152. * A border which is like a Margin border but it will only honor the margin
  153. * if the margin has been explicitly set by the developer.
  154. *
  155. * Note: This is identical to the package private class
  156. * MetalBorders.RolloverMarginBorder and should probably be consolidated.
  157. */
  158. static class RolloverMarginBorder extends EmptyBorder {
  159. public RolloverMarginBorder() {
  160. super(3,3,3,3); // hardcoded margin for JLF requirements.
  161. }
  162. public Insets getBorderInsets(Component c) {
  163. return getBorderInsets(c, new Insets(0,0,0,0));
  164. }
  165. public Insets getBorderInsets(Component c, Insets insets) {
  166. Insets margin = null;
  167. if (c instanceof AbstractButton) {
  168. margin = ((AbstractButton)c).getMargin();
  169. }
  170. if (margin == null || margin instanceof UIResource) {
  171. // default margin so replace
  172. insets.left = left;
  173. insets.top = top;
  174. insets.right = right;
  175. insets.bottom = bottom;
  176. } else {
  177. // Margin which has been explicitly set by the user.
  178. insets.left = margin.left;
  179. insets.top = margin.top;
  180. insets.right = margin.right;
  181. insets.bottom = margin.bottom;
  182. }
  183. return insets;
  184. }
  185. }
  186. public static class ButtonBorder extends AbstractBorder implements UIResource {
  187. protected Color shadow;
  188. protected Color darkShadow;
  189. protected Color highlight;
  190. protected Color lightHighlight;
  191. public ButtonBorder(Color shadow, Color darkShadow,
  192. Color highlight, Color lightHighlight) {
  193. this.shadow = shadow;
  194. this.darkShadow = darkShadow;
  195. this.highlight = highlight;
  196. this.lightHighlight = lightHighlight;
  197. }
  198. public void paintBorder(Component c, Graphics g, int x, int y,
  199. int width, int height) {
  200. boolean isPressed = false;
  201. boolean isDefault = false;
  202. if (c instanceof AbstractButton) {
  203. AbstractButton b = (AbstractButton)c;
  204. ButtonModel model = b.getModel();
  205. isPressed = model.isPressed() && model.isArmed();
  206. if (c instanceof JButton) {
  207. isDefault = ((JButton)c).isDefaultButton();
  208. }
  209. }
  210. BasicGraphicsUtils.drawBezel(g, x, y, width, height,
  211. isPressed, isDefault, shadow,
  212. darkShadow, highlight, lightHighlight);
  213. }
  214. public Insets getBorderInsets(Component c) {
  215. return getBorderInsets(c, new Insets(0,0,0,0));
  216. }
  217. public Insets getBorderInsets(Component c, Insets insets) {
  218. // leave room for default visual
  219. insets.top = 2;
  220. insets.left = insets.bottom = insets.right = 3;
  221. return insets;
  222. }
  223. }
  224. public static class ToggleButtonBorder extends ButtonBorder {
  225. public ToggleButtonBorder(Color shadow, Color darkShadow,
  226. Color highlight, Color lightHighlight) {
  227. super(shadow, darkShadow, highlight, lightHighlight);
  228. }
  229. public void paintBorder(Component c, Graphics g, int x, int y,
  230. int width, int height) {
  231. BasicGraphicsUtils.drawBezel(g, x, y, width, height,
  232. false, false,
  233. shadow, darkShadow,
  234. highlight, lightHighlight);
  235. }
  236. public Insets getBorderInsets(Component c) {
  237. return new Insets(2, 2, 2, 2);
  238. }
  239. public Insets getBorderInsets(Component c, Insets insets) {
  240. insets.top = insets.left = insets.bottom = insets.right = 2;
  241. return insets;
  242. }
  243. }
  244. public static class RadioButtonBorder extends ButtonBorder {
  245. public RadioButtonBorder(Color shadow, Color darkShadow,
  246. Color highlight, Color lightHighlight) {
  247. super(shadow, darkShadow, highlight, lightHighlight);
  248. }
  249. public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
  250. if (c instanceof AbstractButton) {
  251. AbstractButton b = (AbstractButton)c;
  252. ButtonModel model = b.getModel();
  253. if (model.isArmed() && model.isPressed() || model.isSelected()) {
  254. BasicGraphicsUtils.drawLoweredBezel(g, x, y, width, height,
  255. shadow, darkShadow,
  256. highlight, lightHighlight);
  257. } else {
  258. BasicGraphicsUtils.drawBezel(g, x, y, width, height,
  259. false, b.isFocusPainted() && b.hasFocus(),
  260. shadow, darkShadow,
  261. highlight, lightHighlight);
  262. }
  263. } else {
  264. BasicGraphicsUtils.drawBezel(g, x, y, width, height, false, false,
  265. shadow, darkShadow, highlight, lightHighlight);
  266. }
  267. }
  268. public Insets getBorderInsets(Component c) {
  269. return getBorderInsets(c, new Insets(0,0,0,0));
  270. }
  271. public Insets getBorderInsets(Component c, Insets insets) {
  272. insets.top = insets.left = insets.bottom = insets.right = 2;
  273. return insets;
  274. }
  275. }
  276. public static class MenuBarBorder extends AbstractBorder implements UIResource {
  277. private Color shadow;
  278. private Color highlight;
  279. public MenuBarBorder(Color shadow, Color highlight) {
  280. this.shadow = shadow;
  281. this.highlight = highlight;
  282. }
  283. public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
  284. BasicGraphicsUtils.drawGroove(g, 0, height-2,
  285. width, height,
  286. shadow, highlight);
  287. }
  288. public Insets getBorderInsets(Component c) {
  289. return getBorderInsets(c, new Insets(0,0,0,0));
  290. }
  291. public Insets getBorderInsets(Component c, Insets insets) {
  292. insets.top = 0;
  293. insets.left = 0;
  294. insets.bottom = 2;
  295. insets.right = 0;
  296. return insets;
  297. }
  298. }
  299. public static class MarginBorder extends AbstractBorder implements UIResource {
  300. public Insets getBorderInsets(Component c) {
  301. return getBorderInsets(c, new Insets(0,0,0,0));
  302. }
  303. public Insets getBorderInsets(Component c, Insets insets) {
  304. Insets margin = null;
  305. //
  306. // Ideally we'd have an interface defined for classes which
  307. // support margins (to avoid this hackery), but we've
  308. // decided against it for simplicity
  309. //
  310. if (c instanceof AbstractButton) {
  311. AbstractButton b = (AbstractButton)c;
  312. margin = b.getMargin();
  313. } else if (c instanceof JToolBar) {
  314. JToolBar t = (JToolBar)c;
  315. margin = t.getMargin();
  316. } else if (c instanceof JTextComponent) {
  317. JTextComponent t = (JTextComponent)c;
  318. margin = t.getMargin();
  319. }
  320. insets.top = margin != null? margin.top : 0;
  321. insets.left = margin != null? margin.left : 0;
  322. insets.bottom = margin != null? margin.bottom : 0;
  323. insets.right = margin != null? margin.right : 0;
  324. return insets;
  325. }
  326. }
  327. public static class FieldBorder extends AbstractBorder implements UIResource {
  328. protected Color shadow;
  329. protected Color darkShadow;
  330. protected Color highlight;
  331. protected Color lightHighlight;
  332. public FieldBorder(Color shadow, Color darkShadow,
  333. Color highlight, Color lightHighlight) {
  334. this.shadow = shadow;
  335. this.highlight = highlight;
  336. this.darkShadow = darkShadow;
  337. this.lightHighlight = lightHighlight;
  338. }
  339. public void paintBorder(Component c, Graphics g, int x, int y,
  340. int width, int height) {
  341. BasicGraphicsUtils.drawEtchedRect(g, x, y, width, height,
  342. shadow, darkShadow,
  343. highlight, lightHighlight);
  344. }
  345. public Insets getBorderInsets(Component c) {
  346. return getBorderInsets(c, new Insets(0,0,0,0));
  347. }
  348. public Insets getBorderInsets(Component c, Insets insets) {
  349. Insets margin = null;
  350. if (c instanceof JTextComponent) {
  351. margin = ((JTextComponent)c).getMargin();
  352. }
  353. insets.top = margin != null? 2+margin.top : 2;
  354. insets.left = margin != null? 2+margin.left : 2;
  355. insets.bottom = margin != null? 2+margin.bottom : 2;
  356. insets.right = margin != null? 2+margin.right : 2;
  357. return insets;
  358. }
  359. }
  360. /**
  361. * Draws the border around the divider in a splitpane
  362. * (when BasicSplitPaneUI is used). To get the appropriate effect, this
  363. * needs to be used with a SplitPaneBorder.
  364. */
  365. static class SplitPaneDividerBorder implements Border, UIResource {
  366. Color highlight;
  367. Color shadow;
  368. SplitPaneDividerBorder(Color highlight, Color shadow) {
  369. this.highlight = highlight;
  370. this.shadow = shadow;
  371. }
  372. public void paintBorder(Component c, Graphics g, int x, int y,
  373. int width, int height) {
  374. Component child;
  375. Rectangle cBounds;
  376. JSplitPane splitPane = ((BasicSplitPaneDivider)c).
  377. getBasicSplitPaneUI().getSplitPane();
  378. Dimension size = c.getSize();
  379. child = splitPane.getLeftComponent();
  380. // This is needed for the space between the divider and end of
  381. // splitpane.
  382. g.setColor(c.getBackground());
  383. g.drawRect(x, y, width - 1, height - 1);
  384. if(splitPane.getOrientation() == JSplitPane.HORIZONTAL_SPLIT) {
  385. if(child != null) {
  386. g.setColor(highlight);
  387. g.drawLine(0, 0, 0, size.height);
  388. }
  389. child = splitPane.getRightComponent();
  390. if(child != null) {
  391. g.setColor(shadow);
  392. g.drawLine(size.width - 1, 0, size.width - 1, size.height);
  393. }
  394. } else {
  395. if(child != null) {
  396. g.setColor(highlight);
  397. g.drawLine(0, 0, size.width, 0);
  398. }
  399. child = splitPane.getRightComponent();
  400. if(child != null) {
  401. g.setColor(shadow);
  402. g.drawLine(0, size.height - 1, size.width,
  403. size.height - 1);
  404. }
  405. }
  406. }
  407. public Insets getBorderInsets(Component c) {
  408. Insets insets = new Insets(0,0,0,0);
  409. if (c instanceof BasicSplitPaneDivider) {
  410. BasicSplitPaneUI bspui = ((BasicSplitPaneDivider)c).
  411. getBasicSplitPaneUI();
  412. if (bspui != null) {
  413. JSplitPane splitPane = bspui.getSplitPane();
  414. if (splitPane != null) {
  415. if (splitPane.getOrientation() ==
  416. JSplitPane.HORIZONTAL_SPLIT) {
  417. insets.top = insets.bottom = 0;
  418. insets.left = insets.right = 1;
  419. return insets;
  420. }
  421. // VERTICAL_SPLIT
  422. insets.top = insets.bottom = 1;
  423. insets.left = insets.right = 0;
  424. return insets;
  425. }
  426. }
  427. }
  428. insets.top = insets.bottom = insets.left = insets.right = 1;
  429. return insets;
  430. }
  431. public boolean isBorderOpaque() { return true; }
  432. }
  433. /**
  434. * Draws the border around the splitpane. To work correctly you shoudl
  435. * also install a border on the divider (property SplitPaneDivider.border).
  436. */
  437. public static class SplitPaneBorder implements Border, UIResource {
  438. protected Color highlight;
  439. protected Color shadow;
  440. public SplitPaneBorder(Color highlight, Color shadow) {
  441. this.highlight = highlight;
  442. this.shadow = shadow;
  443. }
  444. public void paintBorder(Component c, Graphics g, int x, int y,
  445. int width, int height) {
  446. // The only tricky part with this border is that the divider is
  447. // not positioned at the top (for horizontal) or left (for vert),
  448. // so this border draws to where the divider is:
  449. // -----------------
  450. // |xxxxxxx xxxxxxx|
  451. // |x --- x|
  452. // |x | | x|
  453. // |x |D| x|
  454. // |x | | x|
  455. // |x --- x|
  456. // |xxxxxxx xxxxxxx|
  457. // -----------------
  458. // The above shows (rather excessively) what this looks like for
  459. // a horizontal orientation. This border then draws the x's, with
  460. // the SplitPaneDividerBorder drawing its own border.
  461. Component child;
  462. Rectangle cBounds;
  463. JSplitPane splitPane = (JSplitPane)c;
  464. child = splitPane.getLeftComponent();
  465. // This is needed for the space between the divider and end of
  466. // splitpane.
  467. g.setColor(c.getBackground());
  468. g.drawRect(x, y, width - 1, height - 1);
  469. if(splitPane.getOrientation() == JSplitPane.HORIZONTAL_SPLIT) {
  470. if(child != null) {
  471. cBounds = child.getBounds();
  472. g.setColor(shadow);
  473. g.drawLine(0, 0, cBounds.width + 1, 0);
  474. g.drawLine(0, 1, 0, cBounds.height + 2);
  475. g.setColor(highlight);
  476. g.drawLine(1, cBounds.height + 1, cBounds.width + 1,
  477. cBounds.height + 1);
  478. }
  479. child = splitPane.getRightComponent();
  480. if(child != null) {
  481. cBounds = child.getBounds();
  482. int maxX = cBounds.x + cBounds.width;
  483. int maxY = cBounds.y + cBounds.height;
  484. g.setColor(shadow);
  485. g.drawLine(cBounds.x - 1, 0, maxX, 0);
  486. g.drawLine(cBounds.x - 1, maxY, cBounds.x, maxY);
  487. g.setColor(highlight);
  488. g.drawLine(cBounds.x, maxY, maxX, maxY);
  489. g.drawLine(maxX, 0, maxX, maxY + 1);
  490. }
  491. } else {
  492. if(child != null) {
  493. cBounds = child.getBounds();
  494. g.setColor(shadow);
  495. g.drawLine(0, 0, cBounds.width + 1, 0);
  496. g.drawLine(0, 1, 0, cBounds.height);
  497. g.setColor(highlight);
  498. g.drawLine(1 + cBounds.width, 0, 1 + cBounds.width,
  499. cBounds.height + 1);
  500. g.drawLine(0, cBounds.height + 1, 0, cBounds.height + 1);
  501. }
  502. child = splitPane.getRightComponent();
  503. if(child != null) {
  504. cBounds = child.getBounds();
  505. int maxX = cBounds.x + cBounds.width;
  506. int maxY = cBounds.y + cBounds.height;
  507. g.setColor(shadow);
  508. g.drawLine(0, cBounds.y - 1, 0, maxY);
  509. g.drawLine(maxX, cBounds.y - 1, maxX, cBounds.y - 1);
  510. g.drawLine(0, cBounds.y - 1, cBounds.width, cBounds.y - 1);
  511. g.setColor(highlight);
  512. g.drawLine(0, maxY, cBounds.width + 1, maxY);
  513. g.drawLine(maxX, cBounds.y, maxX, maxY);
  514. }
  515. }
  516. }
  517. public Insets getBorderInsets(Component c) {
  518. return new Insets(1, 1, 1, 1);
  519. }
  520. public boolean isBorderOpaque() { return true; }
  521. }
  522. }