001 /*
002 * $Id: RectanglePainter.java 3288 2009-03-10 14:36:28Z 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 java.awt.BasicStroke;
025 import java.awt.Color;
026 import java.awt.Graphics2D;
027 import java.awt.Insets;
028 import java.awt.Paint;
029 import java.awt.Rectangle;
030 import java.awt.Shape;
031 import java.awt.geom.Rectangle2D;
032 import java.awt.geom.RectangularShape;
033 import java.awt.geom.RoundRectangle2D;
034
035 import org.jdesktop.swingx.graphics.GraphicsUtilities;
036 import org.jdesktop.swingx.painter.effects.AreaEffect;
037
038
039
040 /**
041 * A painter which paints square and rounded rectangles
042 * @author joshua.marinacci@sun.com
043 */
044
045 public class RectanglePainter<T> extends AbstractAreaPainter<T> {
046 private boolean rounded = false;
047 //private Insets insets = new Insets(0,0,0,0);
048 private int roundWidth = 20;
049 private int roundHeight = 20;
050 private int width = -1;
051 private int height = -1;
052 //private double strokeWidth = 1;
053
054 /** Creates a new instance of RectanglePainter */
055 public RectanglePainter() {
056 this(0,0,0,0, 0,0, false, Color.RED, 1f, Color.BLACK);
057 }
058
059 public RectanglePainter(Color fillPaint, Color borderPaint) {
060 this(0,0,0,0,0,0,false,fillPaint,1f,borderPaint);
061 }
062
063 public RectanglePainter(Paint fillPaint, Paint borderPaint, float borderWidth, RectanglePainter.Style style) {
064 this();
065 setFillPaint(fillPaint);
066 setBorderPaint(borderPaint);
067 setBorderWidth(borderWidth);
068 setStyle(style);
069 }
070 public RectanglePainter(int top, int left, int bottom, int right) {
071 this(top, left, bottom, right, 0, 0, false, Color.RED, 1f, Color.BLACK);
072 }
073 public RectanglePainter(int top, int left, int bottom, int right,
074 int roundWidth, int roundHeight) {
075 this(top,left,bottom,right,roundWidth, roundHeight, true, Color.RED, 1f, Color.BLACK);
076 }
077
078 public RectanglePainter(int width, int height, int cornerRadius, Paint fillPaint) {
079 this(new Insets(0,0,0,0), width,height,
080 cornerRadius, cornerRadius, true,
081 fillPaint, 1f, Color.BLACK);
082 }
083
084 public RectanglePainter(Insets insets,
085 int width, int height,
086 int roundWidth, int roundHeight, boolean rounded, Paint fillPaint,
087 float strokeWidth, Paint borderPaint) {
088 this.width = width;
089 this.height = height;
090 setFillHorizontal(false);
091 setFillVertical(false);
092 setInsets(insets);
093 this.roundWidth = roundWidth;
094 this.roundHeight = roundHeight;
095 this.rounded = rounded;
096 this.setFillPaint(fillPaint);
097 this.setBorderWidth(strokeWidth);
098 this.setBorderPaint(borderPaint);
099 }
100
101 public RectanglePainter(int top, int left, int bottom, int right,
102 int roundWidth, int roundHeight, boolean rounded, Paint fillPaint,
103 float strokeWidth, Paint borderPaint) {
104 this.setInsets(new Insets(top,left,bottom,right));
105 setFillVertical(true);
106 setFillHorizontal(true);
107 this.roundWidth = roundWidth;
108 this.roundHeight = roundHeight;
109 this.rounded = rounded;
110 this.setFillPaint(fillPaint);
111 this.setBorderWidth(strokeWidth);
112 this.setBorderPaint(borderPaint);
113 }
114
115
116
117
118 /**
119 * Indicates if the rectangle is rounded
120 * @return if the rectangle is rounded
121 */
122 public boolean isRounded() {
123 return rounded;
124 }
125
126 /**
127 * sets if the rectangle should be rounded
128 * @param rounded if the rectangle should be rounded
129 */
130 public void setRounded(boolean rounded) {
131 boolean oldRounded = isRounded();
132 this.rounded = rounded;
133 setDirty(true);
134 firePropertyChange("rounded",oldRounded,rounded);
135 }
136
137 /**
138 * gets the round width of the rectangle
139 * @return the current round width
140 */
141 public int getRoundWidth() {
142 return roundWidth;
143 }
144
145 /**
146 * sets the round width of the rectangle
147 * @param roundWidth a new round width
148 */
149 public void setRoundWidth(int roundWidth) {
150 int oldRoundWidth = getRoundWidth();
151 this.roundWidth = roundWidth;
152 setDirty(true);
153 firePropertyChange("roundWidth",oldRoundWidth,roundWidth);
154 }
155
156 /**
157 * gets the round height of the rectangle
158 * @return the current round height
159 */
160 public int getRoundHeight() {
161 return roundHeight;
162 }
163
164 /**
165 * sets the round height of the rectangle
166 * @param roundHeight a new round height
167 */
168 public void setRoundHeight(int roundHeight) {
169 int oldRoundHeight = getRoundHeight();
170 this.roundHeight = roundHeight;
171 setDirty(true);
172 firePropertyChange("roundHeight",oldRoundHeight,roundHeight);
173 }
174
175
176 /* ======== drawing code ============ */
177 protected RectangularShape calculateShape(int width, int height) {
178 Insets insets = getInsets();
179 int x = insets.left;
180 int y = insets.top;
181
182 // use the position calcs from the super class
183 Rectangle bounds = calculateLayout(this.width, this.height, width, height);
184 if(this.width != -1 && !isFillHorizontal()) {
185 width = this.width;
186 x = bounds.x;
187 }
188 if(this.height != -1 && !isFillVertical()) {
189 height = this.height;
190 y = bounds.y;
191 }
192
193 if(isFillHorizontal()) {
194 width = width - insets.left - insets.right;
195 }
196 if(isFillVertical()) {
197 height = height - insets.top - insets.bottom;
198 }
199
200
201 RectangularShape shape = new Rectangle2D.Double(x, y, width, height);
202 if(rounded) {
203 shape = new RoundRectangle2D.Double(x, y, width, height, roundWidth, roundHeight);
204 }
205 return shape;
206 }
207
208
209
210 protected void doPaint(Graphics2D g, T component, int width, int height) {
211 RectangularShape shape = calculateShape(width, height);
212 switch (getStyle()) {
213 case BOTH:
214 drawBackground(g,shape,width,height);
215 drawBorder(g,shape,width,height);
216 break;
217 case FILLED:
218 drawBackground(g,shape,width,height);
219 break;
220 case OUTLINE:
221 drawBorder(g,shape,width,height);
222 break;
223 case NONE:
224 break;
225 }
226
227 // background
228 // border
229 // leave the clip to support masking other painters
230 GraphicsUtilities.mergeClip(g,shape);
231 /*
232 Area area = new Area(g.getClip());
233 area.intersect(new Area(shape));//new Rectangle(0,0,width,height)));
234 g.setClip(area);*/
235 //g.setClip(shape);
236 }
237
238 private void drawBorder(Graphics2D g, RectangularShape shape, int width, int height) {
239 Paint p = getBorderPaint();
240 if(isPaintStretched()) {
241 p = calculateSnappedPaint(p, width, height);
242 }
243
244 g.setPaint(p);
245
246 g.setStroke(new BasicStroke(getBorderWidth()));
247 // shrink the border by 1 px
248 if(shape instanceof Rectangle2D) {
249 g.draw(new Rectangle2D.Double(shape.getX(), shape.getY(),
250 shape.getWidth()-1, shape.getHeight()-1));
251 } else if(shape instanceof RoundRectangle2D) {
252 g.draw(new RoundRectangle2D.Double(shape.getX(), shape.getY(),
253 shape.getWidth()-1, shape.getHeight()-1,
254 ((RoundRectangle2D)shape).getArcWidth(),
255 ((RoundRectangle2D)shape).getArcHeight()));
256
257 } else {
258 g.draw(shape);
259 }
260
261
262 }
263
264 private void drawBackground(Graphics2D g, Shape shape, int width, int height) {
265 Paint p = getFillPaint();
266 if(isPaintStretched()) {
267 p = calculateSnappedPaint(p, width, height);
268 }
269
270 g.setPaint(p);
271
272 g.fill(shape);
273 if(getAreaEffects() != null) {
274 for(AreaEffect ef : getAreaEffects()) {
275 ef.apply(g, shape, width, height);
276 }
277 }
278 }
279
280 public Shape provideShape(Graphics2D g, T comp, int width, int height) {
281 return calculateShape(width,height);
282 }
283
284 }
285