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 }