Frames | No Frames |
1: /* BevelBorder.java -- 2: Copyright (C) 2003 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: package javax.swing.border; 39: 40: import java.awt.Color; 41: import java.awt.Component; 42: import java.awt.Graphics; 43: import java.awt.Insets; 44: 45: 46: /** 47: * A rectangular, two pixel thick border that causes the enclosed area 48: * to appear as if it was raising out of or lowered into the screen. Some 49: * LookAndFeels use this kind of border for rectangular buttons. 50: * 51: * <p>A BevelBorder has a highlight and a shadow color. In the raised 52: * variant, the highlight color is used for the top and left edges, 53: * and the shadow color is used for the bottom and right edge. For an 54: * image, see the documentation of the individual constructors. 55: * 56: * @author Sascha Brawer (brawer@dandelis.ch) 57: */ 58: public class BevelBorder extends AbstractBorder 59: { 60: /** 61: * Determined using the <code>serialver</code> tool 62: * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5. 63: */ 64: static final long serialVersionUID = -1034942243356299676L; 65: 66: 67: /** 68: * Indicates that the BevelBorder looks like if the enclosed area was 69: * raising out of the screen. 70: */ 71: public static final int RAISED = 0; 72: 73: 74: /** 75: * Indicates that the BevelBorder looks like if the enclosed area was 76: * pressed into the screen. 77: */ 78: public static final int LOWERED = 1; 79: 80: 81: /** 82: * The type of this BevelBorder, which is either {@link #RAISED} 83: * or {@link #LOWERED}. 84: */ 85: protected int bevelType; 86: 87: 88: /** 89: * The outer highlight color, or <code>null</code> to indicate that 90: * the color shall be derived from the background of the component 91: * whose border is being painted. 92: */ 93: protected Color highlightOuter; 94: 95: 96: /** 97: * The inner highlight color, or <code>null</code> to indicate that 98: * the color shall be derived from the background of the component 99: * whose border is being painted. 100: */ 101: protected Color highlightInner; 102: 103: 104: /** 105: * The outer shadow color, or <code>null</code> to indicate that the 106: * color shall be derived from the background of the component whose 107: * border is being painted. 108: */ 109: protected Color shadowOuter; 110: 111: 112: /** 113: * The inner shadow color, or <code>null</code> to indicate that the 114: * color shall be derived from the background of the component whose 115: * border is being painted. 116: */ 117: protected Color shadowInner; 118: 119: 120: /** 121: * Constructs a BevelBorder whose colors will be derived from the 122: * background of the enclosed component. The background color is 123: * retrieved each time the border is painted, so a BevelBorder 124: * constructed by this method will automatically reflect a change 125: * to the component’s background color. 126: * 127: * <p><img src="doc-files/BevelBorder-1.png" width="500" height="150" 128: * alt="[An illustration showing raised and lowered BevelBorders]" /> 129: * 130: * @param bevelType the desired appearance of the border. The value 131: * must be either {@link #RAISED} or {@link #LOWERED}. 132: * 133: * @throws IllegalArgumentException if <code>bevelType</code> has 134: * an unsupported value. 135: */ 136: public BevelBorder(int bevelType) 137: { 138: if ((bevelType != RAISED) && (bevelType != LOWERED)) 139: throw new IllegalArgumentException(); 140: 141: this.bevelType = bevelType; 142: } 143: 144: 145: /** 146: * Constructs a BevelBorder given its appearance type and two colors 147: * for its highlight and shadow. 148: * 149: * <p><img src="doc-files/BevelBorder-2.png" width="500" height="150" 150: * alt="[An illustration showing BevelBorders that were constructed 151: * with this method]" /> 152: * 153: * @param bevelType the desired appearance of the border. The value 154: * must be either {@link #RAISED} or {@link #LOWERED}. 155: * 156: * @param highlight the color that will be used for the inner 157: * side of the highlighted edges (top and left if 158: * if <code>bevelType</code> is {@link #RAISED}; bottom 159: * and right otherwise). The color for the outer side 160: * is a brightened version of this color. 161: * 162: * @param shadow the color that will be used for the outer 163: * side of the shadowed edges (bottom and right 164: * if <code>bevelType</code> is {@link #RAISED}; top 165: * and left otherwise). The color for the inner side 166: * is a brightened version of this color. 167: * 168: * @throws IllegalArgumentException if <code>bevelType</code> has 169: * an unsupported value. 170: * 171: * @throws NullPointerException if <code>highlight</code> or 172: * <code>shadow</code> is <code>null</code>. 173: * 174: * @see java.awt.Color#brighter() 175: */ 176: public BevelBorder(int bevelType, Color highlight, Color shadow) 177: { 178: this(bevelType, 179: /* highlightOuter */ highlight.brighter(), 180: /* highlightInner */ highlight, 181: /* shadowOuter */ shadow, 182: /* shadowInner */ shadow.brighter()); 183: } 184: 185: 186: /** 187: * Constructs a BevelBorder given its appearance type and all 188: * colors. 189: * 190: * <p><img src="doc-files/BevelBorder-3.png" width="500" height="150" 191: * alt="[An illustration showing BevelBorders that were constructed 192: * with this method]" /> 193: * 194: * @param bevelType the desired appearance of the border. The value 195: * must be either {@link #RAISED} or {@link #LOWERED}. 196: * 197: * @param highlightOuter the color that will be used for the outer 198: * side of the highlighted edges (top and left if 199: * <code>bevelType</code> is {@link #RAISED}; bottom and 200: * right otherwise). 201: * 202: * @param highlightInner the color that will be used for the inner 203: * side of the highlighted edges. 204: * 205: * @param shadowOuter the color that will be used for the outer 206: * side of the shadowed edges (bottom and right 207: * if <code>bevelType</code> is {@link #RAISED}; top 208: * and left otherwise). 209: * 210: * @param shadowInner the color that will be used for the inner 211: * side of the shadowed edges. 212: * 213: * @throws IllegalArgumentException if <code>bevelType</code> has 214: * an unsupported value. 215: * 216: * @throws NullPointerException if one of the passed colors 217: * is <code>null</code>. 218: */ 219: public BevelBorder(int bevelType, 220: Color highlightOuter, Color highlightInner, 221: Color shadowOuter, Color shadowInner) 222: { 223: this(bevelType); // checks the validity of bevelType 224: 225: if ((highlightOuter == null) || (highlightInner == null) 226: || (shadowOuter == null) || (shadowInner == null)) 227: throw new NullPointerException(); 228: 229: this.highlightOuter = highlightOuter; 230: this.highlightInner = highlightInner; 231: this.shadowOuter = shadowOuter; 232: this.shadowInner = shadowInner; 233: } 234: 235: 236: /** 237: * Paints the border for a given component. 238: * 239: * @param c the component whose border is to be painted. 240: * @param g the graphics for painting. 241: * @param x the horizontal position for painting the border. 242: * @param y the vertical position for painting the border. 243: * @param width the width of the available area for painting the border. 244: * @param height the height of the available area for painting the border. 245: */ 246: public void paintBorder(Component c, Graphics g, 247: int x, int y, int width, int height) 248: { 249: switch (bevelType) 250: { 251: case RAISED: 252: paintRaisedBevel(c, g, x, y, width, height); 253: break; 254: 255: case LOWERED: 256: paintLoweredBevel(c, g, x, y, width, height); 257: break; 258: } 259: } 260: 261: 262: /** 263: * Measures the width of this border. 264: * 265: * @param c the component whose border is to be measured. 266: * 267: * @return an Insets object whose <code>left</code>, <code>right</code>, 268: * <code>top</code> and <code>bottom</code> fields indicate the 269: * width of the border at the respective edge. 270: * 271: * @see #getBorderInsets(java.awt.Component, java.awt.Insets) 272: */ 273: public Insets getBorderInsets(Component c) 274: { 275: return new Insets(2, 2, 2, 2); 276: } 277: 278: 279: /** 280: * Measures the width of this border, storing the results into a 281: * pre-existing Insets object. 282: * 283: * @param insets an Insets object for holding the result values. 284: * After invoking this method, the <code>left</code>, 285: * <code>right</code>, <code>top</code> and 286: * <code>bottom</code> fields indicate the width of the 287: * border at the respective edge. 288: * 289: * @return the same object that was passed for <code>insets</code>. 290: * 291: * @see #getBorderInsets(Component) 292: */ 293: public Insets getBorderInsets(Component c, Insets insets) 294: { 295: insets.left = insets.right = insets.top = insets.bottom = 2; 296: return insets; 297: } 298: 299: 300: /** 301: * Determines the color that will be used for the outer side of 302: * highlighted edges when painting the border. If a highlight color 303: * has been specified upon constructing the border, that color is 304: * returned. Otherwise, the inner highlight color is brightened. 305: * 306: * @param c the component enclosed by this border. 307: * 308: * @return The color. 309: * 310: * @see #getHighlightInnerColor(java.awt.Component) 311: * @see java.awt.Color#brighter() 312: */ 313: public Color getHighlightOuterColor(Component c) 314: { 315: if (highlightOuter != null) 316: return highlightOuter; 317: else 318: return getHighlightInnerColor(c).brighter(); 319: } 320: 321: 322: /** 323: * Determines the color that will be used for the inner side of 324: * highlighted edges when painting the border. If a highlight color 325: * has been specified upon constructing the border, that color is 326: * returned. Otherwise, the background color of the enclosed 327: * component is brightened. 328: * 329: * @param c the component enclosed by this border. 330: * 331: * @return The color. 332: * 333: * @see java.awt.Component#getBackground() 334: * @see java.awt.Color#brighter() 335: */ 336: public Color getHighlightInnerColor(Component c) 337: { 338: if (highlightInner != null) 339: return highlightInner; 340: else 341: return c.getBackground().brighter(); 342: } 343: 344: 345: /** 346: * Determines the color that will be used for the inner side of 347: * shadowed edges when painting the border. If a shadow color has 348: * been specified upon constructing the border, that color is 349: * returned. Otherwise, the background color of the enclosed 350: * component is darkened. 351: * 352: * @param c the component enclosed by this border. 353: * 354: * @return The color. 355: * 356: * @see java.awt.Component#getBackground() 357: * @see java.awt.Color#darker() 358: */ 359: public Color getShadowInnerColor(Component c) 360: { 361: if (shadowInner != null) 362: return shadowInner; 363: else 364: return c.getBackground().darker(); 365: } 366: 367: 368: /** 369: * Determines the color that will be used for the outer side of 370: * shadowed edges when painting the border. If a shadow color 371: * has been specified upon constructing the border, that color is 372: * returned. Otherwise, the inner shadow color is darkened. 373: * 374: * @param c the component enclosed by this border. 375: * 376: * @return The color. 377: * 378: * @see #getShadowInnerColor(java.awt.Component) 379: * @see java.awt.Color#darker() 380: */ 381: public Color getShadowOuterColor(Component c) 382: { 383: if (shadowOuter != null) 384: return shadowOuter; 385: else 386: return getShadowInnerColor(c).darker(); 387: } 388: 389: 390: /** 391: * Returns the color that will be used for the outer side of 392: * highlighted edges when painting the border, or <code>null</code> 393: * if that color will be derived from the background of the enclosed 394: * Component. 395: * 396: * @return The color (possibly <code>null</code>). 397: */ 398: public Color getHighlightOuterColor() 399: { 400: return highlightOuter; 401: } 402: 403: 404: /** 405: * Returns the color that will be used for the inner side of 406: * highlighted edges when painting the border, or <code>null</code> 407: * if that color will be derived from the background of the enclosed 408: * Component. 409: * 410: * @return The color (possibly <code>null</code>). 411: */ 412: public Color getHighlightInnerColor() 413: { 414: return highlightInner; 415: } 416: 417: 418: /** 419: * Returns the color that will be used for the inner side of 420: * shadowed edges when painting the border, or <code>null</code> if 421: * that color will be derived from the background of the enclosed 422: * Component. 423: * 424: * @return The color (possibly <code>null</code>). 425: */ 426: public Color getShadowInnerColor() 427: { 428: return shadowInner; 429: } 430: 431: 432: /** 433: * Returns the color that will be used for the outer side of 434: * shadowed edges when painting the border, or <code>null</code> if 435: * that color will be derived from the background of the enclosed 436: * Component. 437: * 438: * @return The color (possibly <code>null</code>). 439: */ 440: public Color getShadowOuterColor() 441: { 442: return shadowOuter; 443: } 444: 445: 446: /** 447: * Returns the appearance of this border, which is either {@link 448: * #RAISED} or {@link #LOWERED}. 449: * 450: * @return The bevel type ({@link #RAISED} or {@link #LOWERED}). 451: */ 452: public int getBevelType() 453: { 454: return bevelType; 455: } 456: 457: 458: /** 459: * Determines whether this border fills every pixel in its area 460: * when painting. 461: * 462: * <p>If the border colors are derived from the background color of 463: * the enclosed component, the result is <code>true</code> because 464: * the derivation method always returns opaque colors. Otherwise, 465: * the result depends on the opacity of the individual colors. 466: * 467: * @return <code>true</code> if the border is fully opaque, or 468: * <code>false</code> if some pixels of the background 469: * can shine through the border. 470: */ 471: public boolean isBorderOpaque() 472: { 473: /* If the colors are to be drived from the enclosed Component's 474: * background color, the border is guaranteed to be fully opaque 475: * because Color.brighten() and Color.darken() always return an 476: * opaque color. 477: */ 478: return 479: ((highlightOuter == null) || (highlightOuter.getAlpha() == 255)) 480: && ((highlightInner == null) || (highlightInner.getAlpha() == 255)) 481: && ((shadowInner == null) || (shadowInner.getAlpha() == 255)) 482: && ((shadowOuter == null) || (shadowOuter.getAlpha() == 255)); 483: } 484: 485: 486: /** 487: * Paints a raised bevel border around a component. 488: * 489: * @param c the component whose border is to be painted. 490: * @param g the graphics for painting. 491: * @param x the horizontal position for painting the border. 492: * @param y the vertical position for painting the border. 493: * @param width the width of the available area for painting the border. 494: * @param height the height of the available area for painting the border. 495: */ 496: protected void paintRaisedBevel(Component c, Graphics g, 497: int x, int y, int width, int height) 498: { 499: paintBevel(g, x, y, width, height, 500: getHighlightOuterColor(c), getHighlightInnerColor(c), 501: getShadowInnerColor(c), getShadowOuterColor(c)); 502: } 503: 504: 505: /** 506: * Paints a lowered bevel border around a component. 507: * 508: * @param c the component whose border is to be painted. 509: * @param g the graphics for painting. 510: * @param x the horizontal position for painting the border. 511: * @param y the vertical position for painting the border. 512: * @param width the width of the available area for painting the border. 513: * @param height the height of the available area for painting the border. 514: */ 515: protected void paintLoweredBevel(Component c, Graphics g, 516: int x, int y, int width, int height) 517: { 518: paintBevel(g, x, y, width, height, 519: getShadowInnerColor(c), getShadowOuterColor(c), 520: getHighlightInnerColor(c), getHighlightOuterColor(c)); 521: } 522: 523: 524: /** 525: * Paints a two-pixel bevel in four colors. 526: * 527: * <pre> 528: * ++++++++++++ 529: * +..........# + = color a 530: * +. X# . = color b 531: * +. X# X = color c 532: * +.XXXXXXXXX# # = color d 533: * ############</pre> 534: * 535: * @param g the graphics for painting. 536: * @param x the horizontal position for painting the border. 537: * @param y the vertical position for painting the border. 538: * @param width the width of the available area for painting the border. 539: * @param height the height of the available area for painting the border. 540: * @param a the color for the outer side of the top and left edges. 541: * @param b the color for the inner side of the top and left edges. 542: * @param c the color for the inner side of the bottom and right edges. 543: * @param d the color for the outer side of the bottom and right edges. 544: */ 545: private static void paintBevel(Graphics g, 546: int x, int y, int width, int height, 547: Color a, Color b, Color c, Color d) 548: { 549: Color oldColor; 550: 551: oldColor = g.getColor(); 552: g.translate(x, y); 553: width = width - 1; 554: height = height - 1; 555: 556: try 557: { 558: /* To understand this code, it might be helpful to look at the 559: * images that are included with the JavaDoc. They are located 560: * in the "doc-files" subdirectory. 561: */ 562: g.setColor(a); 563: g.drawLine(0, 0, width, 0); // a, horizontal 564: g.drawLine(0, 1, 0, height); // a, vertical 565: 566: g.setColor(b); 567: g.drawLine(1, 1, width - 1, 1); // b, horizontal 568: g.drawLine(1, 2, 1, height - 1); // b, vertical 569: 570: g.setColor(c); 571: g.drawLine(2, height - 1, width - 1, height - 1); // c, horizontal 572: g.drawLine(width - 1, 2, width - 1, height - 2); // c, vertical 573: 574: g.setColor(d); 575: g.drawLine(1, height, width, height); // d, horizontal 576: g.drawLine(width, 1, width, height - 1); // d, vertical 577: } 578: finally 579: { 580: g.translate(-x, -y); 581: g.setColor(oldColor); 582: } 583: } 584: }