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