001 /* BevelBorder.java -- 002 Copyright (C) 2003 Free Software Foundation, Inc. 003 004 This file is part of GNU Classpath. 005 006 GNU Classpath is free software; you can redistribute it and/or modify 007 it under the terms of the GNU General Public License as published by 008 the Free Software Foundation; either version 2, or (at your option) 009 any later version. 010 011 GNU Classpath is distributed in the hope that it will be useful, but 012 WITHOUT ANY WARRANTY; without even the implied warranty of 013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 General Public License for more details. 015 016 You should have received a copy of the GNU General Public License 017 along with GNU Classpath; see the file COPYING. If not, write to the 018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 019 02110-1301 USA. 020 021 Linking this library statically or dynamically with other modules is 022 making a combined work based on this library. Thus, the terms and 023 conditions of the GNU General Public License cover the whole 024 combination. 025 026 As a special exception, the copyright holders of this library give you 027 permission to link this library with independent modules to produce an 028 executable, regardless of the license terms of these independent 029 modules, and to copy and distribute the resulting executable under 030 terms of your choice, provided that you also meet, for each linked 031 independent module, the terms and conditions of the license of that 032 module. An independent module is a module which is not derived from 033 or based on this library. If you modify this library, you may extend 034 this exception to your version of the library, but you are not 035 obligated to do so. If you do not wish to do so, delete this 036 exception statement from your version. */ 037 038 package javax.swing.border; 039 040 import java.awt.Color; 041 import java.awt.Component; 042 import java.awt.Graphics; 043 import java.awt.Insets; 044 045 046 /** 047 * A rectangular, two pixel thick border that causes the enclosed area 048 * to appear as if it was raising out of or lowered into the screen. Some 049 * LookAndFeels use this kind of border for rectangular buttons. 050 * 051 * <p>A BevelBorder has a highlight and a shadow color. In the raised 052 * variant, the highlight color is used for the top and left edges, 053 * and the shadow color is used for the bottom and right edge. For an 054 * image, see the documentation of the individual constructors. 055 * 056 * @author Sascha Brawer (brawer@dandelis.ch) 057 */ 058 public class BevelBorder extends AbstractBorder 059 { 060 /** 061 * Determined using the <code>serialver</code> tool 062 * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5. 063 */ 064 static final long serialVersionUID = -1034942243356299676L; 065 066 067 /** 068 * Indicates that the BevelBorder looks like if the enclosed area was 069 * raising out of the screen. 070 */ 071 public static final int RAISED = 0; 072 073 074 /** 075 * Indicates that the BevelBorder looks like if the enclosed area was 076 * pressed into the screen. 077 */ 078 public static final int LOWERED = 1; 079 080 081 /** 082 * The type of this BevelBorder, which is either {@link #RAISED} 083 * or {@link #LOWERED}. 084 */ 085 protected int bevelType; 086 087 088 /** 089 * The outer highlight color, or <code>null</code> to indicate that 090 * the color shall be derived from the background of the component 091 * whose border is being painted. 092 */ 093 protected Color highlightOuter; 094 095 096 /** 097 * The inner highlight color, or <code>null</code> to indicate that 098 * the color shall be derived from the background of the component 099 * 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 } 585