001/* EtchedBorder.java -- 002 Copyright (C) 2003 Free Software Foundation, Inc. 003 004This file is part of GNU Classpath. 005 006GNU Classpath is free software; you can redistribute it and/or modify 007it under the terms of the GNU General Public License as published by 008the Free Software Foundation; either version 2, or (at your option) 009any later version. 010 011GNU Classpath is distributed in the hope that it will be useful, but 012WITHOUT ANY WARRANTY; without even the implied warranty of 013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014General Public License for more details. 015 016You should have received a copy of the GNU General Public License 017along with GNU Classpath; see the file COPYING. If not, write to the 018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 01902110-1301 USA. 020 021Linking this library statically or dynamically with other modules is 022making a combined work based on this library. Thus, the terms and 023conditions of the GNU General Public License cover the whole 024combination. 025 026As a special exception, the copyright holders of this library give you 027permission to link this library with independent modules to produce an 028executable, regardless of the license terms of these independent 029modules, and to copy and distribute the resulting executable under 030terms of your choice, provided that you also meet, for each linked 031independent module, the terms and conditions of the license of that 032module. An independent module is a module which is not derived from 033or based on this library. If you modify this library, you may extend 034this exception to your version of the library, but you are not 035obligated to do so. If you do not wish to do so, delete this 036exception statement from your version. */ 037 038 039package javax.swing.border; 040 041import java.awt.Color; 042import java.awt.Component; 043import java.awt.Graphics; 044import java.awt.Insets; 045 046 047/** 048 * A border that looks like an engraving etched into the background 049 * surface, or (in its raised variant) coming out of the surface 050 * plane. Using different constructors, it is possible to either 051 * explicitly specify the border colors, or to let the colors derive 052 * from the background color of the enclosed Component. 053 * 054 * <p><img src="doc-files/EtchedBorder-1.png" width="500" height="200" 055 * alt="[An illustration of the two EtchedBorder variants]" /> 056 * 057 * @author Sascha Brawer (brawer@dandelis.ch) 058 */ 059public class EtchedBorder extends AbstractBorder 060{ 061 /** 062 * Determined using the <code>serialver</code> tool 063 * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5. 064 */ 065 static final long serialVersionUID = 4001244046866360638L; 066 067 068 /** 069 * Indicates that the border appears as coming out of the 070 * background. 071 */ 072 public static final int RAISED = 0; 073 074 075 /** 076 * Indicates that the border appears as engraved into the 077 * background. 078 */ 079 public static final int LOWERED = 1; 080 081 082 /** 083 * The type of this EtchedBorder, which is either {@link #RAISED} 084 * or {@link #LOWERED}. 085 */ 086 protected int etchType; 087 088 089 /** 090 * The highlight color, or <code>null</code> to indicate that the 091 * color shall be derived from the background of the enclosed 092 * component. 093 */ 094 protected Color highlight; 095 096 097 /** 098 * The shadow color, or <code>null</code> to indicate that the 099 * color shall be derived from the background of the enclosed 100 * component. 101 */ 102 protected Color shadow; 103 104 105 /** 106 * Constructs a lowered EtchedBorder. The colors will be derived 107 * from the background color of the enclosed Component when the 108 * border gets painted. 109 */ 110 public EtchedBorder() 111 { 112 this(LOWERED); 113 } 114 115 116 /** 117 * Constructs an EtchedBorder with the specified appearance. The 118 * colors will be derived from the background color of the enclosed 119 * Component when the border gets painted. 120 * 121 * <p><img src="doc-files/EtchedBorder-1.png" width="500" height="200" 122 * alt="[An illustration of the two EtchedBorder variants]" /> 123 * 124 * @param etchType the desired appearance of the border. The value 125 * must be either {@link #RAISED} or {@link #LOWERED}. 126 * 127 * @throws IllegalArgumentException if <code>etchType</code> has 128 * an unsupported value. 129 */ 130 public EtchedBorder(int etchType) 131 { 132 if ((etchType != RAISED) && (etchType != LOWERED)) 133 throw new IllegalArgumentException(); 134 135 this.etchType = etchType; 136 137 /* The highlight and shadow fields already have a null value 138 * when the constructor gets called, so there is no need to 139 * assign a value here. 140 */ 141 } 142 143 144 /** 145 * Constructs a lowered EtchedBorder, explicitly selecting the 146 * colors that will be used for highlight and shadow. 147 * 148 * @param highlight the color that will be used for painting 149 * the highlight part of the border. 150 * 151 * @param shadow the color that will be used for painting 152 * the shadow part of the border. 153 * 154 * @see #EtchedBorder(int, Color, Color) 155 */ 156 public EtchedBorder(Color highlight, Color shadow) 157 { 158 this(LOWERED, highlight, shadow); 159 } 160 161 162 /** 163 * Constructs an EtchedBorder with the specified appearance, 164 * explicitly selecting the colors that will be used for 165 * highlight and shadow. 166 * 167 * <p><img src="doc-files/EtchedBorder-2.png" width="500" height="200" 168 * alt="[An illustration that shows which pixels get painted 169 * in what color]" /> 170 * 171 * @param etchType the desired appearance of the border. The value 172 * must be either {@link #RAISED} or {@link #LOWERED}. 173 * 174 * @param highlight the color that will be used for painting 175 * the highlight part of the border. 176 * 177 * @param shadow the color that will be used for painting 178 * the shadow part of the border. 179 * 180 * @throws IllegalArgumentException if <code>etchType</code> has 181 * an unsupported value. 182 */ 183 public EtchedBorder(int etchType, Color highlight, Color shadow) 184 { 185 this(etchType); // Checks the validity of the value. 186 this.highlight = highlight; 187 this.shadow = shadow; 188 } 189 190 191 /** 192 * Paints the border for a given component. 193 * 194 * @param c the component whose border is to be painted. 195 * @param g the graphics for painting. 196 * @param x the horizontal position for painting the border. 197 * @param y the vertical position for painting the border. 198 * @param width the width of the available area for painting the border. 199 * @param height the height of the available area for painting the border. 200 */ 201 public void paintBorder(Component c, Graphics g, int x, int y, int width, 202 int height) 203 { 204 switch (etchType) 205 { 206 case RAISED: 207 paintEtchedBorder(g, x, y, width, height, 208 getHighlightColor(c), getShadowColor(c)); 209 break; 210 211 case LOWERED: 212 paintEtchedBorder(g, x, y, width, height, 213 getShadowColor(c), getHighlightColor(c)); 214 break; 215 } 216 } 217 218 219 /** 220 * Measures the width of this border. 221 * 222 * @param c the component whose border is to be measured. 223 * 224 * @return an Insets object whose <code>left</code>, <code>right</code>, 225 * <code>top</code> and <code>bottom</code> fields indicate the 226 * width of the border at the respective edge. 227 * 228 * @see #getBorderInsets(java.awt.Component, java.awt.Insets) 229 */ 230 public Insets getBorderInsets(Component c) 231 { 232 return new Insets(2, 2, 2, 2); 233 } 234 235 236 /** 237 * Measures the width of this border, storing the results into a 238 * pre-existing Insets object. 239 * 240 * @param insets an Insets object for holding the result values. 241 * After invoking this method, the <code>left</code>, 242 * <code>right</code>, <code>top</code> and 243 * <code>bottom</code> fields indicate the width of the 244 * border at the respective edge. 245 * 246 * @return the same object that was passed for <code>insets</code>. 247 * 248 * @see #getBorderInsets(Component) 249 */ 250 public Insets getBorderInsets(Component c, Insets insets) 251 { 252 insets.left = insets.right = insets.top = insets.bottom = 2; 253 return insets; 254 } 255 256 257 /** 258 * Determines whether this border fills every pixel in its area 259 * when painting. 260 * 261 * <p>If the border colors are derived from the background color of 262 * the enclosed component, the result is <code>true</code> because 263 * the derivation method always returns opaque colors. Otherwise, 264 * the result depends on the opacity of the individual colors. 265 * 266 * @return <code>true</code> if the border is fully opaque, or 267 * <code>false</code> if some pixels of the background 268 * can shine through the border. 269 */ 270 public boolean isBorderOpaque() 271 { 272 // If the colors are to be derived from the enclosed Component's 273 // background color, the border is guaranteed to be fully opaque 274 // because Color.brighten() and Color.darken() always return an 275 // opaque color. 276 return 277 ((highlight == null) || (highlight.getAlpha() == 255)) 278 && ((shadow == null) || (shadow.getAlpha() == 255)); 279 } 280 281 /** 282 * Returns the appearance of this EtchedBorder, which is either 283 * {@link #RAISED} or {@link #LOWERED}. 284 * 285 * @return The type ({@link #RAISED} or {@link #LOWERED}). 286 */ 287 public int getEtchType() 288 { 289 return etchType; 290 } 291 292 293 /** 294 * Determines the color that will be used for highlighted parts when 295 * painting the border around a given component. If a highlight 296 * color has been specified upon constructing the border, that color 297 * is returned. Otherwise, the background color of the enclosed 298 * component is brightened. 299 * 300 * @param c the component enclosed by this border. 301 * 302 * @return The color. 303 * 304 * @see java.awt.Component#getBackground() 305 * @see java.awt.Color#brighter() 306 */ 307 public Color getHighlightColor(Component c) 308 { 309 if (highlight != null) 310 return highlight; 311 else 312 return c.getBackground().brighter(); 313 } 314 315 /** 316 * Returns the color that will be used for highlighted parts when 317 * painting the border, or <code>null</code> if that color will be 318 * derived from the background of the enclosed Component. 319 * 320 * @return The highlight color (possibly <code>null</code>). 321 */ 322 public Color getHighlightColor() 323 { 324 return highlight; 325 } 326 327 328 /** 329 * Determines the color that will be used for shadowed parts when 330 * painting the border around a given component. If a shadow color 331 * has been specified upon constructing the border, that color is 332 * returned. Otherwise, the background color of the enclosed 333 * component is darkened. 334 * 335 * @param c the component enclosed by this border. 336 * 337 * @return The shadow color. 338 * 339 * @see java.awt.Component#getBackground() 340 * @see java.awt.Color#darker() 341 */ 342 public Color getShadowColor(Component c) 343 { 344 if (shadow != null) 345 return shadow; 346 else 347 return c.getBackground().darker(); 348 } 349 350 351 /** 352 * Returns the color that will be used for shadowed parts when 353 * painting the border, or <code>null</code> if that color will be 354 * derived from the background of the enclosed Component. 355 * 356 * @return The shadow color (possibly <code>null</code>). 357 */ 358 public Color getShadowColor() 359 { 360 return shadow; 361 } 362 363 364 /** 365 * Paints a two-pixel etching in two colors. 366 * 367 * <pre> 368 * +++++++++++. 369 * +.........+. + = color a 370 * +. +. . = color b 371 * +. +. 372 * +++++++++++. 373 * ............</pre> 374 * 375 * @param g the graphics for painting. 376 * @param x the horizontal position for painting the border. 377 * @param y the vertical position for painting the border. 378 * @param width the width of the available area for painting the border. 379 * @param height the height of the available area for painting the border. 380 * @param a one of the two colors. 381 * @param b the second of the two colors. 382 */ 383 private static void paintEtchedBorder(Graphics g, int x, int y, int width, 384 int height, Color a, Color b) 385 { 386 Color oldColor; 387 388 oldColor = g.getColor(); 389 g.translate(x, y); 390 width = width - 1; 391 height = height - 1; 392 393 try 394 { 395 // To understand this code, it might be helpful to look at the 396 // images that are included with the JavaDoc. They are located 397 // in the "doc-files" subdirectory. EtchedBorder-2.png might 398 // be especially informative. 399 g.setColor(a); 400 g.drawRect(0, 0, width - 1, height - 1); 401 402 g.setColor(b); 403 g.drawLine(1, 1, width - 2, 1); // top edge 404 g.drawLine(1, 2, 1, height - 2); // left edge 405 g.drawLine(0, height, width, height); // bottom edge 406 g.drawLine(width, 0, width, height - 1); // right edge 407 } 408 finally 409 { 410 g.translate(-x, -y); 411 g.setColor(oldColor); 412 } 413 } 414}