001 /*
002 * $Id: CheckerboardPainter.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.Color;
025 import java.awt.Graphics2D;
026 import java.awt.Paint;
027 import java.awt.Rectangle;
028 import java.awt.TexturePaint;
029 import java.awt.image.BufferedImage;
030 import javax.swing.JComponent;
031
032 /**
033 * <p>A Painter implementation that paints a checkerboard pattern. The light
034 * and dark colors (Paint instances) are configurable, as are the size of the
035 * squares (squareSize).</p>
036 *
037 * <p>To configure a checkerboard pattern that used a gradient for the dark
038 * tiles and Color.WHITE for the light tiles, you could:
039 * <pre><code>
040 * GradientPaint gp = new GradientPaint(
041 * new Point2D.Double(0, 0),
042 * Color.BLACK,
043 * new Point2D.Double(0, 32),
044 * Color.GRAY);
045 * CheckerboardPainter p = new CheckerboardPainter();
046 * p.setDarkPaint(gp);
047 * p.setLightPaint(Color.WHITE);
048 * p.setSquareSize(32);
049 * panel.seBackgroundPainter(p);
050 * </code></pre></p>
051 *
052 * <p>Note that in this example, the "32" in the GradientPaint matches the "32"
053 * set for the squareSize. This is necessary because GradientPaints don't
054 * readjust themselves for the size of the square. They are fixed and immutable
055 * at the time of creation.</p>
056 *
057 * @author rbair
058 */
059 public class CheckerboardPainter extends AbstractPainter<Object> {
060 private transient Paint checkerPaint;
061
062 private Paint darkPaint = new Color(204, 204, 204);
063 private Paint lightPaint = Color.WHITE;
064 private double squareSize = 8;
065
066 /**
067 * Create a new CheckerboardPainter. By default the light color is Color.WHITE,
068 * the dark color is a light gray, and the square length is 8.
069 */
070 public CheckerboardPainter() {
071 }
072
073 /**
074 * Create a new CheckerboardPainter with the specified light and dark paints.
075 * By default the square length is 8.
076 *
077 * @param darkPaint the paint used to draw the dark squares
078 * @param lightPaint the paint used to draw the light squares
079 */
080 public CheckerboardPainter(Paint darkPaint, Paint lightPaint) {
081 this(darkPaint, lightPaint, 8);
082 }
083
084 /**
085 * Create a new CheckerboardPainter with the specified light and dark paints
086 * and the specified square size.
087 *
088 * @param darkPaint the paint used to draw the dark squares
089 * @param lightPaint the paint used to draw the light squares
090 * @param squareSize the squareSize of the checker board squares
091 */
092 public CheckerboardPainter(Paint darkPaint, Paint lightPaint, double squareSize) {
093 this.darkPaint = darkPaint;
094 this.lightPaint = lightPaint;
095 this.squareSize = squareSize;
096 }
097
098
099 /**
100 * Specifies the squareSize of the squares. By default, it is 8. A squareSize of <=
101 * 0 will cause an IllegalArgumentException to be thrown.
102 *
103 * @param squareSize the squareSize of one side of a square tile. Must be > 0.
104 */
105 public void setSquareSize(double squareSize) {
106 if (squareSize <= 0) {
107 throw new IllegalArgumentException("Length must be > 0");
108 }
109
110 double old = getSquareSize();
111 this.squareSize = squareSize;
112 checkerPaint = null;
113 setDirty(true);
114 firePropertyChange("squareSize", old, getSquareSize());
115 }
116
117 /**
118 * Gets the current square length.
119 *
120 * @return the squareSize. Will be > 0
121 */
122 public double getSquareSize() {
123 return squareSize;
124 }
125
126 /**
127 * Specifies the paint to use for dark tiles. This is a Paint and
128 * may be anything, including a TexturePaint for painting images. If null,
129 * the background color of the component is used.
130 *
131 * @param color the Paint to use for painting the "dark" tiles. May be null.
132 */
133 public void setDarkPaint(Paint color) {
134 Paint old = getDarkPaint();
135 this.darkPaint = color;
136 checkerPaint = null;
137 setDirty(true);
138 firePropertyChange("darkPaint", old, getDarkPaint());
139 }
140
141 /**
142 *
143 * Gets the current dark paint.
144 * @return the Paint used for painting the "dark" tiles. May be null
145 */
146 public Paint getDarkPaint() {
147 return darkPaint;
148 }
149
150 /**
151 * Specifies the paint to use for light tiles. This is a Paint and
152 * may be anything, including a TexturePaint for painting images. If null,
153 * the foreground color of the component is used.
154 *
155 * @param color the Paint to use for painting the "light" tiles. May be null.
156 */
157 public void setLightPaint(Paint color) {
158 Paint old = getLightPaint();
159 this.lightPaint = color;
160 checkerPaint = null;
161 setDirty(true);
162 firePropertyChange("lightPaint", old, getLightPaint());
163 }
164
165 /**
166 *
167 * gets the current light paint
168 * @return the Paint used for painting the "light" tiles. May be null
169 */
170 public Paint getLightPaint() {
171 return lightPaint;
172 }
173
174 /**
175 * Helper method that creates and returns the Paint that incorporates the
176 * sizes and light and dark Paints in one TexturePaint. I may want to cache
177 * this value in the future for performance reasons
178 */
179 private Paint getCheckerPaint(Object c) {
180 if (checkerPaint == null) {
181 double sqlength = getSquareSize();
182 int length = (int)(sqlength * 2);
183 BufferedImage image = new BufferedImage(length, length, BufferedImage.TYPE_INT_ARGB);
184 Graphics2D gfx = image.createGraphics();
185
186 try {
187 Paint p = getLightPaint();
188 if (p == null && c instanceof JComponent) {
189 p = ((JComponent)c).getForeground();
190 }
191 gfx.setPaint(p);
192 gfx.fillRect(0, 0, length, length);
193 p = getDarkPaint();
194 if (p == null) {
195 if(c instanceof JComponent) {
196 p = ((JComponent)c).getBackground();
197 }
198 }
199 gfx.setPaint(p);
200 gfx.fillRect(0, 0, (int)(sqlength - 1), (int)(sqlength - 1));
201 gfx.fillRect((int) sqlength, (int) sqlength,
202 (int) sqlength - 1, (int) sqlength - 1);
203 } finally {
204 gfx.dispose();
205 }
206
207 checkerPaint = new TexturePaint(image, new Rectangle(0, 0, image.getWidth(), image.getHeight()));
208 }
209 return checkerPaint;
210 }
211
212 /**
213 * {@inheritDoc}
214 */
215 @Override
216 protected void doPaint(Graphics2D g, Object t, int width, int height) {
217 g.setPaint(getCheckerPaint(t));
218 g.fillRect(0, 0, width, height);
219 }
220 }