Source for javax.swing.border.BevelBorder

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