GNU Classpath (0.20) | |
Frames | No Frames |
1: /* BasicBorders.java -- 2: Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package javax.swing.plaf.basic; 40: 41: import java.awt.Color; 42: import java.awt.Component; 43: import java.awt.Graphics; 44: import java.awt.Insets; 45: import java.awt.Rectangle; 46: import java.io.Serializable; 47: 48: import javax.swing.AbstractButton; 49: import javax.swing.ButtonModel; 50: import javax.swing.JButton; 51: import javax.swing.JPopupMenu; 52: import javax.swing.JSplitPane; 53: import javax.swing.JToolBar; 54: import javax.swing.UIManager; 55: import javax.swing.border.AbstractBorder; 56: import javax.swing.border.BevelBorder; 57: import javax.swing.border.Border; 58: import javax.swing.plaf.BorderUIResource; 59: import javax.swing.plaf.UIResource; 60: import javax.swing.text.JTextComponent; 61: 62: /** 63: * Provides various borders for the Basic look and feel. 64: * 65: * @author Sascha Brawer (brawer@dandelis.ch) 66: */ 67: public class BasicBorders 68: { 69: /** 70: * A MarginBorder that gets shared by multiple components. 71: * Created on demand by the private helper function {@link 72: * #getMarginBorder()}. 73: */ 74: private static MarginBorder sharedMarginBorder; 75: 76: 77: /** 78: * Returns a border for drawing push buttons. 79: * 80: * <p>The colors of the border are retrieved from the 81: * <code>UIDefaults</code> of the currently active look and feel 82: * using the keys <code>“Button.shadow”</code>, 83: * <code>“Button.darkShadow”</code>, 84: * <code>“Button.light”</code>, and 85: * <code>“Button.highlight”</code>. 86: * 87: * <p><img src="doc-files/BasicBorders.ButtonBorder-1.png" width="300" 88: * height="170" alt="[A screen shot of the returned border]" /> 89: * 90: * @return a {@link 91: * javax.swing.plaf.BorderUIResource.CompoundBorderUIResource} 92: * whose outer border is a {@link ButtonBorder} and whose 93: * inner border is a {@link MarginBorder}. 94: */ 95: public static Border getButtonBorder() 96: { 97: Border outer; 98: 99: /* The keys for UIDefaults have been determined by writing a 100: * test program that dumps the UIDefaults to stdout; that program 101: * was run on a JDK 1.4.1_01 for GNU/Linux. Note that in the API, 102: * the key "light" is usually called "highlight", and "highlight" 103: * is usually called "lightHighlight". 104: */ 105: outer = new ButtonBorder(UIManager.getColor("Button.shadow"), 106: UIManager.getColor("Button.darkShadow"), 107: UIManager.getColor("Button.light"), 108: UIManager.getColor("Button.highlight")); 109: 110: /* While the inner border is shared between multiple buttons, 111: * we do not share the outer border because ButtonBorders store 112: * their border colors. We cannot guarantee that the colors 113: * (which come from UIDefaults) are unchanged between invocations 114: * of getButtonBorder. We could store the last colors, and share 115: * the button border if the colors are the same as in the last 116: * invocation, but it probably is not worth the effort. 117: */ 118: return new BorderUIResource.CompoundBorderUIResource( 119: outer, 120: /* inner */ getMarginBorder()); 121: } 122: 123: 124: /** 125: * Returns a border for drawing radio buttons. 126: * 127: * <p>The colors of the border are retrieved from the 128: * <code>UIDefaults</code> of the currently active look and feel 129: * using the keys <code>“RadioButton.shadow”</code>, 130: * <code>“RadioButton.darkShadow”</code>, 131: * <code>“RadioButton.light”</code>, and 132: * <code>“RadioButton.highlight”</code>. 133: * 134: * <p><img src="doc-files/BasicBorders.RadioButtonBorder-1.png" width="300" 135: * height="135" alt="[A screen shot of the returned border]" /> 136: * 137: * @return a {@link 138: * javax.swing.plaf.BorderUIResource.CompoundBorderUIResource} 139: * whose outer border is a {@link RadioButtonBorder} and whose 140: * inner border is a {@link MarginBorder}. 141: */ 142: public static Border getRadioButtonBorder() 143: { 144: Border outer; 145: 146: /* The keys for UIDefaults have been determined by writing a 147: * test program that dumps the UIDefaults to stdout; that program 148: * was run on a JDK 1.4.1_01 for GNU/Linux. Note that in the API, 149: * the key "light" is usually called "highlight", and "highlight" 150: * is usually called "lightHighlight". 151: */ 152: outer = new RadioButtonBorder( 153: UIManager.getColor("RadioButton.shadow"), 154: UIManager.getColor("RadioButton.darkShadow"), 155: UIManager.getColor("RadioButton.light"), 156: UIManager.getColor("RadioButton.highlight")); 157: 158: /* While the inner border is shared between multiple buttons, we 159: * do not share the outer border because RadioButtonBorders, being 160: * ButtonBorders, store their border colors. We cannot guarantee 161: * that the colors (which come from UIDefaults) are unchanged 162: * between invocations of getButtonBorder. We could store the last 163: * colors, and share the button border if the colors are the same 164: * as in the last invocation, but it probably is not worth the 165: * effort. 166: */ 167: return new BorderUIResource.CompoundBorderUIResource( 168: outer, 169: /* inner */ getMarginBorder()); 170: } 171: 172: 173: /** 174: * Returns a border for drawing toggle buttons. 175: * 176: * <p>The colors of the border are retrieved from the 177: * <code>UIDefaults</code> of the currently active look and feel 178: * using the keys <code>“ToggleButton.shadow”</code>, 179: * <code>“ToggleButton.darkShadow”</code>, 180: * <code>“ToggleButton.light”</code>, and 181: * <code>“ToggleButton.highlight”</code>. 182: * 183: * <p><img src="doc-files/BasicBorders.ToggleButtonBorder-1.png" width="270" 184: * height="135" alt="[A screen shot of the returned border]" /> 185: * 186: * @return a {@link 187: * javax.swing.plaf.BorderUIResource.CompoundBorderUIResource} 188: * whose outer border is a {@link ToggleButtonBorder} and whose 189: * inner border is a {@link MarginBorder}. 190: */ 191: public static Border getToggleButtonBorder() 192: { 193: Border outer; 194: 195: /* The keys for UIDefaults have been determined by writing a 196: * test program that dumps the UIDefaults to stdout; that program 197: * was run on a JDK 1.4.1_01 for GNU/Linux. Note that in the API, 198: * the key "light" is usually called "highlight", and "highlight" 199: * is usually called "lightHighlight". 200: */ 201: outer = new ToggleButtonBorder( 202: UIManager.getColor("ToggleButton.shadow"), 203: UIManager.getColor("ToggleButton.darkShadow"), 204: UIManager.getColor("ToggleButton.light"), 205: UIManager.getColor("ToggleButton.highlight")); 206: 207: /* While the inner border is shared between multiple buttons, we 208: * do not share the outer border because ToggleButtonBorders, being 209: * ButtonBorders, store their border colors. We cannot guarantee 210: * that the colors (which come from UIDefaults) are unchanged 211: * between invocations of getButtonBorder. We could store the last 212: * colors, and share the button border if the colors are the same 213: * as in the last invocation, but it probably is not worth the 214: * effort. 215: */ 216: return new BorderUIResource.CompoundBorderUIResource( 217: outer, 218: /* inner */ getMarginBorder()); 219: } 220: 221: 222: /** 223: * Returns a border for drawing a two-pixel thick separator line 224: * below menu bars. 225: * 226: * <p>The colors of the border are retrieved from the 227: * <code>UIDefaults</code> of the currently active look and feel 228: * using the keys <code>“MenuBar.shadow”</code> and 229: * <code>“MenuBar.highlight”</code>. 230: * 231: * <p><img src="doc-files/BasicBorders.MenuBarBorder-1.png" width="500" 232: * height="140" alt="[A screen shot of a JMenuBar with this border]" /> 233: * 234: * @return a {@link MenuBarBorder}. 235: * 236: * @see javax.swing.JMenuBar 237: */ 238: public static Border getMenuBarBorder() 239: { 240: /* See comment in methods above for why this border is not shared. */ 241: return new MenuBarBorder(UIManager.getColor("MenuBar.shadow"), 242: UIManager.getColor("MenuBar.highlight")); 243: } 244: 245: 246: /** 247: * Returns a border for drawing a one-pixel thick border around 248: * split panes that are interrupted where the divider joins the 249: * border. 250: * 251: * <p>The colors of the border are retrieved from the 252: * <code>UIDefaults</code> of the currently active look and feel 253: * using the keys <code>“SplitPane.darkShadow”</code> and 254: * <code>“SplitPane.highlight”</code>. 255: * 256: * <p><img src="doc-files/BasicBorders.SplitPaneBorder-1.png" width="520" 257: * height="200" alt="[A screen shot for JSplitPane.HORIZONTAL_SPLIT]" /> 258: * 259: * <p><img src="doc-files/BasicBorders.SplitPaneBorder-2.png" width="520" 260: * height="200" alt="[A screen shot for JSplitPane.VERTICAL_SPLIT]" /> 261: * 262: * @return a {@link SplitPaneBorder}. 263: * 264: * @see javax.swing.JSplitPane 265: * @see #getSplitPaneDividerBorder() 266: */ 267: public static Border getSplitPaneBorder() 268: { 269: /* See comment in methods above for why this border is not shared. */ 270: return new SplitPaneBorder(UIManager.getColor("SplitPane.highlight"), 271: UIManager.getColor("SplitPane.darkShadow")); 272: } 273: 274: 275: /** 276: * Returns a border for drawing a one-pixel thick border around 277: * the divider of split panes. 278: * 279: * <p>The colors of the edges that are adjacent to the child components 280: * of the <code>JSplitPane</code> are retrieved from the 281: * <code>UIDefaults</code> of the currently active look and feel 282: * using the keys <code>“SplitPane.darkShadow”</code> and 283: * <code>“SplitPane.highlight”</code>. The color of the 284: * other two edges is the background color of the divider. 285: * 286: * <p><img src="doc-files/BasicBorders.SplitPaneDividerBorder-1.png" 287: * width="520" height="200" alt= 288: * "[A screen shot for JSplitPane.HORIZONTAL_SPLIT]" /> 289: * 290: * @return an instance of <code>SplitPaneDividerBorder</code>, which is 291: * not a public API class of this package. 292: * 293: * @see javax.swing.JSplitPane 294: * @see javax.swing.plaf.basic.BasicSplitPaneDivider 295: * @see #getSplitPaneBorder() 296: * 297: * @since 1.3 298: */ 299: public static Border getSplitPaneDividerBorder() 300: { 301: /* See comment in methods above for why this border is not shared. */ 302: return new SplitPaneDividerBorder( 303: UIManager.getColor("SplitPane.highlight"), 304: UIManager.getColor("SplitPane.darkShadow")); 305: } 306: 307: 308: /** 309: * Returns a border for drawing a border around a text field 310: * that makes the field appear as etched into the surface. 311: * 312: * <p>The colors of the border are retrieved from the 313: * <code>UIDefaults</code> of the currently active look and feel 314: * using the keys <code>“TextField.shadow”</code>, 315: * <code>“TextField.darkShadow”</code>, 316: * <code>“TextField.light”</code>, and 317: * <code>“TextField.highlight”</code>. 318: * 319: * <p><img src="doc-files/BasicBorders.FieldBorder-1.png" width="500" 320: * height="200" alt="[A screen shot of a border returned by 321: * this method]" /> 322: * 323: * @return an instance of {@link FieldBorder}. 324: * 325: * @see javax.swing.JTextField 326: * @see javax.swing.text.JTextComponent 327: */ 328: public static Border getTextFieldBorder() 329: { 330: /* See comment in methods above for why this border is not shared. */ 331: return new FieldBorder( 332: UIManager.getColor("TextField.shadow"), 333: UIManager.getColor("TextField.darkShadow"), 334: UIManager.getColor("TextField.light"), 335: UIManager.getColor("TextField.highlight")); 336: } 337: 338: 339: /** 340: * Returns a two-pixel thick, green 341: * <code>LineBorderUIResource</code>. This is so ugly that look and 342: * feels better use different borders for their progress bars, or 343: * they will look really terrible. 344: * 345: * <p><img src="doc-files/BasicBorders-1.png" width="120" height="80" 346: * alt="[A screen shot of a border returned by this method]" /> 347: */ 348: public static Border getProgressBarBorder() 349: { 350: /* There does not seem to exist a way to parametrize the color 351: * or thickness of the border through UIDefaults. 352: */ 353: return new BorderUIResource.LineBorderUIResource(Color.green, 2); 354: } 355: 356: 357: /** 358: * Returns a border that is composed of a raised bevel border and a 359: * one-pixel thick line border. 360: * 361: * <p><img src="doc-files/BasicBorders-2.png" width="300" height="200" 362: * alt="[A screen shot of a border returned by this method]" /> 363: * 364: * <p>The colors of the border are retrieved from the 365: * <code>UIDefaults</code> of the currently active look and feel 366: * using the keys <code>“InternalFrame.borderShadow”</code>, 367: * <code>“InternalFrame.borderDarkShadow”</code>, 368: * <code>“InternalFrame.borderLight”</code>, 369: * <code>“InternalFrame.borderHighlight”</code>, and 370: * (for the inner one-pixel thick line) 371: * <code>“InternalFrame.borderColor”</code>. 372: */ 373: public static Border getInternalFrameBorder() 374: { 375: Color shadow, darkShadow, highlight, lightHighlight, line; 376: 377: /* See comment in methods above for why this border is not shared. */ 378: shadow = UIManager.getColor("InternalFrame.borderShadow"); 379: darkShadow = UIManager.getColor("InternalFrame.borderDarkShadow"); 380: highlight = UIManager.getColor("InternalFrame.borderLight"); 381: lightHighlight = UIManager.getColor("InternalFrame.borderHighlight"); 382: line = UIManager.getColor("InternalFrame.borderColor"); 383: 384: return new BorderUIResource.CompoundBorderUIResource( 385: /* outer border */ 386: new BorderUIResource.BevelBorderUIResource( 387: BevelBorder.RAISED, 388: (highlight != null) ? highlight : Color.lightGray, 389: (lightHighlight != null) ? lightHighlight : Color.white, 390: (darkShadow != null) ? darkShadow : Color.black, 391: (shadow != null) ? shadow : Color.gray), 392: 393: /* inner border */ 394: new BorderUIResource.LineBorderUIResource( 395: (line != null) ? line : Color.lightGray)); 396: } 397: 398: 399: /** 400: * Returns a shared MarginBorder. 401: */ 402: static Border getMarginBorder() // intentionally not public 403: { 404: /* Swing is not designed to be thread-safe, so there is no 405: * need to synchronize the access to the global variable. 406: */ 407: if (sharedMarginBorder == null) 408: sharedMarginBorder = new MarginBorder(); 409: 410: return sharedMarginBorder; 411: } 412: 413: 414: /** 415: * A border whose appearance depends on the state of 416: * the enclosed button. 417: * 418: * <p><img src="doc-files/BasicBorders.ButtonBorder-1.png" width="300" 419: * height="170" alt="[A screen shot of this border]" /> 420: * 421: * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel 422: * 423: * @author Sascha Brawer (brawer@dandelis.ch) 424: */ 425: public static class ButtonBorder 426: extends AbstractBorder 427: implements Serializable, UIResource 428: { 429: /** 430: * Determined using the <code>serialver</code> tool 431: * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5. 432: */ 433: static final long serialVersionUID = -157053874580739687L; 434: 435: 436: /** 437: * The color for drawing the shaded parts of the border. 438: * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel 439: */ 440: protected Color shadow; 441: 442: 443: /** 444: * The color for drawing the dark shaded parts of the border. 445: * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel 446: */ 447: protected Color darkShadow; 448: 449: 450: /** 451: * The color for drawing the highlighted parts of the border. 452: * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel 453: */ 454: protected Color highlight; 455: 456: 457: /** 458: * The color for drawing the bright highlighted parts of the border. 459: * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel 460: */ 461: protected Color lightHighlight; 462: 463: 464: /** 465: * Constructs a new border for drawing a button in the Basic 466: * look and feel. 467: * 468: * @param shadow the shadow color. 469: * @param darkShadow a darker variant of the shadow color. 470: * @param highlight the highlight color. 471: * @param lightHighlight a brighter variant of the highlight color. 472: */ 473: public ButtonBorder(Color shadow, Color darkShadow, 474: Color highlight, Color lightHighlight) 475: { 476: /* These colors usually come from the UIDefaults of the current 477: * look and feel. Use fallback values if the colors are not 478: * supplied. The API specification is silent about what 479: * behavior is expected for null colors, so users should not 480: * rely on this fallback (which is why it is not documented in 481: * the above Javadoc). 482: */ 483: this.shadow = (shadow != null) ? shadow : Color.gray; 484: this.darkShadow = (darkShadow != null) ? darkShadow : Color.black; 485: this.highlight = (highlight != null) ? highlight : Color.lightGray; 486: this.lightHighlight = (lightHighlight != null) 487: ? lightHighlight 488: : Color.white; 489: } 490: 491: 492: /** 493: * Paints the ButtonBorder around a given component. 494: * 495: * @param c the component whose border is to be painted. 496: * @param g the graphics for painting. 497: * @param x the horizontal position for painting the border. 498: * @param y the vertical position for painting the border. 499: * @param width the width of the available area for painting the border. 500: * @param height the height of the available area for painting the border. 501: * 502: * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel 503: */ 504: public void paintBorder(Component c, Graphics g, 505: int x, int y, int width, int height) 506: { 507: ButtonModel bmodel = null; 508: 509: if (c instanceof AbstractButton) 510: bmodel = ((AbstractButton) c).getModel(); 511: 512: BasicGraphicsUtils.drawBezel( 513: g, x, y, width, height, 514: /* pressed */ (bmodel != null) 515: && /* mouse button pressed */ bmodel.isPressed() 516: && /* mouse inside */ bmodel.isArmed(), 517: /* default */ (c instanceof JButton) 518: && ((JButton) c).isDefaultButton(), 519: shadow, darkShadow, highlight, lightHighlight); 520: } 521: 522: 523: /** 524: * Measures the width of this border. 525: * 526: * <p>Although the thickness of the actually painted border 527: * depends on the state of the enclosed component, this 528: * measurement always returns the same amount of pixels. Indeed, 529: * it would be rather confusing if a button was appearing to 530: * change its size depending on whether it is pressed or not. 531: * 532: * @param c the component whose border is to be measured. 533: * 534: * @return an Insets object whose <code>left</code>, 535: * <code>right</code>, <code>top</code> and 536: * <code>bottom</code> fields indicate the width of the 537: * border at the respective edge. 538: * 539: * @see #getBorderInsets(java.awt.Component, java.awt.Insets) 540: */ 541: public Insets getBorderInsets(Component c) 542: { 543: /* There is no obvious reason for overriding this method, but we 544: * try to have exactly the same API as the Sun reference 545: * implementation. 546: */ 547: return getBorderInsets(c, null); 548: } 549: 550: 551: /** 552: * Measures the width of this border, storing the results into a 553: * pre-existing Insets object. 554: * 555: * <p>Although the thickness of the actually painted border 556: * depends on the state of the enclosed component, this 557: * measurement always returns the same amount of pixels. Indeed, 558: * it would be rather confusing if a button was appearing to 559: * change its size depending on whether it is pressed or not. 560: * 561: * @param insets an Insets object for holding the result values. 562: * After invoking this method, the <code>left</code>, 563: * <code>right</code>, <code>top</code> and 564: * <code>bottom</code> fields indicate the width of the 565: * border at the respective edge. 566: * 567: * @return the same object that was passed for <code>insets</code>. 568: * 569: * @see #getBorderInsets(Component) 570: */ 571: public Insets getBorderInsets(Component c, Insets insets) 572: { 573: /* The exact amount has been determined using a test program 574: * that was run on the Sun reference implementation. With 575: * Apple/Sun JDK 1.3.1 on MacOS X 10.1.5, the result is 576: * [3, 3, 3, 3]. With Sun JDK 1.4.1_01 on Linux/x86, the 577: * result is [2, 3, 3, 3]. We use the values from the 1.4.1_01 578: * release. 579: */ 580: if (insets == null) 581: return new Insets(2, 3, 3, 3); 582: 583: insets.top = 2; 584: insets.bottom = insets.left = insets.right = 3; 585: return insets; 586: } 587: } 588: 589: 590: /** 591: * A border that makes its enclosed component appear as lowered 592: * into the surface. Typically used for text fields. 593: * 594: * <p><img src="doc-files/BasicBorders.FieldBorder-1.png" width="500" 595: * height="200" alt="[A screen shot of this border]" /> 596: * 597: * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawEtchedRect 598: * 599: * @author Sascha Brawer (brawer@dandelis.ch) 600: */ 601: public static class FieldBorder 602: extends AbstractBorder 603: implements UIResource 604: { 605: /** 606: * Determined using the <code>serialver</code> tool 607: * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5. 608: */ 609: static final long serialVersionUID = 949220756998454908L; 610: 611: 612: /** 613: * The color for drawing the outer half of the top and left 614: * edges. 615: */ 616: protected Color shadow; 617: 618: 619: /** 620: * The color for drawing the inner half of the top and left 621: * edges. 622: */ 623: protected Color darkShadow; 624: 625: 626: /** 627: * The color for drawing the inner half of the bottom and right 628: * edges. 629: */ 630: protected Color highlight; 631: 632: 633: /** 634: * The color for drawing the outer half of the bottom and right 635: * edges. 636: */ 637: protected Color lightHighlight; 638: 639: 640: /** 641: * Constructs a new border for drawing a text field in the Basic 642: * look and feel. 643: * 644: * @param shadow the color for drawing the outer half 645: * of the top and left edges. 646: * 647: * @param darkShadow the color for drawing the inner half 648: * of the top and left edges. 649: * 650: * @param highlight the color for drawing the inner half 651: * of the bottom and right edges. 652: * 653: * @param lightHighlight the color for drawing the outer half 654: * of the bottom and right edges. 655: */ 656: public FieldBorder(Color shadow, Color darkShadow, 657: Color highlight, Color lightHighlight) 658: { 659: /* These colors usually come from the UIDefaults of the current 660: * look and feel. Use fallback values if the colors are not 661: * supplied. The API specification is silent about what 662: * behavior is expected for null colors, so users should not 663: * rely on this fallback (which is why it is not documented in 664: * the above Javadoc). 665: */ 666: this.shadow = (shadow != null) ? shadow : Color.gray; 667: this.darkShadow = (darkShadow != null) ? darkShadow : Color.black; 668: this.highlight = (highlight != null) ? highlight : Color.lightGray; 669: this.lightHighlight = (lightHighlight != null) 670: ? lightHighlight : Color.white; 671: } 672: 673: 674: /** 675: * Paints the FieldBorder around a given component. 676: * 677: * @param c the component whose border is to be painted. 678: * @param g the graphics for painting. 679: * @param x the horizontal position for painting the border. 680: * @param y the vertical position for painting the border. 681: * @param width the width of the available area for painting the border. 682: * @param height the height of the available area for painting the border. 683: * 684: * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawEtchedRect 685: */ 686: public void paintBorder(Component c, Graphics g, 687: int x, int y, int width, int height) 688: { 689: BasicGraphicsUtils.drawEtchedRect(g, x, y, width, height, 690: shadow, darkShadow, 691: highlight, lightHighlight); 692: } 693: 694: 695: /** 696: * Measures the width of this border. 697: * 698: * @param c the component whose border is to be measured. 699: * If <code>c</code> is an instance of {@link 700: * javax.swing.text.JTextComponent}, its margin is 701: * added to the border size. 702: * 703: * @return an Insets object whose <code>left</code>, 704: * <code>right</code>, <code>top</code> and 705: * <code>bottom</code> fields indicate the width of the 706: * border at the respective edge. 707: * 708: * @see #getBorderInsets(java.awt.Component, java.awt.Insets) 709: */ 710: public Insets getBorderInsets(Component c) 711: { 712: return getBorderInsets(c, null); 713: } 714: 715: 716: /** 717: * Measures the width of this border, storing the results into a 718: * pre-existing Insets object. 719: * 720: * @param c the component whose border is to be measured. 721: * If <code>c</code> is an instance of {@link 722: * javax.swing.text.JTextComponent}, its margin is 723: * added to the border size. 724: * 725: * @param insets an Insets object for holding the result values. 726: * After invoking this method, the <code>left</code>, 727: * <code>right</code>, <code>top</code> and 728: * <code>bottom</code> fields indicate the width of the 729: * border at the respective edge. 730: * 731: * @return the same object that was passed for <code>insets</code>. 732: * 733: * @see #getBorderInsets(Component) 734: */ 735: public Insets getBorderInsets(Component c, Insets insets) 736: { 737: if (insets == null) 738: insets = new Insets(2, 2, 2, 2); 739: else 740: insets.top = insets.left = insets.bottom = insets.right = 2; 741: 742: if (c instanceof JTextComponent) 743: { 744: Insets margin = ((JTextComponent) c).getMargin(); 745: insets.top += margin.top; 746: insets.left += margin.left; 747: insets.bottom += margin.bottom; 748: insets.right += margin.right; 749: } 750: 751: return insets; 752: } 753: } 754: 755: 756: /** 757: * An invisible, but spacing border whose margin is determined 758: * by calling the <code>getMargin()</code> method of the enclosed 759: * component. If the enclosed component has no such method, 760: * this border will not occupy any space. 761: * 762: * <p><img src="doc-files/BasicBorders.MarginBorder-1.png" width="325" 763: * height="200" alt="[An illustration that shows how MarginBorder 764: * determines its borders]" /> 765: * 766: * @author Sascha Brawer (brawer@dandelis.ch) 767: */ 768: public static class MarginBorder 769: extends AbstractBorder 770: implements Serializable, UIResource 771: { 772: /** 773: * Determined using the <code>serialver</code> tool 774: * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5. 775: */ 776: static final long serialVersionUID = -3035848353448896090L; 777: 778: 779: /** 780: * Constructs a new MarginBorder. 781: */ 782: public MarginBorder() 783: { 784: // Nothing to do here. 785: } 786: 787: /** 788: * Measures the width of this border. 789: * 790: * @param c the component whose border is to be measured. 791: * 792: * @return an Insets object whose <code>left</code>, <code>right</code>, 793: * <code>top</code> and <code>bottom</code> fields indicate the 794: * width of the border at the respective edge. 795: * 796: * @see #getBorderInsets(java.awt.Component, java.awt.Insets) 797: */ 798: public Insets getBorderInsets(Component c) 799: { 800: return getBorderInsets(c, new Insets(0, 0, 0, 0)); 801: } 802: 803: 804: /** 805: * Determines the insets of this border by calling the 806: * <code>getMargin()</code> method of the enclosed component. The 807: * resulting margin will be stored into the the <code>left</code>, 808: * <code>right</code>, <code>top</code> and <code>bottom</code> 809: * fields of the passed <code>insets</code> parameter. 810: * 811: * <p>Unfortunately, <code>getMargin()</code> is not a method of 812: * {@link javax.swing.JComponent} or some other common superclass 813: * of things with margins. While reflection could be used to 814: * determine the existence of this method, this would be slow on 815: * many virtual machines. Therefore, the current implementation 816: * knows about {@link javax.swing.AbstractButton#getMargin()}, 817: * {@link javax.swing.JPopupMenu#getMargin()}, {@link 818: * javax.swing.JToolBar#getMargin()}, and {@link 819: * javax.swing.text.JTextComponent}. If <code>c</code> is an 820: * instance of a known class, the respective 821: * <code>getMargin()</code> method is called to determine the 822: * correct margin. Otherwise, a zero-width margin is returned. 823: * 824: * @param c the component whose border is to be measured. 825: * 826: * @return the same object that was passed for <code>insets</code>, 827: * but with changed fields. 828: */ 829: public Insets getBorderInsets(Component c, Insets insets) 830: { 831: Insets margin = null; 832: 833: /* This is terrible object-oriented design. See the above Javadoc 834: * for an excuse. 835: */ 836: if (c instanceof AbstractButton) 837: margin = ((AbstractButton) c).getMargin(); 838: else if (c instanceof JPopupMenu) 839: margin = ((JPopupMenu) c).getMargin(); 840: else if (c instanceof JToolBar) 841: margin = ((JToolBar) c).getMargin(); 842: else if (c instanceof JTextComponent) 843: margin = ((JTextComponent) c).getMargin(); 844: 845: if (margin == null) 846: insets.top = insets.left = insets.bottom = insets.right = 0; 847: else 848: { 849: insets.top = margin.top; 850: insets.left = margin.left; 851: insets.bottom = margin.bottom; 852: insets.right = margin.right; 853: } 854: 855: return insets; 856: } 857: } 858: 859: 860: /** 861: * A border for drawing a separator line below JMenuBar. 862: * 863: * <p><img src="doc-files/BasicBorders.MenuBarBorder-1.png" width="500" 864: * height="140" alt="[A screen shot of a JMenuBar with this border]" /> 865: * 866: * @author Sascha Brawer (brawer@dandelis.ch) 867: */ 868: public static class MenuBarBorder 869: extends AbstractBorder 870: implements UIResource 871: { 872: /** 873: * Determined using the <code>serialver</code> tool 874: * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5. 875: */ 876: static final long serialVersionUID = -6909056571935227506L; 877: 878: 879: /** 880: * The shadow color, which is used for the upper line of the 881: * two-pixel thick bottom edge. 882: */ 883: private Color shadow; 884: 885: 886: /** 887: * The highlight color, which is used for the lower line of the 888: * two-pixel thick bottom edge. 889: */ 890: private Color highlight; 891: 892: 893: /** 894: * Constructs a new MenuBarBorder for drawing a JMenuBar in 895: * the Basic look and feel. 896: * 897: * <p><img src="doc-files/BasicBorders.MenuBarBorder-1.png" width="500" 898: * height="140" alt="[A screen shot of a JMenuBar with this 899: * border]" /> 900: * 901: * @param shadow the shadow color, which is used for the upper 902: * line of the two-pixel thick bottom edge. 903: * 904: * @param highlight the shadow color, which is used for the lower 905: * line of the two-pixel thick bottom edge. 906: */ 907: public MenuBarBorder(Color shadow, Color highlight) 908: { 909: /* These colors usually come from the UIDefaults of the current 910: * look and feel. Use fallback values if the colors are not 911: * supplied. The API specification is silent about what 912: * behavior is expected for null colors, so users should not 913: * rely on this fallback (which is why it is not documented in 914: * the above Javadoc). 915: */ 916: this.shadow = (shadow != null) ? shadow : Color.gray; 917: this.highlight = (highlight != null) ? highlight : Color.white; 918: } 919: 920: 921: /** 922: * Paints the MenuBarBorder around a given component. 923: * 924: * @param c the component whose border is to be painted, usually 925: * an instance of {@link javax.swing.JMenuBar}. 926: * 927: * @param g the graphics for painting. 928: * @param x the horizontal position for painting the border. 929: * @param y the vertical position for painting the border. 930: * @param width the width of the available area for painting the border. 931: * @param height the height of the available area for painting the border. 932: */ 933: public void paintBorder(Component c, Graphics g, 934: int x, int y, int width, int height) 935: { 936: Color oldColor; 937: 938: /* To understand this code, it might be helpful to look at the 939: * image "BasicBorders.MenuBarBorder-1.png" that is included 940: * with the JavaDoc. It is located in the "doc-files" 941: * subdirectory. 942: */ 943: oldColor = g.getColor(); 944: y = y + height - 2; 945: try 946: { 947: g.setColor(shadow); 948: g.drawLine(x, y, x + width - 2, y); 949: g.drawLine(x, y + 1, x, y + 1); 950: g.drawLine(x + width - 2, y + 1, x + width - 2, y + 1); 951: 952: g.setColor(highlight); 953: g.drawLine(x + 1, y + 1, x + width - 3, y + 1); 954: g.drawLine(x + width - 1, y, x + width - 1, y + 1); 955: } 956: finally 957: { 958: g.setColor(oldColor); 959: } 960: } 961: 962: 963: /** 964: * Measures the width of this border. 965: * 966: * @param c the component whose border is to be measured. 967: * 968: * @return an Insets object whose <code>left</code>, 969: * <code>right</code>, <code>top</code> and 970: * <code>bottom</code> fields indicate the width of the 971: * border at the respective edge. 972: * 973: * @see #getBorderInsets(java.awt.Component, java.awt.Insets) 974: */ 975: public Insets getBorderInsets(Component c) 976: { 977: /* There is no obvious reason for overriding this method, but we 978: * try to have exactly the same API as the Sun reference 979: * implementation. 980: */ 981: return getBorderInsets(c, null); 982: } 983: 984: 985: /** 986: * Measures the width of this border, storing the results into a 987: * pre-existing Insets object. 988: * 989: * @param insets an Insets object for holding the result values. 990: * After invoking this method, the <code>left</code>, 991: * <code>right</code>, <code>top</code> and 992: * <code>bottom</code> fields indicate the width of the 993: * border at the respective edge. 994: * 995: * @return the same object that was passed for <code>insets</code>. 996: * 997: * @see #getBorderInsets(Component) 998: */ 999: public Insets getBorderInsets(Component c, Insets insets) 1000: { 1001: /* The exact amount has been determined using a test program 1002: * that was run on the Apple/Sun JDK 1.3.1 on MacOS X, and the 1003: * Sun JDK 1.4.1_01 on GNU/Linux for x86. Both gave [0,0,2,0], 1004: * which was expected from looking at the screen shot. 1005: */ 1006: if (insets == null) 1007: return new Insets(0, 0, 2, 0); 1008: 1009: insets.left = insets.right = insets.top = 0; 1010: insets.bottom = 2; 1011: return insets; 1012: } 1013: } 1014: 1015: 1016: /** 1017: * A border for drawing radio buttons in the Basic look and feel. 1018: * 1019: * <p><img src="doc-files/BasicBorders.RadioButtonBorder-1.png" width="300" 1020: * height="135" alt="[A screen shot of this border]" /> 1021: * 1022: * <p>Note about the screen shot: Normally, the 1023: * <code>borderPainted</code> property is <code>false</code> for 1024: * JRadioButtons. For this screen shot, it has been set to 1025: * <code>true</code> so the borders get drawn. Also, a 1026: * concretization of the Basic look and would typically provide 1027: * icons for the various states of radio buttons. 1028: * 1029: * <p>Note that the focus rectangle is invisible If the radio button 1030: * is currently selected. While it might be debatable whether this 1031: * makes a lot of sense, this behavior can be observed in the Sun 1032: * reference implementation (in JDK 1.3.1 and 1.4.1). The Classpath 1033: * implementation tries to exactly replicate the JDK appearance. 1034: * 1035: * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel 1036: * 1037: * @author Sascha Brawer (brawer@dandelis.ch) 1038: */ 1039: public static class RadioButtonBorder 1040: extends ButtonBorder 1041: { 1042: /** 1043: * Determined using the <code>serialver</code> tool 1044: * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5. 1045: */ 1046: static final long serialVersionUID = 1596945751743747369L; 1047: 1048: 1049: /** 1050: * Constructs a new border for drawing a JRadioButton in 1051: * the Basic look and feel. 1052: * 1053: * @param shadow the shadow color. 1054: * @param darkShadow a darker variant of the shadow color. 1055: * @param highlight the highlight color. 1056: * @param lightHighlight a brighter variant of the highlight color. 1057: */ 1058: public RadioButtonBorder(Color shadow, Color darkShadow, 1059: Color highlight, Color lightHighlight) 1060: { 1061: /* The superclass ButtonBorder substitutes null arguments 1062: * with fallback colors. 1063: */ 1064: super(shadow, darkShadow, highlight, lightHighlight); 1065: } 1066: 1067: 1068: /** 1069: * Paints the RadioButtonBorder around a given component. 1070: * 1071: * <p>The Sun implementation always seems to draw exactly 1072: * the same border, irrespective of the state of the button. 1073: * This is rather surprising, but GNU Classpath emulates the 1074: * observable behavior. 1075: * 1076: * @param c the component whose border is to be painted. 1077: * @param g the graphics for painting. 1078: * @param x the horizontal position for painting the border. 1079: * @param y the vertical position for painting the border. 1080: * @param width the width of the available area for painting the border. 1081: * @param height the height of the available area for painting the border. 1082: * 1083: * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel 1084: */ 1085: public void paintBorder(Component c, Graphics g, 1086: int x, int y, int width, int height) 1087: { 1088: AbstractButton button = null; 1089: ButtonModel bmodel = null; 1090: boolean lowered = false; 1091: boolean focused = false; 1092: 1093: if (c instanceof AbstractButton) 1094: { 1095: button = (AbstractButton) c; 1096: bmodel = button.getModel(); 1097: } 1098: 1099: if (bmodel != null) 1100: { 1101: lowered = button.isSelected() 1102: || (/* mouse inside */ bmodel.isArmed() && bmodel.isPressed()); 1103: focused = button.hasFocus() && button.isFocusPainted(); 1104: } 1105: 1106: if (lowered) 1107: BasicGraphicsUtils.drawLoweredBezel(g, x, y, width, height, 1108: shadow, darkShadow, 1109: highlight, lightHighlight); 1110: else 1111: BasicGraphicsUtils.drawBezel(g, x, y, width, height, 1112: /* isPressed */ false, 1113: /* isPefault */ focused, 1114: shadow, darkShadow, 1115: highlight, lightHighlight); 1116: } 1117: 1118: 1119: /** 1120: * Measures the width of this border. 1121: * 1122: * @param c the component whose border is to be measured. 1123: * 1124: * @return an Insets object whose <code>left</code>, 1125: * <code>right</code>, <code>top</code> and 1126: * <code>bottom</code> fields indicate the width of the 1127: * border at the respective edge. 1128: * 1129: * @see #getBorderInsets(java.awt.Component, java.awt.Insets) 1130: */ 1131: public Insets getBorderInsets(Component c) 1132: { 1133: /* There is no obvious reason for overriding this method, but we 1134: * try to have exactly the same API as the Sun reference 1135: * implementation. 1136: */ 1137: return getBorderInsets(c, null); 1138: } 1139: 1140: 1141: /** 1142: * Measures the width of this border, storing the results into a 1143: * pre-existing Insets object. 1144: * 1145: * @param insets an Insets object for holding the result values. 1146: * After invoking this method, the <code>left</code>, 1147: * <code>right</code>, <code>top</code> and 1148: * <code>bottom</code> fields indicate the width of the 1149: * border at the respective edge. 1150: * 1151: * @return the same object that was passed for <code>insets</code>. 1152: * 1153: * @see #getBorderInsets(Component) 1154: */ 1155: public Insets getBorderInsets(Component c, Insets insets) 1156: { 1157: /* The exact amount has been determined using a test program 1158: * that was run on the Apple/Sun JDK 1.3.1 on MacOS X, and the 1159: * Sun JDK 1.4.1_01 on GNU/Linux for x86. Both gave [2,2,2,2]. 1160: */ 1161: if (insets == null) 1162: return new Insets(2, 2, 2, 2); 1163: 1164: insets.left = insets.right = insets.top = insets.bottom = 2; 1165: return insets; 1166: } 1167: } 1168: 1169: 1170: /** 1171: * A one-pixel thick border for rollover buttons, for example in 1172: * tool bars. 1173: * 1174: * @since 1.4 1175: * @author Sascha Brawer (brawer@dandelis.ch) 1176: */ 1177: public static class RolloverButtonBorder 1178: extends ButtonBorder 1179: { 1180: /** 1181: * Determined using the <code>serialver</code> tool 1182: * of Sun JDK 1.4.1_01 on GNU/Linux 2.4.20 for x86. 1183: */ 1184: static final long serialVersionUID = 1976364864896996846L; 1185: 1186: 1187: /** 1188: * Constructs a new border for drawing a roll-over button 1189: * in the Basic look and feel. 1190: * 1191: * @param shadow the shadow color. 1192: * @param darkShadow a darker variant of the shadow color. 1193: * @param highlight the highlight color. 1194: * @param lightHighlight a brighter variant of the highlight color. 1195: */ 1196: public RolloverButtonBorder(Color shadow, Color darkShadow, 1197: Color highlight, Color lightHighlight) 1198: { 1199: super(shadow, darkShadow, highlight, lightHighlight); 1200: } 1201: 1202: 1203: /** 1204: * Paints the border around a rollover button. If <code>c</code> 1205: * is not an {@link javax.swing.AbstractButton} whose model 1206: * returns <code>true</code> for {@link 1207: * javax.swing.ButtonModel#isRollover}, nothing gets painted at 1208: * all. 1209: * 1210: * @param c the button whose border is to be painted. 1211: * @param g the graphics for painting. 1212: * @param x the horizontal position for painting the border. 1213: * @param y the vertical position for painting the border. 1214: * @param width the width of the available area for painting the border. 1215: * @param height the height of the available area for painting the border. 1216: */ 1217: public void paintBorder(Component c, Graphics g, 1218: int x, int y, int width, int height) 1219: { 1220: ButtonModel bmodel = null; 1221: boolean drawPressed; 1222: Color oldColor = g.getColor(); 1223: int x2, y2; 1224: 1225: if (c instanceof AbstractButton) 1226: bmodel = ((AbstractButton) c).getModel(); 1227: 1228: /* Draw nothing if c is not a rollover button. */ 1229: if ((bmodel == null) || !bmodel.isRollover()) 1230: return; 1231: 1232: /* Draw nothing if the mouse is pressed, but outside the button. */ 1233: if (bmodel.isPressed() && !bmodel.isArmed()) 1234: return; 1235: 1236: drawPressed = bmodel.isSelected() || bmodel.isPressed(); 1237: x2 = x + width - 1; 1238: y2 = y + height - 1; 1239: 1240: try 1241: { 1242: g.setColor(drawPressed ? shadow : lightHighlight); 1243: g.drawLine(x, y, x2 - 1, y); // top edge 1244: g.drawLine(x, y + 1, x, y2 - 1); // left edge 1245: 1246: g.setColor(drawPressed ? lightHighlight : shadow); 1247: g.drawLine(x, y2, x2, y2); // bottom edge 1248: g.drawLine(x2, y, x2, y2 - 1); // right edge 1249: } 1250: finally 1251: { 1252: g.setColor(oldColor); 1253: } 1254: } 1255: } 1256: 1257: 1258: /** 1259: * A border for JSplitPanes in the Basic look and feel. The divider 1260: * in the middle of the JSplitPane has its own border class, of which 1261: * an instance can be obtained with {@link #getSplitPaneDividerBorder()}. 1262: * 1263: * <p><img src="doc-files/BasicBorders.SplitPaneBorder-1.png" width="520" 1264: * height="200" alt="[A screen shot for JSplitPane.HORIZONTAL_SPLIT]" /> 1265: * 1266: * <p><img src="doc-files/BasicBorders.SplitPaneBorder-2.png" width="520" 1267: * height="200" alt="[A screen shot for JSplitPane.VERTICAL_SPLIT]" /> 1268: * 1269: * <p>In contrast to the other borders of the Basic look and feel, 1270: * this class is not serializable. While this might be unintended, 1271: * GNU Classpath follows the specification in order to be fully 1272: * compatible with the Sun reference implementation. 1273: * 1274: * <p>In the Sun JDK, the bottom edge of the divider also gets 1275: * painted if the orientation of the enclosed JSplitPane is 1276: * <code>JSplitPane.VERTICAL_SPLIT</code> (at least in versions 1277: * 1.3.1 and 1.4.1). GNU Classpath does not replicate this bug. A 1278: * report has been filed with Sun (bug ID 4885629). 1279: * 1280: * <p>Note that the bottom left pixel of the border has a different 1281: * color depending on the orientation of the enclosed JSplitPane. 1282: * Although this is visually inconsistent, Classpath replicates the 1283: * appearance of the Sun reference implementation. A bug report has 1284: * been filed with Sun (review ID 188774). 1285: * 1286: * @see #getSplitPaneBorder() 1287: * @see #getSplitPaneDividerBorder() 1288: * 1289: * @author Sascha Brawer (brawer@dandelis.ch) 1290: */ 1291: public static class SplitPaneBorder implements Border, UIResource 1292: { 1293: /** 1294: * Indicates that the top edge shall be not be painted 1295: * by {@link #paintRect}. 1296: */ 1297: private static final int SUPPRESS_TOP = 1; 1298: 1299: 1300: /** 1301: * Indicates that the left edge shall be not be painted 1302: * by {@link #paintRect}. 1303: */ 1304: private static final int SUPPRESS_LEFT = 2; 1305: 1306: 1307: /** 1308: * Indicates that the bottom edge shall be not be painted 1309: * by {@link #paintRect}. 1310: */ 1311: private static final int SUPPRESS_BOTTOM = 4; 1312: 1313: 1314: /** 1315: * Indicates that the right edge shall be not be painted 1316: * by {@link #paintRect}. 1317: */ 1318: private static final int SUPPRESS_RIGHT = 8; 1319: 1320: 1321: /** 1322: * The color for drawing the bottom and right edges of the border. 1323: */ 1324: protected Color highlight; 1325: 1326: 1327: /** 1328: * The color for drawing the top and left edges of the border. 1329: */ 1330: protected Color shadow; 1331: 1332: 1333: /** 1334: * Constructs a new border for drawing a JSplitPane in the Basic 1335: * look and feel. The divider in the middle of the JSplitPane has 1336: * its own border class, <code>SplitPaneDividerBorder</code>. 1337: * 1338: * @param shadow the shadow color. 1339: * @param highlight the highlight color. 1340: */ 1341: public SplitPaneBorder(Color highlight, Color shadow) 1342: { 1343: /* These colors usually come from the UIDefaults of the current 1344: * look and feel. Use fallback values if the colors are not 1345: * supplied. The API specification is silent about what 1346: * behavior is expected for null colors, so users should not 1347: * rely on this fallback (which is why it is not documented in 1348: * the above Javadoc). 1349: */ 1350: this.shadow = (shadow != null) ? shadow : Color.black; 1351: this.highlight = (highlight != null) ? highlight : Color.white; 1352: } 1353: 1354: 1355: /** 1356: * Paints the border around a <code>JSplitPane</code>. 1357: * 1358: * <p><img src="doc-files/BasicBorders.SplitPaneBorder-1.png" width="520" 1359: * height="200" alt="[A screen shot for JSplitPane.HORIZONTAL_SPLIT]" /> 1360: * 1361: * <p><img src="doc-files/BasicBorders.SplitPaneBorder-2.png" width="520" 1362: * height="200" alt="[A screen shot for JSplitPane.VERTICAL_SPLIT]" /> 1363: * 1364: * @param c the <code>JSplitPane</code> whose border is to be painted. 1365: * @param g the graphics for painting. 1366: * @param x the horizontal position for painting the border. 1367: * @param y the vertical position for painting the border. 1368: * @param width the width of the available area for painting the border. 1369: * @param height the height of the available area for painting the border. 1370: */ 1371: public void paintBorder(Component c, Graphics g, 1372: int x, int y, int width, int height) 1373: { 1374: JSplitPane splitPane; 1375: Component content; 1376: 1377: if (!(c instanceof JSplitPane)) 1378: return; 1379: 1380: splitPane = (JSplitPane) c; 1381: switch (splitPane.getOrientation()) 1382: { 1383: case JSplitPane.HORIZONTAL_SPLIT: 1384: if ((content = splitPane.getLeftComponent()) != null) 1385: paintRect(g, SUPPRESS_RIGHT, true, x, y, content.getBounds()); 1386: if ((content = splitPane.getRightComponent()) != null) 1387: paintRect(g, SUPPRESS_LEFT, true, x, y, content.getBounds()); 1388: break; 1389: 1390: case JSplitPane.VERTICAL_SPLIT: 1391: if ((content = splitPane.getTopComponent()) != null) 1392: paintRect(g, SUPPRESS_BOTTOM, false, x, y, content.getBounds()); 1393: if ((content = splitPane.getBottomComponent()) != null) 1394: paintRect(g, SUPPRESS_TOP, false, x, y, content.getBounds()); 1395: break; 1396: } 1397: } 1398: 1399: 1400: /** 1401: * Paints a border around a child of a <code>JSplitPane</code>, 1402: * omitting some of the edges. 1403: * 1404: * @param g the graphics for painting. 1405: * 1406: * @param suppress a bit mask indicating the set of suppressed 1407: * edges, for example <code>SUPPRESS_TOP | SUPPRESS_RIGHT</code>. 1408: * 1409: * @param x the x coordinate of the SplitPaneBorder. 1410: * 1411: * @param y the y coordinate of the SplitPaneBorder. 1412: * 1413: * @param shadeBottomLeftPixel <code>true</code> to paint the 1414: * bottom left pixel in the shadow color, 1415: * <code>false</code> for the highlight color. The Basic 1416: * look and feel uses the highlight color for the bottom 1417: * left pixel of the border of a JSplitPane whose 1418: * orientation is VERTICAL_SPLIT, and the shadow color 1419: * otherwise. While this might be a strange distinction, 1420: * Classpath tries to look identical to the reference 1421: * implementation. A bug report has been filed with Sun; 1422: * its review ID is 188774. We currently replicate the 1423: * Sun behavior. 1424: * 1425: * @param rect the bounds of the child of JSplitPane whose 1426: * border is to be painted. 1427: */ 1428: private void paintRect(Graphics g, int suppress, 1429: boolean shadeBottomLeftPixel, 1430: int x, int y, 1431: Rectangle rect) 1432: { 1433: if (rect == null) 1434: return; 1435: 1436: /* On each edge, the border exceeds the enclosed child by one 1437: * pixel. See the image "BasicBorders.SplitPaneBorder-1.png" in 1438: * the directory "doc-files". 1439: */ 1440: x += rect.x - 1; 1441: y += rect.y - 1; 1442: int right = x + rect.width + 1; 1443: int bottom = y + rect.height + 1; 1444: 1445: Color oldColor = g.getColor(); 1446: try 1447: { 1448: g.setColor(shadow); 1449: if ((suppress & SUPPRESS_TOP) == 0) 1450: g.drawLine(x, y, right, y); 1451: if ((suppress & SUPPRESS_LEFT) == 0) 1452: g.drawLine(x, y, x, bottom); 1453: else 1454: g.drawLine(x, bottom, x, bottom); // one pixel 1455: 1456: g.setColor(highlight); 1457: if ((suppress & SUPPRESS_BOTTOM) == 0) 1458: g.drawLine(x + (shadeBottomLeftPixel ? 1 : 0), bottom, right, bottom); 1459: else if (!shadeBottomLeftPixel) 1460: g.drawLine(x, bottom, x, bottom); // one pixel 1461: 1462: if ((suppress & SUPPRESS_RIGHT) == 0) 1463: g.drawLine(right, y, right, bottom); 1464: } 1465: finally 1466: { 1467: g.setColor(oldColor); 1468: } 1469: } 1470: 1471: 1472: /** 1473: * Measures the width of this border. 1474: * 1475: * @param c the component whose border is to be measured, usually 1476: * an instance of {@link javax.swing.JSplitPane}. 1477: * 1478: * @return an Insets object whose <code>left</code>, 1479: * <code>right</code>, <code>top</code> and 1480: * <code>bottom</code> fields indicate the width of the 1481: * border at the respective edge. 1482: */ 1483: public Insets getBorderInsets(Component c) 1484: { 1485: return new Insets(1, 1, 1, 1); 1486: } 1487: 1488: 1489: /** 1490: * Determines whether this border fills every pixel in its area 1491: * when painting. 1492: * 1493: * @return <code>false</code> because this border does not 1494: * paint over the pixels where the divider joins 1495: * the border. 1496: */ 1497: public boolean isBorderOpaque() 1498: { 1499: /* Strangely, the Sun implementation (tested with JDK 1.3.1 and 1500: * 1.4.1_01) seems to always return true. It could be a bug, 1501: * but without knowing the details of their implementation, it is 1502: * hard to decide. 1503: */ 1504: return false; 1505: } 1506: } 1507: 1508: 1509: /** 1510: * A border for the divider inside a JSplitPane. 1511: * 1512: * <p><img src="doc-files/BasicBorders.SplitPaneDividerBorder-1.png" 1513: * width="520" height="200" alt="[A screen shot of this border]" /> 1514: * 1515: * @author Sascha Brawer (brawer@dandelis.ch) 1516: */ 1517: private static class SplitPaneDividerBorder 1518: implements Border, UIResource, Serializable 1519: { 1520: /** 1521: * The highlight color, which is drawn on the left or top edge 1522: * depending on the orientation of the JSplitPanel. 1523: */ 1524: protected Color highlight; 1525: 1526: 1527: /** 1528: * The highlight color, which is drawn on the right or bottom edge 1529: * depending on the orientation of the JSplitPanel. 1530: */ 1531: protected Color shadow; 1532: 1533: 1534: /** 1535: * Constructs a new border for drawing the divider of a JSplitPane 1536: * in the Basic look and feel. The outer parts of the JSplitPane have 1537: * their own border class, <code>SplitPaneBorder</code>. 1538: * 1539: * @param shadow the shadow color. 1540: * @param highlight the highlight color. 1541: */ 1542: public SplitPaneDividerBorder(Color highlight, Color shadow) 1543: { 1544: this.highlight = (highlight != null) ? highlight : Color.white; 1545: this.shadow = (shadow != null) ? shadow : Color.black; 1546: } 1547: 1548: 1549: /** 1550: * Paints the border around the divider of a <code>JSplitPane</code>. 1551: * 1552: * <p><img src="doc-files/BasicBorders.SplitPaneDividerBorder-1.png" 1553: * width="520" height="200" alt="[A picture that shows which pixels 1554: * get painted in what color]" /> 1555: * 1556: * @param c the <code>JSplitPane</code> whose divider’s border 1557: * is to be painted. 1558: * @param g the graphics for painting. 1559: * @param x the horizontal position for painting the border. 1560: * @param y the vertical position for painting the border. 1561: * @param width the width of the available area for painting the border. 1562: * @param height the height of the available area for painting the border. 1563: */ 1564: public void paintBorder(Component c, Graphics g, 1565: int x, int y, int width, int height) 1566: { 1567: Color oldColor, dcol; 1568: int x2, y2; 1569: JSplitPane sp; 1570: 1571: sp = getSplitPane(c); 1572: if (sp == null) 1573: return; 1574: 1575: x2 = x + width - 1; 1576: y2 = y + height - 1; 1577: oldColor = g.getColor(); 1578: dcol = c.getBackground(); 1579: try 1580: { 1581: switch (sp.getOrientation()) 1582: { 1583: case JSplitPane.HORIZONTAL_SPLIT: 1584: g.setColor(dcol); 1585: g.drawLine(x + 1, y, x2 - 1, y); 1586: g.drawLine(x + 1, y2, x2 - 1, y2); 1587: g.setColor(sp.getLeftComponent() != null ? highlight : dcol); 1588: g.drawLine(x, y, x, y2); 1589: g.setColor(sp.getRightComponent() != null ? shadow : dcol); 1590: g.drawLine(x2, y, x2, y2); 1591: break; 1592: 1593: case JSplitPane.VERTICAL_SPLIT: 1594: g.setColor(dcol); 1595: g.drawLine(x, y + 1, x, y2 - 1); 1596: g.drawLine(x2, y + 1, x2, y2 - 1); 1597: g.setColor(sp.getTopComponent() != null ? highlight : dcol); 1598: g.drawLine(x, y, x2, y); 1599: g.setColor(sp.getBottomComponent() != null ? shadow : dcol); 1600: g.drawLine(x, y2, x2, y2); 1601: break; 1602: } 1603: } 1604: finally 1605: { 1606: g.setColor(oldColor); 1607: } 1608: } 1609: 1610: 1611: /** 1612: * Measures the width of this border. 1613: * 1614: * @param c the component whose border is to be measured, usually 1615: * an instance of {@link javax.swing.JSplitPane}. 1616: * 1617: * @return an Insets object whose <code>left</code>, 1618: * <code>right</code>, <code>top</code> and 1619: * <code>bottom</code> fields indicate the width of the 1620: * border at the respective edge. 1621: */ 1622: public Insets getBorderInsets(Component c) 1623: { 1624: return new Insets(1, 1, 1, 1); 1625: } 1626: 1627: 1628: /** 1629: * Determines whether this border fills every pixel in its area 1630: * when painting. 1631: * 1632: * @return <code>true</code> if both highlight and shadow 1633: * color are fully opaque. 1634: */ 1635: public boolean isBorderOpaque() 1636: { 1637: return (highlight.getAlpha() == 255) && (shadow.getAlpha() == 255); 1638: } 1639: 1640: 1641: /** 1642: * Determines the JSplitPane whose divider is being painted. 1643: * 1644: * @param c an instance of BasicSplitPaneDivider. 1645: * 1646: * @return a <code>JSplitPane</code>, or <code>null</code> if 1647: * <code>c</code> is not an instance of {@link 1648: * javax.swing.plaf.basic.BasicSplitPaneDivider}. 1649: */ 1650: private JSplitPane getSplitPane(Component c) 1651: { 1652: if (c instanceof BasicSplitPaneDivider) 1653: return (((BasicSplitPaneDivider) c).getBasicSplitPaneUI()) 1654: .getSplitPane(); 1655: else 1656: return null; 1657: } 1658: } 1659: 1660: 1661: /** 1662: * A border for toggle buttons in the Basic look and feel. 1663: * 1664: * <p><img src="doc-files/BasicBorders.ToggleButtonBorder-1.png" 1665: * width="270" height="135" alt="[A screen shot of this border]" /> 1666: * 1667: * <p>The Sun implementation always seems to draw exactly 1668: * the same border, irrespective of the state of the button. 1669: * This is rather surprising, but GNU Classpath emulates the 1670: * observable behavior. 1671: * 1672: * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel 1673: * 1674: * @author Sascha Brawer (brawer@dandelis.ch) 1675: */ 1676: public static class ToggleButtonBorder 1677: extends ButtonBorder 1678: { 1679: /** 1680: * Determined using the <code>serialver</code> tool 1681: * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5. 1682: */ 1683: static final long serialVersionUID = -3528666548001058394L; 1684: 1685: 1686: /** 1687: * Constructs a new border for drawing a JToggleButton in 1688: * the Basic look and feel. 1689: * 1690: * @param shadow the shadow color. 1691: * @param darkShadow a darker variant of the shadow color. 1692: * @param highlight the highlight color. 1693: * @param lightHighlight a brighter variant of the highlight color. 1694: */ 1695: public ToggleButtonBorder(Color shadow, Color darkShadow, 1696: Color highlight, Color lightHighlight) 1697: { 1698: /* The superclass ButtonBorder substitutes null arguments 1699: * with fallback colors. 1700: */ 1701: super(shadow, darkShadow, highlight, lightHighlight); 1702: } 1703: 1704: 1705: /** 1706: * Paints the ToggleButtonBorder around a given component. 1707: * 1708: * <p>The Sun implementation always seems to draw exactly 1709: * the same border, irrespective of the state of the button. 1710: * This is rather surprising, but GNU Classpath emulates the 1711: * observable behavior. 1712: * 1713: * @param c the component whose border is to be painted. 1714: * @param g the graphics for painting. 1715: * @param x the horizontal position for painting the border. 1716: * @param y the vertical position for painting the border. 1717: * @param width the width of the available area for painting the border. 1718: * @param height the height of the available area for painting the border. 1719: * 1720: * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel 1721: */ 1722: public void paintBorder(Component c, Graphics g, 1723: int x, int y, int width, int height) 1724: { 1725: /* The author of this code tried various variants for setting 1726: * the state of the enclosed JToggleButton, but it seems that 1727: * the drawn border is always identical. Weird, because this 1728: * means that the user does not see whether the JToggleButton 1729: * is selected or not. 1730: */ 1731: BasicGraphicsUtils.drawBezel(g, x, y, width, height, 1732: /* pressed */ false, 1733: /* default */ false, 1734: shadow, darkShadow, 1735: highlight, lightHighlight); 1736: } 1737: 1738: 1739: /** 1740: * Measures the width of this border. 1741: * 1742: * @param c the component whose border is to be measured. 1743: * 1744: * @return an Insets object whose <code>left</code>, 1745: * <code>right</code>, <code>top</code> and 1746: * <code>bottom</code> fields indicate the width of the 1747: * border at the respective edge. 1748: * 1749: * @see #getBorderInsets(java.awt.Component, java.awt.Insets) 1750: */ 1751: public Insets getBorderInsets(Component c) 1752: { 1753: /* There is no obvious reason for overriding this method, but we 1754: * try to have exactly the same API as the Sun reference 1755: * implementation. 1756: */ 1757: return getBorderInsets(c, null); 1758: } 1759: 1760: 1761: /** 1762: * Measures the width of this border, storing the results into a 1763: * pre-existing Insets object. 1764: * 1765: * @param insets an Insets object for holding the result values. 1766: * After invoking this method, the <code>left</code>, 1767: * <code>right</code>, <code>top</code> and 1768: * <code>bottom</code> fields indicate the width of the 1769: * border at the respective edge. 1770: * 1771: * @return the same object that was passed for <code>insets</code>. 1772: * 1773: * @see #getBorderInsets(Component) 1774: */ 1775: public Insets getBorderInsets(Component c, Insets insets) 1776: { 1777: /* The exact amount has been determined using a test program 1778: * that was run on the Apple/Sun JDK 1.3.1 on MacOS X, and the 1779: * Sun JDK 1.4.1_01 on GNU/Linux for x86. Both gave [2,2,2,2]. 1780: */ 1781: if (insets == null) 1782: return new Insets(2, 2, 2, 2); 1783: 1784: insets.left = insets.right = insets.top = insets.bottom = 2; 1785: return insets; 1786: } 1787: } 1788: }
GNU Classpath (0.20) |