1. /*
  2. * @(#)BasicBorders.java 1.33 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.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.33 12/19/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. Color oldColor = g.getColor();
  285. g.translate(x, y);
  286. g.setColor(shadow);
  287. g.drawLine(0, height-2, width, height-2);
  288. g.setColor(highlight);
  289. g.drawLine(0, height-1, width, height-1);
  290. g.translate(-x,-y);
  291. g.setColor(oldColor);
  292. }
  293. public Insets getBorderInsets(Component c) {
  294. return getBorderInsets(c, new Insets(0,0,0,0));
  295. }
  296. public Insets getBorderInsets(Component c, Insets insets) {
  297. insets.top = 0;
  298. insets.left = 0;
  299. insets.bottom = 2;
  300. insets.right = 0;
  301. return insets;
  302. }
  303. }
  304. public static class MarginBorder extends AbstractBorder implements UIResource {
  305. public Insets getBorderInsets(Component c) {
  306. return getBorderInsets(c, new Insets(0,0,0,0));
  307. }
  308. public Insets getBorderInsets(Component c, Insets insets) {
  309. Insets margin = null;
  310. //
  311. // Ideally we'd have an interface defined for classes which
  312. // support margins (to avoid this hackery), but we've
  313. // decided against it for simplicity
  314. //
  315. if (c instanceof AbstractButton) {
  316. AbstractButton b = (AbstractButton)c;
  317. margin = b.getMargin();
  318. } else if (c instanceof JToolBar) {
  319. JToolBar t = (JToolBar)c;
  320. margin = t.getMargin();
  321. } else if (c instanceof JTextComponent) {
  322. JTextComponent t = (JTextComponent)c;
  323. margin = t.getMargin();
  324. }
  325. insets.top = margin != null? margin.top : 0;
  326. insets.left = margin != null? margin.left : 0;
  327. insets.bottom = margin != null? margin.bottom : 0;
  328. insets.right = margin != null? margin.right : 0;
  329. return insets;
  330. }
  331. }
  332. public static class FieldBorder extends AbstractBorder implements UIResource {
  333. protected Color shadow;
  334. protected Color darkShadow;
  335. protected Color highlight;
  336. protected Color lightHighlight;
  337. public FieldBorder(Color shadow, Color darkShadow,
  338. Color highlight, Color lightHighlight) {
  339. this.shadow = shadow;
  340. this.highlight = highlight;
  341. this.darkShadow = darkShadow;
  342. this.lightHighlight = lightHighlight;
  343. }
  344. public void paintBorder(Component c, Graphics g, int x, int y,
  345. int width, int height) {
  346. BasicGraphicsUtils.drawEtchedRect(g, x, y, width, height,
  347. shadow, darkShadow,
  348. highlight, lightHighlight);
  349. }
  350. public Insets getBorderInsets(Component c) {
  351. return getBorderInsets(c, new Insets(0,0,0,0));
  352. }
  353. public Insets getBorderInsets(Component c, Insets insets) {
  354. Insets margin = null;
  355. if (c instanceof JTextComponent) {
  356. margin = ((JTextComponent)c).getMargin();
  357. }
  358. insets.top = margin != null? 2+margin.top : 2;
  359. insets.left = margin != null? 2+margin.left : 2;
  360. insets.bottom = margin != null? 2+margin.bottom : 2;
  361. insets.right = margin != null? 2+margin.right : 2;
  362. return insets;
  363. }
  364. }
  365. /**
  366. * Draws the border around the divider in a splitpane
  367. * (when BasicSplitPaneUI is used). To get the appropriate effect, this
  368. * needs to be used with a SplitPaneBorder.
  369. */
  370. static class SplitPaneDividerBorder implements Border, UIResource {
  371. Color highlight;
  372. Color shadow;
  373. SplitPaneDividerBorder(Color highlight, Color shadow) {
  374. this.highlight = highlight;
  375. this.shadow = shadow;
  376. }
  377. public void paintBorder(Component c, Graphics g, int x, int y,
  378. int width, int height) {
  379. Component child;
  380. Rectangle cBounds;
  381. JSplitPane splitPane = ((BasicSplitPaneDivider)c).
  382. getBasicSplitPaneUI().getSplitPane();
  383. Dimension size = c.getSize();
  384. child = splitPane.getLeftComponent();
  385. // This is needed for the space between the divider and end of
  386. // splitpane.
  387. g.setColor(c.getBackground());
  388. g.drawRect(x, y, width - 1, height - 1);
  389. if(splitPane.getOrientation() == JSplitPane.HORIZONTAL_SPLIT) {
  390. if(child != null) {
  391. g.setColor(highlight);
  392. g.drawLine(0, 0, 0, size.height);
  393. }
  394. child = splitPane.getRightComponent();
  395. if(child != null) {
  396. g.setColor(shadow);
  397. g.drawLine(size.width - 1, 0, size.width - 1, size.height);
  398. }
  399. } else {
  400. if(child != null) {
  401. g.setColor(highlight);
  402. g.drawLine(0, 0, size.width, 0);
  403. }
  404. child = splitPane.getRightComponent();
  405. if(child != null) {
  406. g.setColor(shadow);
  407. g.drawLine(0, size.height - 1, size.width,
  408. size.height - 1);
  409. }
  410. }
  411. }
  412. public Insets getBorderInsets(Component c) {
  413. Insets insets = new Insets(0,0,0,0);
  414. if (c instanceof BasicSplitPaneDivider) {
  415. BasicSplitPaneUI bspui = ((BasicSplitPaneDivider)c).
  416. getBasicSplitPaneUI();
  417. if (bspui != null) {
  418. JSplitPane splitPane = bspui.getSplitPane();
  419. if (splitPane != null) {
  420. if (splitPane.getOrientation() ==
  421. JSplitPane.HORIZONTAL_SPLIT) {
  422. insets.top = insets.bottom = 0;
  423. insets.left = insets.right = 1;
  424. return insets;
  425. }
  426. // VERTICAL_SPLIT
  427. insets.top = insets.bottom = 1;
  428. insets.left = insets.right = 0;
  429. return insets;
  430. }
  431. }
  432. }
  433. insets.top = insets.bottom = insets.left = insets.right = 1;
  434. return insets;
  435. }
  436. public boolean isBorderOpaque() { return true; }
  437. }
  438. /**
  439. * Draws the border around the splitpane. To work correctly you shoudl
  440. * also install a border on the divider (property SplitPaneDivider.border).
  441. */
  442. public static class SplitPaneBorder implements Border, UIResource {
  443. protected Color highlight;
  444. protected Color shadow;
  445. public SplitPaneBorder(Color highlight, Color shadow) {
  446. this.highlight = highlight;
  447. this.shadow = shadow;
  448. }
  449. public void paintBorder(Component c, Graphics g, int x, int y,
  450. int width, int height) {
  451. // The only tricky part with this border is that the divider is
  452. // not positioned at the top (for horizontal) or left (for vert),
  453. // so this border draws to where the divider is:
  454. // -----------------
  455. // |xxxxxxx xxxxxxx|
  456. // |x --- x|
  457. // |x | | x|
  458. // |x |D| x|
  459. // |x | | x|
  460. // |x --- x|
  461. // |xxxxxxx xxxxxxx|
  462. // -----------------
  463. // The above shows (rather excessively) what this looks like for
  464. // a horizontal orientation. This border then draws the x's, with
  465. // the SplitPaneDividerBorder drawing its own border.
  466. Component child;
  467. Rectangle cBounds;
  468. JSplitPane splitPane = (JSplitPane)c;
  469. child = splitPane.getLeftComponent();
  470. // This is needed for the space between the divider and end of
  471. // splitpane.
  472. g.setColor(c.getBackground());
  473. g.drawRect(x, y, width - 1, height - 1);
  474. if(splitPane.getOrientation() == JSplitPane.HORIZONTAL_SPLIT) {
  475. if(child != null) {
  476. cBounds = child.getBounds();
  477. g.setColor(shadow);
  478. g.drawLine(0, 0, cBounds.width + 1, 0);
  479. g.drawLine(0, 1, 0, cBounds.height + 2);
  480. g.setColor(highlight);
  481. g.drawLine(1, cBounds.height + 1, cBounds.width + 1,
  482. cBounds.height + 1);
  483. }
  484. child = splitPane.getRightComponent();
  485. if(child != null) {
  486. cBounds = child.getBounds();
  487. int maxX = cBounds.x + cBounds.width;
  488. int maxY = cBounds.y + cBounds.height;
  489. g.setColor(shadow);
  490. g.drawLine(cBounds.x - 1, 0, maxX, 0);
  491. g.drawLine(cBounds.x - 1, maxY, cBounds.x, maxY);
  492. g.setColor(highlight);
  493. g.drawLine(cBounds.x, maxY, maxX, maxY);
  494. g.drawLine(maxX, 0, maxX, maxY + 1);
  495. }
  496. } else {
  497. if(child != null) {
  498. cBounds = child.getBounds();
  499. g.setColor(shadow);
  500. g.drawLine(0, 0, cBounds.width + 1, 0);
  501. g.drawLine(0, 1, 0, cBounds.height);
  502. g.setColor(highlight);
  503. g.drawLine(1 + cBounds.width, 0, 1 + cBounds.width,
  504. cBounds.height + 1);
  505. g.drawLine(0, cBounds.height + 1, 0, cBounds.height + 1);
  506. }
  507. child = splitPane.getRightComponent();
  508. if(child != null) {
  509. cBounds = child.getBounds();
  510. int maxX = cBounds.x + cBounds.width;
  511. int maxY = cBounds.y + cBounds.height;
  512. g.setColor(shadow);
  513. g.drawLine(0, cBounds.y - 1, 0, maxY);
  514. g.drawLine(maxX, cBounds.y - 1, maxX, cBounds.y - 1);
  515. g.setColor(highlight);
  516. g.drawLine(0, maxY, cBounds.width + 1, maxY);
  517. g.drawLine(maxX, cBounds.y, maxX, maxY);
  518. }
  519. }
  520. }
  521. public Insets getBorderInsets(Component c) {
  522. return new Insets(1, 1, 1, 1);
  523. }
  524. public boolean isBorderOpaque() { return true; }
  525. }
  526. }