001 /*
002 * $Id: PinstripePainter.java 3288 2009-03-10 14:36:28Z kschaefe $
003 *
004 * Copyright 2004 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.Graphics2D;
026 import java.awt.Paint;
027 import java.awt.Rectangle;
028 import java.awt.Shape;
029 import java.awt.geom.Area;
030 import java.awt.geom.Line2D;
031
032 import javax.swing.JComponent;
033
034 /**
035 * <p>A fun Painter that paints pinstripes. You can specify the Paint to paint
036 * those pinstripes in (could even be a texture paint!), the angle at which
037 * to paint the pinstripes, and the spacing between stripes.</p>
038 *
039 * <p>The default PinstripePainter configuration will paint the pinstripes
040 * using the foreground color of the component (the default behavior if a
041 * Paint is not specified) at a 45 degree angle with 8 pixels between stripes</p>
042 *
043 * <p>Here is a custom code snippet that paints Color.GRAY pinstripes at a 135
044 * degree angle:
045 * <pre><code>
046 * PinstripePainter p = new PinstripePainter();
047 * p.setAngle(135);
048 * p.setPaint(Color.GRAY);
049 * </code></pre>
050 *
051 * @author rbair
052 */
053 public class PinstripePainter extends AbstractPainter<Object> {
054 /**
055 * The angle in degrees to paint the pinstripes at. The default
056 * value is 45. The value will be between 0 and 360 inclusive. The
057 * setAngle method will ensure this.
058 */
059 private double angle = 45;
060 /**
061 * The spacing between pinstripes
062 */
063 private double spacing = 8;
064
065 /**
066 * The stroke width of the pinstripes
067 */
068 private double stripeWidth = 1;
069
070 /**
071 * The Paint to use when drawing the pinstripes
072 */
073 private Paint paint;
074
075 /**
076 * Create a new PinstripePainter. By default the angle with be 45 degrees,
077 * the spacing will be 8 pixels, and the color will be the Component foreground
078 * color.
079 */
080 public PinstripePainter() {
081 }
082
083 /**
084 * Create a new PinstripePainter using an angle of 45, 8 pixel spacing,
085 * and the given Paint.
086 *
087 * @param paint the paint used when drawing the stripes
088 */
089 public PinstripePainter(Paint paint) {
090 this(paint, 45);
091 }
092
093 /**
094 * Create a new PinstripePainter using the given angle, 8 pixel spacing,
095 * and the given Paint
096 *
097 * @param paint the paint used when drawing the stripes
098 * @param angle the angle, in degrees, in which to paint the pinstripes
099 */
100 public PinstripePainter(Paint paint, double angle) {
101 this.paint = paint;
102 this.angle = angle;
103 }
104
105 /**
106 * Create a new PinstripePainter using the given angle, 8 pixel spacing,
107 * and the foreground color of the Component
108 *
109 * @param angle the angle, in degrees, in which to paint the pinstripes
110 */
111 public PinstripePainter(double angle) {
112 this.angle = angle;
113 }
114
115 /**
116 * Create a new PinstripePainter with the specified paint, angle, stripe width, and stripe spacing.
117 * @param paint
118 * @param angle
119 * @param stripeWidth
120 * @param spacing
121 */
122 public PinstripePainter(Paint paint, double angle, double stripeWidth, double spacing) {
123 this.paint = paint;
124 this.angle = angle;
125 this.stripeWidth = stripeWidth;
126 this.spacing = spacing;
127 }
128
129 /**
130 * Set the paint to use for drawing the pinstripes
131 *
132 * @param p the Paint to use. May be a Color.
133 */
134 public void setPaint(Paint p) {
135 Paint old = getPaint();
136 this.paint = p;
137 firePropertyChange("paint", old, getPaint());
138 }
139
140 /**
141 * Get the current paint used for drawing the pinstripes
142 * @return the Paint to use to draw the pinstripes
143 */
144 public Paint getPaint() {
145 return paint;
146 }
147
148 /**
149 * Sets the angle, in degrees, at which to paint the pinstripes. If the
150 * given angle is < 0 or > 360, it will be appropriately constrained. For
151 * example, if a value of 365 is given, it will result in 5 degrees. The
152 * conversion is not perfect, but "a man on a galloping horse won't be
153 * able to tell the difference".
154 *
155 * @param angle the Angle in degrees at which to paint the pinstripes
156 */
157 public void setAngle(double angle) {
158 if (angle > 360) {
159 angle = angle % 360;
160 }
161
162 if (angle < 0) {
163 angle = 360 - ((angle * -1) % 360);
164 }
165
166 double old = getAngle();
167 this.angle = angle;
168 firePropertyChange("angle", old, getAngle());
169 }
170
171 /**
172 * Gets the current angle of the pinstripes
173 * @return the angle, in degrees, at which the pinstripes are painted
174 */
175 public double getAngle() {
176 return angle;
177 }
178
179 /**
180 * Sets the spacing between pinstripes
181 *
182 * @param spacing spacing between pinstripes
183 */
184 public void setSpacing(double spacing) {
185 double old = getSpacing();
186 this.spacing = spacing;
187 firePropertyChange("spacing", old, getSpacing());
188 }
189
190 /**
191 * Get the current spacing between the stripes
192 * @return the spacing between pinstripes
193 */
194 public double getSpacing() {
195 return spacing;
196 }
197
198 /**
199 * {@inheritDoc}
200 */
201 protected void doPaint(Graphics2D g, Object component, int width, int height) {
202 //draws pinstripes at the angle specified in this class
203 //and at the given distance apart
204 Shape oldClip = g.getClip();
205 Area area = new Area(new Rectangle(0,0,width,height));
206 if(oldClip != null) {
207 area = new Area(oldClip);
208 }
209 area.intersect(new Area(new Rectangle(0,0,width,height)));
210 g.setClip(area);
211 //g.setClip(oldClip.intersection(new Rectangle(0,0,width,height)));
212 Paint p = getPaint();
213 if (p == null) {
214 if(component instanceof JComponent) {
215 g.setColor(((JComponent)component).getForeground());
216 }
217 } else {
218 g.setPaint(p);
219 }
220
221 g.setStroke(new BasicStroke((float)getStripeWidth()));
222
223 double hypLength = Math.sqrt((width * width) +
224 (height * height));
225
226 double radians = Math.toRadians(getAngle());
227 g.rotate(radians);
228
229 double spacing = getSpacing();
230 spacing += getStripeWidth();
231 int numLines = (int)(hypLength / spacing);
232
233 for (int i=0; i<numLines; i++) {
234 double x = i * spacing;
235 Line2D line = new Line2D.Double(x, -hypLength, x, hypLength);
236 g.draw(line);
237 }
238 g.setClip(oldClip);
239 }
240
241 /**
242 * Gets the current width of the pinstripes
243 * @return the current pinstripe width
244 */
245 public double getStripeWidth() {
246 return stripeWidth;
247 }
248
249 /**
250 * Set the width of the pinstripes
251 * @param stripeWidth a new width for the pinstripes
252 */
253 public void setStripeWidth(double stripeWidth) {
254 double oldSripeWidth = getStripeWidth();
255 this.stripeWidth = stripeWidth;
256 firePropertyChange("stripeWidth",new Double(oldSripeWidth),new Double(stripeWidth));
257 }
258
259 }