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 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&#x2019;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: }