1 /* EtchedBorder.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 39 package javax.swing.border; 40 41 import java.awt.Color; 42 import java.awt.Component; 43 import java.awt.Graphics; 44 import java.awt.Insets; 45 46 47 /** 48 * A border that looks like an engraving etched into the background 49 * surface, or (in its raised variant) coming out of the surface 50 * plane. Using different constructors, it is possible to either 51 * explicitly specify the border colors, or to let the colors derive 52 * from the background color of the enclosed Component. 53 * 54 * <p><img src="doc-files/EtchedBorder-1.png" width="500" height="200" 55 * alt="[An illustration of the two EtchedBorder variants]" /> 56 * 57 * @author Sascha Brawer (brawer@dandelis.ch) 58 */ 59 public class EtchedBorder 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 = 4001244046866360638L; 66 67 68 /** 69 * Indicates that the border appears as coming out of the 70 * background. 71 */ 72 public static final int RAISED = 0; 73 74 75 /** 76 * Indicates that the border appears as engraved into the 77 * background. 78 */ 79 public static final int LOWERED = 1; 80 81 82 /** 83 * The type of this EtchedBorder, which is either {@link #RAISED} 84 * or {@link #LOWERED}. 85 */ 86 protected int etchType; 87 88 89 /** 90 * The highlight color, or <code>null</code> to indicate that the 91 * color shall be derived from the background of the enclosed 92 * component. 93 */ 94 protected Color highlight; 95 96 97 /** 98 * The shadow color, or <code>null</code> to indicate that the 99 * 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 */ EtchedBorder()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 */ EtchedBorder(int etchType)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 */ EtchedBorder(Color highlight, Color shadow)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 */ EtchedBorder(int etchType, Color highlight, Color shadow)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 */ paintBorder(Component c, Graphics g, int x, int y, int width, int height)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 */ getBorderInsets(Component c)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 */ getBorderInsets(Component c, Insets insets)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 */ isBorderOpaque()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 */ getEtchType()285 public int getEtchType() 286 { 287 return etchType; 288 } 289 290 291 /** 292 * Determines the color that will be used for highlighted parts when 293 * painting the border around a given component. If a highlight 294 * color has been specified upon constructing the border, that color 295 * is returned. Otherwise, the background color of the enclosed 296 * component is brightened. 297 * 298 * @param c the component enclosed by this border. 299 * 300 * @see java.awt.Component#getBackground() 301 * @see java.awt.Color#brighter() 302 */ getHighlightColor(Component c)303 public Color getHighlightColor(Component c) 304 { 305 if (highlight != null) 306 return highlight; 307 else 308 return c.getBackground().brighter(); 309 } 310 311 /** 312 * Returns the color that will be used for highlighted parts when 313 * painting the border, or <code>null</code> if that color will be 314 * derived from the background of the enclosed Component. 315 */ getHighlightColor()316 public Color getHighlightColor() 317 { 318 return highlight; 319 } 320 321 322 /** 323 * Determines the color that will be used for shadowed parts when 324 * painting the border around a given component. If a shadow color 325 * has been specified upon constructing the border, that color is 326 * returned. Otherwise, the background color of the enclosed 327 * component is darkened. 328 * 329 * @param c the component enclosed by this border. 330 * 331 * @see java.awt.Component#getBackground() 332 * @see java.awt.Color#darker() 333 */ getShadowColor(Component c)334 public Color getShadowColor(Component c) 335 { 336 if (shadow != null) 337 return shadow; 338 else 339 return c.getBackground().darker(); 340 } 341 342 343 /** 344 * Returns the color that will be used for shadowed parts when 345 * painting the border, or <code>null</code> if that color will be 346 * derived from the background of the enclosed Component. 347 */ getShadowColor()348 public Color getShadowColor() 349 { 350 return shadow; 351 } 352 353 354 /** 355 * Paints a two-pixel etching in two colors. 356 * 357 * <pre> 358 * +++++++++++. 359 * +.........+. + = color a 360 * +. +. . = color b 361 * +. +. 362 * +++++++++++. 363 * ............</pre> 364 * 365 * @param g the graphics for painting. 366 * @param x the horizontal position for painting the border. 367 * @param y the vertical position for painting the border. 368 * @param width the width of the available area for painting the border. 369 * @param height the height of the available area for painting the border. 370 * @param a one of the two colors. 371 * @param b the second of the two colors. 372 */ paintEtchedBorder(Graphics g, int x, int y, int width, int height, Color a, Color b)373 private static void paintEtchedBorder(Graphics g, int x, int y, int width, 374 int height, Color a, Color b) 375 { 376 Color oldColor; 377 378 oldColor = g.getColor(); 379 g.translate(x, y); 380 width = width - 1; 381 height = height - 1; 382 383 try 384 { 385 // To understand this code, it might be helpful to look at the 386 // images that are included with the JavaDoc. They are located 387 // in the "doc-files" subdirectory. EtchedBorder-2.png might 388 // be especially informative. 389 g.setColor(a); 390 g.drawRect(0, 0, width - 1, height - 1); 391 392 g.setColor(b); 393 g.drawLine(1, 1, width - 2, 1); // top edge 394 g.drawLine(1, 2, 1, height - 2); // left edge 395 g.drawLine(0, height, width, height); // bottom edge 396 g.drawLine(width, 0, width, height - 1); // right edge 397 } 398 finally 399 { 400 g.translate(-x, -y); 401 g.setColor(oldColor); 402 } 403 } 404 } 405