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 }