GNU Classpath (0.17) | ||
Frames | No Frames |
1: /* MatteBorder.java -- 2: Copyright (C) 2003, 2004 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: import javax.swing.Icon; 47: 48: /** 49: * A border that is filled with either a solid color or with repeated 50: * icon tiles. 51: * 52: * <p><img src="doc-files/MatteBorder-1.png" width="500" height="150" 53: * alt="[Two MatteBorders]" /> 54: * 55: * @author Sascha Brawer (brawer@dandelis.ch) 56: */ 57: public class MatteBorder 58: extends EmptyBorder 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 = 4422248989617298224L; 65: 66: 67: /** 68: * The color that is used for filling the border, or 69: * <code>null</code> if the border is filled with repetitions of a 70: * tile icon. 71: * 72: * @see #tileIcon 73: */ 74: protected Color color; 75: 76: 77: /** 78: * The icon is used for filling the border with a tile, or 79: * <code>null</code> if the border is filled with a solid 80: * color. 81: * 82: * @see #color 83: */ 84: protected Icon tileIcon; 85: 86: 87: /** 88: * Constructs a MatteBorder given the width on each side 89: * and a fill color. 90: * 91: * <p><img src="doc-files/MatteBorder-2.png" width="500" height="150" 92: * alt="[A picture of a MatteBorder made by this constructor]" /> 93: * 94: * @param top the width of the border at its top edge. 95: * @param left the width of the border at its left edge. 96: * @param bottom the width of the border at its bottom edge. 97: * @param right the width of the border at its right edge. 98: * @param matteColor the color for filling the border. 99: */ 100: public MatteBorder(int top, int left, int bottom, int right, 101: Color matteColor) 102: { 103: super(top, left, bottom, right); 104: 105: if (matteColor == null) 106: throw new IllegalArgumentException(); 107: 108: this.color = matteColor; 109: } 110: 111: 112: /** 113: * Constructs a MatteBorder given its insets and fill color. 114: * 115: * <p><img src="doc-files/MatteBorder-3.png" width="500" height="150" 116: * alt="[A picture of a MatteBorder made by this constructor]" /> 117: * 118: * @param borderInsets an Insets object whose <code>top</code>, 119: * <code>left</code>, <code>bottom</code> and <code>right</code> 120: * fields indicate the with of the border at the respective 121: * edge. 122: * 123: * @param matteColor the color for filling the border. 124: */ 125: public MatteBorder(Insets borderInsets, Color matteColor) 126: { 127: this(borderInsets.top, borderInsets.left, 128: borderInsets.bottom, borderInsets.right, 129: matteColor); 130: } 131: 132: 133: /** 134: * Constructs a MatteBorder given the width on each side 135: * and an icon for tiling the border area. 136: * 137: * <p><img src="doc-files/MatteBorder-4.png" width="500" height="150" 138: * alt="[A picture of a MatteBorder made by this constructor]" /> 139: * 140: * @param top the width of the border at its top edge. 141: * @param left the width of the border at its left edge. 142: * @param bottom the width of the border at its bottom edge. 143: * @param right the width of the border at its right edge. 144: * @param tileIcon an icon for tiling the border area. 145: */ 146: public MatteBorder(int top, int left, int bottom, int right, 147: Icon tileIcon) 148: { 149: super(top, left, bottom, right); 150: 151: if (tileIcon == null) 152: throw new IllegalArgumentException(); 153: 154: this.tileIcon = tileIcon; 155: } 156: 157: 158: /** 159: * Constructs a MatteBorder given its insets and an icon 160: * for tiling the border area. 161: * 162: * <p><img src="doc-files/MatteBorder-5.png" width="500" height="150" 163: * alt="[A picture of a MatteBorder made by this constructor]" /> 164: * 165: * @param borderInsets an Insets object whose <code>top</code>, 166: * <code>left</code>, <code>bottom</code> and <code>right</code> 167: * fields indicate the with of the border at the respective 168: * edge. 169: * 170: * @param tileIcon an icon for tiling the border area. 171: */ 172: public MatteBorder(Insets borderInsets, Icon tileIcon) 173: { 174: this(borderInsets.top, borderInsets.left, 175: borderInsets.bottom, borderInsets.right, 176: tileIcon); 177: } 178: 179: 180: /** 181: * Constructs a MatteBorder given an icon for tiling the 182: * border area. The icon width is used for the border insets 183: * at the left and right edge, the icon height for the top and 184: * bottom edge. 185: * 186: * <p><img src="doc-files/MatteBorder-6.png" width="379" height="150" 187: * alt="[A picture of a MatteBorder made by this constructor]" /> 188: * 189: * @param tileIcon an icon for tiling the border area. 190: */ 191: public MatteBorder(Icon tileIcon) 192: { 193: this(-1, -1, -1, -1, tileIcon); 194: } 195: 196: 197: /** 198: * Paints the border for a given component. 199: * 200: * @param c the component whose border is to be painted. 201: * @param g the graphics for painting. 202: * @param x the horizontal position for painting the border. 203: * @param y the vertical position for painting the border. 204: * @param width the width of the available area for painting the border. 205: * @param height the height of the available area for painting the border. 206: */ 207: public void paintBorder(Component c, Graphics g, 208: int x, int y, int width, int height) 209: { 210: Insets i = getBorderInsets(); 211: paintEdge(c, g, x, y, width, i.top, 0, 0); // top edge 212: paintEdge(c, g, x, y + height - i.bottom, // bottom edge 213: width, i.bottom, 214: 0, height - i.bottom); 215: paintEdge(c, g, x, y + i.top, // left edge 216: i.left, height - i.top, 217: 0, i.top); 218: paintEdge(c, g, x + width - i.right, y + i.top, // right edge 219: i.right, height - i.bottom, 220: width - i.right, i.top); 221: } 222: 223: 224: /** 225: * Measures the width of this border. 226: * 227: * @param c the component whose border is to be measured. 228: * 229: * @return an Insets object whose <code>left</code>, <code>right</code>, 230: * <code>top</code> and <code>bottom</code> fields indicate the 231: * width of the border at the respective edge. 232: * 233: * @see #getBorderInsets(java.awt.Component, java.awt.Insets) 234: */ 235: public Insets getBorderInsets(Component c) 236: { 237: /* There is no obvious reason for overriding this method, but we 238: * try to have exactly the same API as the Sun reference 239: * implementation. 240: */ 241: return this.getBorderInsets(c, null); 242: } 243: 244: 245: /** 246: * Measures the width of this border, storing the results into a 247: * pre-existing Insets object. 248: * 249: * @param insets an Insets object for holding the result values. 250: * After invoking this method, the <code>left</code>, 251: * <code>right</code>, <code>top</code> and 252: * <code>bottom</code> fields indicate the width of the 253: * border at the respective edge. 254: * 255: * @return the same object that was passed for <code>insets</code>. 256: * 257: * @see #getBorderInsets() 258: */ 259: public Insets getBorderInsets(Component c, Insets insets) 260: { 261: if (insets == null) 262: insets = new Insets(0, 0, 0, 0); 263: 264: if ((tileIcon != null) 265: && (top < 0) && (left < 0) 266: && (right < 0) && (bottom < 0)) 267: { 268: insets.left = insets.right = tileIcon.getIconWidth(); 269: insets.top = insets.bottom = tileIcon.getIconHeight(); 270: return insets; 271: } 272: 273: /* Copy top, left, bottom and right into the respective 274: * field of insets. 275: */ 276: return super.getBorderInsets(c, insets); 277: } 278: 279: 280: /** 281: * Measures the width of this border. 282: * 283: * @return an Insets object whose <code>left</code>, <code>right</code>, 284: * <code>top</code> and <code>bottom</code> fields indicate the 285: * width of the border at the respective edge. 286: * 287: * @see #getBorderInsets(java.awt.Component, java.awt.Insets) 288: */ 289: public Insets getBorderInsets() 290: { 291: /* The inherited implementation of EmptyBorder.isBorderOpaque() 292: * would do the same. It is not clear why this is overriden in the 293: * Sun implementation, at least not from just reading the JavaDoc. 294: */ 295: return this.getBorderInsets(null, null); 296: } 297: 298: 299: /** 300: * Returns the color that is used for filling the border, or 301: * <code>null</code> if the border is filled with repetitions of a 302: * tile icon. 303: */ 304: public Color getMatteColor() 305: { 306: return color; 307: } 308: 309: 310: /** 311: * Returns the icon is used for tiling the border, or 312: * <code>null</code> if the border is filled with a color instead of 313: * an icon. 314: */ 315: public Icon getTileIcon() 316: { 317: return tileIcon; 318: } 319: 320: 321: /** 322: * Determines whether this border fills every pixel in its area 323: * when painting. 324: * 325: * @return <code>true</code> if the border is filled with an 326: * opaque color; <code>false</code> if it is filled with 327: * a semi-transparent color or with an icon. 328: */ 329: public boolean isBorderOpaque() 330: { 331: return (color != null) && (color.getAlpha() == 255); 332: } 333: 334: 335: /** 336: * Paints a rectangular area of the border. This private helper 337: * method is called once for each of the border edges 338: * by {@link #paintBorder}. 339: * 340: * @param c the component whose border is being painted. 341: * @param g the graphics for painting. 342: * @param x the horizontal position of the rectangular area. 343: * @param y the vertical position of the rectangular area. 344: * @param width the width of the rectangular area. 345: * @param height the height of the rectangular area. 346: * @param dx the x displacement for repeating the tile. 347: * @param dy the y displacement for repeating the tile. 348: */ 349: private void paintEdge(Component c, Graphics g, 350: int x, int y, int width, int height, 351: int dx, int dy) 352: { 353: Color oldColor; 354: int iconWidth, iconHeight; 355: Graphics clipped; 356: 357: if ((width <= 0) || (height <= 0)) 358: return; 359: 360: /* Paint a colored rectangle if desired. */ 361: if (color != null) 362: { 363: oldColor = g.getColor(); 364: try 365: { 366: g.setColor(color); 367: g.fillRect(x, y, width, height); 368: } 369: finally 370: { 371: g.setColor(oldColor); 372: } 373: return; 374: } 375: 376: /* Determine the width and height of the icon. Some icons return 377: * -1 if it is an image whose dimensions have not yet been 378: * retrieved. There is not much we can do about this, but we 379: * should at least avoid entering the paint loop below 380: * with negative increments. 381: */ 382: iconWidth = tileIcon.getIconWidth(); 383: iconHeight = tileIcon.getIconHeight(); 384: if ((iconWidth <= 0) || (iconHeight <= 0)) 385: return; 386: 387: dx = dx % iconWidth; 388: dy = dy % iconHeight; 389: 390: clipped = g.create(); 391: try 392: { 393: clipped.setClip(x, y, width, height); 394: for (int ty = y - dy; ty < y + height; ty += iconHeight) 395: for (int tx = x - dx; tx < x + width; tx += iconWidth) 396: tileIcon.paintIcon(c, clipped, tx, ty); 397: } 398: finally 399: { 400: clipped.dispose(); 401: } 402: } 403: }
GNU Classpath (0.17) |