001 /* 002 * $Id: AbstractAreaPainter.java 2476 2007-11-25 15:52:59Z kschaefe $ 003 * 004 * Copyright 2006 Sun Microsystems, Inc., 4150 Network Circle, 005 * Santa Clara, California 95054, U.S.A. All rights reserved. 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this library; if not, write to the Free Software 019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 020 */ 021 022 package org.jdesktop.swingx.painter; 023 024 import org.jdesktop.swingx.painter.effects.AreaEffect; 025 026 import java.awt.*; 027 import org.jdesktop.swingx.util.PaintUtils; 028 029 030 /** 031 * The abstract base class for all painters that fill a vector path area. This 032 * includes Shapes, Rectangles, Text, and the MattePainter 033 * which fills in the entire background of a component. The defining 034 * feature of AbstractAreaPainter subclasses 035 * is that they implement the provideShape() method which returns 036 * the outline shape of the area that this 037 * painter will fill. Subclasses must implement the provideShape() method. 038 * 039 * The AbstractAreaPainter provides support for the following common painting properties 040 * 041 * <ul> 042 * <li>fillPaint</li> 043 * <li>paintStretched</li> 044 * <li>borderPaint</li> 045 * <li>borderWidth</li> 046 * <li>style</li> 047 * </ul> 048 * 049 * The AbstractAreaPainter also provides support for path effects like dropshadows and glows. 050 * 051 * @author joshua@marinacci.org 052 */ 053 public abstract class AbstractAreaPainter<T> extends AbstractLayoutPainter<T> { 054 055 /** 056 * Different available fill styles. BOTH indicates that both the outline, 057 * and the fill should be painted. This is the default. FILLED indicates that 058 * the shape should be filled, but no outline painted. OUTLINE specifies that 059 * the shape should be outlined, but not filled. NONE indicates that neither 060 * the fill area nor the outline should be painted. 061 */ 062 public enum Style {BOTH, FILLED, OUTLINE, NONE} 063 064 // controls if the paint should be stretched to fill the available area 065 private boolean stretchPaint; 066 067 private AreaEffect[] areaEffects = new AreaEffect[0]; 068 069 070 private Style style = Style.BOTH; 071 /** 072 * The stroke width to use when painting. If null, the default Stroke for 073 * the Graphics2D is used 074 */ 075 private float borderWidth; 076 077 /** 078 * The paint to use when filling the shape 079 */ 080 private Paint fillPaint; 081 082 /** 083 * The Paint to use when stroking the shape (drawing the outline). If null, 084 * then the component foreground color is used 085 */ 086 private Paint borderPaint; 087 088 /** 089 * Creates a new instance of AbstractAreaPainter 090 */ 091 public AbstractAreaPainter() { 092 fillPaint = Color.RED; 093 } 094 /** 095 * Creates a new instance of AbstractAreaPainter 096 * @param paint the default paint to fill this area painter with 097 */ 098 public AbstractAreaPainter(Paint paint) { 099 this.fillPaint = paint; 100 } 101 102 103 /** 104 * Gets the current fill paint. This is the Paint object that will be used to fill the path area. 105 * @return Gets the Paint being used. May be null 106 */ 107 public Paint getFillPaint() { 108 return fillPaint; 109 } 110 111 /** 112 * Sets the Paint to use. This is the Paint object that will be used to fill the path area. If null, nothing is painted 113 * @param p the Paint to use 114 */ 115 public void setFillPaint(Paint p) { 116 Paint old = getFillPaint(); 117 this.fillPaint = p; 118 setDirty(true); 119 firePropertyChange("paint", old, getFillPaint()); 120 } 121 122 /** 123 * Indicates if the paint will be snapped. This means that the paint will be scaled and aligned along the 4 axis of (horizontal, vertical, 124 * and both diagonals). Snapping allows the paint to be stretched across the component when it is drawn, even if the component is 125 * resized. This setting is only used for gradient paints. It will have no effect on Color or Texture paints. 126 * @return the current value of the snapPaint property 127 */ 128 public boolean isPaintStretched() { 129 return stretchPaint; 130 } 131 132 133 /** 134 * Specifies whether this Painter should attempt to resize the Paint to fit the area being painted. 135 * For example, if true, then a gradient specified as (0, 0), (1, 0) would stretch horizontally such that 136 * the beginning of the gradient is on the left edge of the painted region, and the end of the gradient 137 * is at the right edge of the painted region. 138 * Specifically, if true, the resizePaint method will be called to perform the actual resizing of the Paint 139 * @param paintStretched true if the paint should be stretched, false otherwise. 140 */ 141 public void setPaintStretched(boolean paintStretched) { 142 boolean old = this.isPaintStretched(); 143 this.stretchPaint = paintStretched; 144 setDirty(true); 145 firePropertyChange("snapPaint",old,this.stretchPaint); 146 } 147 148 /** 149 * The Paint to use for stroking the shape (painting the outline). 150 * Can be a Color, GradientPaint, TexturePaint, or any other kind of Paint. 151 * If null, the component foreground is used. 152 * 153 * @param p the Paint to use for stroking the shape. May be null. 154 */ 155 public void setBorderPaint(Paint p) { 156 Paint old = getBorderPaint(); 157 this.borderPaint = p; 158 setDirty(true); 159 firePropertyChange("borderPaint", old, getBorderPaint()); 160 } 161 162 /** 163 * Gets the current Paint to use for stroking the shape (painting the outline). 164 * Can be a Color, GradientPaint, TexturePaint, or any other kind of Paint. 165 * If null, the component foreground is used. 166 * @return the Paint used when stroking the shape. May be null 167 */ 168 public Paint getBorderPaint() { 169 return borderPaint; 170 } 171 172 /** 173 * The shape can be filled or simply stroked (outlined), or both or none. By default, 174 * the shape is both filled and stroked. This property specifies the strategy to 175 * use. 176 * @param s the Style to use. If null, Style.BOTH is used 177 */ 178 public void setStyle(Style s) { 179 Style old = getStyle(); 180 this.style = s == null ? Style.BOTH : s; 181 setDirty(true); 182 firePropertyChange("style", old, getStyle()); 183 } 184 185 /** 186 * Gets the current Style. The shape can be filled or simply stroked (outlined), or both or none. By default, 187 * the shape is both filled and stroked. This property specifies the strategy to 188 * use. 189 * @return the Style used 190 */ 191 public Style getStyle() { 192 return style; 193 } 194 195 /** 196 * Sets the border width to use for painting. If null, then the default Graphics2D 197 * stroke will be used. The stroke will be centered on the actual shape outline. 198 * @param s the Stroke to fillPaint with 199 */ 200 public void setBorderWidth(float s) { 201 float old = getBorderWidth(); 202 this.borderWidth = s; 203 setDirty(true); 204 firePropertyChange("strokeWidth", old, getBorderWidth()); 205 } 206 207 /** 208 * Gets the current border width. 209 * @return the Stroke to use for painting 210 */ 211 public float getBorderWidth() { 212 return borderWidth; 213 } 214 215 216 217 /** 218 * Resizes the given Paint. By default, only Gradients, LinearGradients, and RadialGradients are resized 219 * in this method. If you have special resizing needs, override this method. This 220 * method is mainly used to make gradient paints resize with the component this 221 * painter is attached to. This method is internal to the painter api and should 222 * not be called elsewhere. It is used by the paintStretched property and 223 * painter subclasses. In the future it may be made public for use by other classes. 224 * If this happens it should probably be turned into a static utility method. 225 */ 226 Paint calculateSnappedPaint(Paint p, int width, int height) { 227 return PaintUtils.resizeGradient(p, width, height); 228 } 229 230 231 232 /** 233 * Returns the outline shape of this painter. Subclasses must implement this method. This shape 234 * will be used for filling, stroking, and clipping. 235 * @return the outline shape of this painter 236 * @param g graphics 237 * @param comp The Object this painter will be painted on. 238 * @param width the width to paint 239 * @param height the height to paint 240 */ 241 protected abstract Shape provideShape(Graphics2D g, T comp, int width, int height); 242 243 /** 244 * Sets the path effects to be drawn on this painter. Set this to null in order to remove all installed effects. 245 * @param areaEffects the effects to apply to this painter 246 */ 247 public void setAreaEffects(AreaEffect... areaEffects) { 248 AreaEffect[] old = getAreaEffects(); 249 this.areaEffects = new AreaEffect[areaEffects == null ? 0 : areaEffects.length]; 250 if (areaEffects != null) { 251 System.arraycopy(areaEffects, 0, this.areaEffects, 0, this.areaEffects.length); 252 } 253 setDirty(true); 254 firePropertyChange("areaEffects", old, getAreaEffects()); 255 } 256 257 /** 258 * Gets the current set of path effects applied to this painter. Returned array is guarantied to be not null. 259 * @return the effects applied to this path painter 260 */ 261 public AreaEffect[] getAreaEffects() { 262 AreaEffect[] results = new AreaEffect[areaEffects.length]; 263 System.arraycopy(areaEffects, 0, results, 0, results.length); 264 return results; 265 } 266 267 }