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 }