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:    * @see #getHighlightInnerColor(java.awt.Component)
 309:    * @see java.awt.Color#brighter()
 310:    */
 311:   public Color getHighlightOuterColor(Component c)
 312:   {
 313:     if (highlightOuter != null)
 314:       return highlightOuter;
 315:     else
 316:       return getHighlightInnerColor(c).brighter();
 317:   }
 318: 
 319: 
 320:   /**
 321:    * Determines the color that will be used for the inner side of
 322:    * highlighted edges when painting the border. If a highlight color
 323:    * has been specified upon constructing the border, that color is
 324:    * returned. Otherwise, the background color of the enclosed
 325:    * component is brightened.
 326:    *
 327:    * @param c the component enclosed by this border.
 328:    *
 329:    * @see java.awt.Component#getBackground()
 330:    * @see java.awt.Color#brighter()
 331:    */
 332:   public Color getHighlightInnerColor(Component c)
 333:   {
 334:     if (highlightInner != null)
 335:       return highlightInner;
 336:     else
 337:       return c.getBackground().brighter();
 338:   }
 339: 
 340: 
 341:   /**
 342:    * Determines the color that will be used for the inner side of
 343:    * shadowed edges when painting the border. If a shadow color has
 344:    * been specified upon constructing the border, that color is
 345:    * returned. Otherwise, the background color of the enclosed
 346:    * component is darkened.
 347:    *
 348:    * @param c the component enclosed by this border.
 349:    *
 350:    * @see java.awt.Component#getBackground()
 351:    * @see java.awt.Color#darker()
 352:    */
 353:   public Color getShadowInnerColor(Component c)
 354:   {
 355:     if (shadowInner != null)
 356:       return shadowInner;
 357:     else
 358:       return c.getBackground().darker();
 359:   }
 360: 
 361: 
 362:   /**
 363:    * Determines the color that will be used for the outer side of
 364:    * shadowed edges when painting the border.  If a shadow color
 365:    * has been specified upon constructing the border, that color is
 366:    * returned. Otherwise, the inner shadow color is darkened.
 367:    *
 368:    * @param c the component enclosed by this border.
 369:    *
 370:    * @see #getShadowInnerColor(java.awt.Component)
 371:    * @see java.awt.Color#darker()
 372:    */
 373:   public Color getShadowOuterColor(Component c)
 374:   {
 375:     if (shadowOuter != null)
 376:       return shadowOuter;
 377:     else
 378:       return getShadowInnerColor(c).darker();
 379:   }
 380: 
 381: 
 382:   /**
 383:    * Returns the color that will be used for the outer side of
 384:    * highlighted edges when painting the border, or <code>null</code>
 385:    * if that color will be derived from the background of the enclosed
 386:    * Component.
 387:    */
 388:   public Color getHighlightOuterColor()
 389:   {
 390:     return highlightOuter;
 391:   }
 392: 
 393: 
 394:   /**
 395:    * Returns the color that will be used for the inner side of
 396:    * highlighted edges when painting the border, or <code>null</code>
 397:    * if that color will be derived from the background of the enclosed
 398:    * Component.
 399:    */
 400:   public Color getHighlightInnerColor()
 401:   {
 402:     return highlightInner;
 403:   }
 404: 
 405: 
 406:   /**
 407:    * Returns the color that will be used for the inner side of
 408:    * shadowed edges when painting the border, or <code>null</code> if
 409:    * that color will be derived from the background of the enclosed
 410:    * Component.
 411:    */
 412:   public Color getShadowInnerColor()
 413:   {
 414:     return shadowInner;
 415:   }
 416: 
 417: 
 418:   /**
 419:    * Returns the color that will be used for the outer 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:   public Color getShadowOuterColor()
 425:   {
 426:     return shadowOuter;
 427:   }
 428:   
 429:   
 430:   /**
 431:    * Returns the appearance of this border, which is either {@link
 432:    * #RAISED} or {@link #LOWERED}.
 433:    */
 434:   public int getBevelType()
 435:   {
 436:     return bevelType;
 437:   }
 438: 
 439: 
 440:   /**
 441:    * Determines whether this border fills every pixel in its area
 442:    * when painting.
 443:    *
 444:    * <p>If the border colors are derived from the background color of
 445:    * the enclosed component, the result is <code>true</code> because
 446:    * the derivation method always returns opaque colors. Otherwise,
 447:    * the result depends on the opacity of the individual colors.
 448:    *
 449:    * @return <code>true</code> if the border is fully opaque, or
 450:    *         <code>false</code> if some pixels of the background
 451:    *         can shine through the border.
 452:    */
 453:   public boolean isBorderOpaque()
 454:   {
 455:     /* If the colors are to be drived from the enclosed Component's
 456:      * background color, the border is guaranteed to be fully opaque
 457:      * because Color.brighten() and Color.darken() always return an
 458:      * opaque color.
 459:      */
 460:     return 
 461:       ((highlightOuter == null) || (highlightOuter.getAlpha() == 255))
 462:       && ((highlightInner == null) || (highlightInner.getAlpha() == 255))
 463:       && ((shadowInner == null) || (shadowInner.getAlpha() == 255))
 464:       && ((shadowOuter == null) ||(shadowOuter.getAlpha() == 255));
 465:   }
 466: 
 467: 
 468:   /**
 469:    * Paints a raised bevel border around a component.
 470:    *
 471:    * @param c the component whose border is to be painted.
 472:    * @param g the graphics for painting.
 473:    * @param x the horizontal position for painting the border.
 474:    * @param y the vertical position for painting the border.
 475:    * @param width the width of the available area for painting the border.
 476:    * @param height the height of the available area for painting the border.
 477:    */
 478:   protected void paintRaisedBevel(Component c, Graphics g,
 479:                                   int x, int y, int width, int height)
 480:   {
 481:     paintBevel(g, x, y, width, height,
 482:                getHighlightOuterColor(c), getHighlightInnerColor(c),
 483:                getShadowInnerColor(c), getShadowOuterColor(c));
 484:   }
 485: 
 486: 
 487:   /**
 488:    * Paints a lowered bevel border around a component.
 489:    *
 490:    * @param c the component whose border is to be painted.
 491:    * @param g the graphics for painting.
 492:    * @param x the horizontal position for painting the border.
 493:    * @param y the vertical position for painting the border.
 494:    * @param width the width of the available area for painting the border.
 495:    * @param height the height of the available area for painting the border.
 496:    */
 497:   protected void paintLoweredBevel(Component c, Graphics g,
 498:                                    int x, int y, int width, int height)
 499:   {
 500:     paintBevel(g, x, y, width, height,
 501:                getShadowInnerColor(c), getShadowOuterColor(c),
 502:                getHighlightInnerColor(c), getHighlightOuterColor(c));
 503:   }
 504: 
 505: 
 506:   /**
 507:    * Paints a two-pixel bevel in four colors.
 508:    * 
 509:    * <pre>
 510:    * ++++++++++++
 511:    * +..........#    + = color a
 512:    * +.        X#    . = color b
 513:    * +.        X#    X = color c
 514:    * +.XXXXXXXXX#    # = color d
 515:    * ############</pre>
 516:    *
 517:    * @param g the graphics for painting.
 518:    * @param x the horizontal position for painting the border.
 519:    * @param y the vertical position for painting the border.
 520:    * @param width the width of the available area for painting the border.
 521:    * @param height the height of the available area for painting the border.
 522:    * @param a the color for the outer side of the top and left edges.
 523:    * @param b the color for the inner side of the top and left edges.
 524:    * @param c the color for the inner side of the bottom and right edges.
 525:    * @param d the color for the outer side of the bottom and right edges.
 526:    */
 527:   private static void paintBevel(Graphics g,
 528:                                  int x, int y, int width, int height,
 529:                                  Color a, Color b, Color c, Color d)
 530:   {
 531:     Color oldColor;
 532: 
 533:     oldColor = g.getColor();
 534:     g.translate(x, y);
 535:     width = width - 1;
 536:     height = height - 1;
 537: 
 538:     try
 539:     {
 540:       /* To understand this code, it might be helpful to look at the
 541:        * images that are included with the JavaDoc. They are located
 542:        * in the "doc-files" subdirectory.
 543:        */
 544:       g.setColor(a);
 545:       g.drawLine(0, 0, width, 0);                       // a, horizontal
 546:       g.drawLine(0, 1, 0, height);                      // a, vertical
 547: 
 548:       g.setColor(b);
 549:       g.drawLine(1, 1, width - 1, 1);                   // b, horizontal
 550:       g.drawLine(1, 2, 1, height - 1);                  // b, vertical
 551: 
 552:       g.setColor(c);
 553:       g.drawLine(2, height - 1, width - 1, height - 1); // c, horizontal
 554:       g.drawLine(width - 1, 2, width - 1, height - 2);  // c, vertical
 555: 
 556:       g.setColor(d);
 557:       g.drawLine(1, height, width, height);             // d, horizontal
 558:       g.drawLine(width, 1, width, height - 1);          // d, vertical
 559:     }
 560:     finally
 561:     {
 562:       g.translate(-x, -y);
 563:       g.setColor(oldColor);
 564:     }
 565:   }
 566: }