001/* 002 * $Id: RectanglePainter.java 4147 2012-02-01 17:13:24Z 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 022package org.jdesktop.swingx.painter; 023 024import java.awt.BasicStroke; 025import java.awt.Color; 026import java.awt.Graphics2D; 027import java.awt.Insets; 028import java.awt.Paint; 029import java.awt.Rectangle; 030import java.awt.Shape; 031import java.awt.geom.Rectangle2D; 032import java.awt.geom.RectangularShape; 033import java.awt.geom.RoundRectangle2D; 034 035import org.jdesktop.beans.JavaBean; 036import org.jdesktop.swingx.painter.effects.AreaEffect; 037import org.jdesktop.swingx.util.ShapeUtils; 038 039/** 040 * A painter which paints square and rounded rectangles 041 * 042 * @author joshua.marinacci@sun.com 043 */ 044@JavaBean 045@SuppressWarnings("nls") 046public class RectanglePainter extends AbstractAreaPainter<Object> { 047 private boolean rounded = false; 048 //private Insets insets = new Insets(0,0,0,0); 049 private int roundWidth = 20; 050 private int roundHeight = 20; 051 private int width = -1; 052 private int height = -1; 053 //private double strokeWidth = 1; 054 055 /** Creates a new instance of RectanglePainter */ 056 public RectanglePainter() { 057 this(0, 0, 0, 0); 058 } 059 060 public RectanglePainter(int top, int left, int bottom, int right) { 061 this(top, left, bottom, right, 0, 0); 062 } 063 064 public RectanglePainter(int top, int left, int bottom, int right, 065 int roundWidth, int roundHeight) { 066 this(top, left, bottom, right, roundWidth, roundHeight, roundWidth != 0 || roundHeight != 0, Color.RED, 1f, Color.BLACK); 067 } 068 069 public RectanglePainter(int top, int left, int bottom, int right, int roundWidth, 070 int roundHeight, boolean rounded, Paint fillPaint, float strokeWidth, Paint borderPaint) { 071 this(new Insets(top, left, bottom, right), -1, -1, roundWidth, roundHeight, rounded, fillPaint, strokeWidth, borderPaint); 072 } 073 074 public RectanglePainter(Color fillPaint, Color borderPaint) { 075 this(fillPaint, borderPaint, 1f, null); 076 } 077 078 public RectanglePainter(Paint fillPaint, Paint borderPaint, float borderWidth, Style style) { 079 this(new Insets(0, 0, 0, 0), -1, -1, 0, 0, false, fillPaint, borderWidth, borderPaint); 080 setStyle(style); 081 setDirty(false); 082 } 083 084 public RectanglePainter(int width, int height, int cornerRadius, Paint fillPaint) { 085 this(new Insets(0, 0, 0, 0), width, height, cornerRadius, cornerRadius, true, fillPaint, 1f, Color.BLACK); 086 } 087 088 public RectanglePainter(Insets insets, int width, int height, int roundWidth, int roundHeight, 089 boolean rounded, Paint fillPaint, float strokeWidth, Paint borderPaint) { 090 this.width = width; 091 this.height = height; 092 setFillHorizontal(width < 0); 093 setFillVertical(height < 0); 094 setInsets(insets); 095 this.roundWidth = roundWidth; 096 this.roundHeight = roundHeight; 097 this.rounded = rounded; 098 this.setFillPaint(fillPaint); 099 this.setBorderWidth(strokeWidth); 100 this.setBorderPaint(borderPaint); 101 this.setDirty(false); 102 } 103 104 /** 105 * Indicates if the rectangle is rounded 106 * @return if the rectangle is rounded 107 */ 108 public boolean isRounded() { 109 return rounded; 110 } 111 112 /** 113 * sets if the rectangle should be rounded 114 * @param rounded if the rectangle should be rounded 115 */ 116 public void setRounded(boolean rounded) { 117 boolean oldRounded = isRounded(); 118 this.rounded = rounded; 119 setDirty(true); 120 firePropertyChange("rounded",oldRounded,rounded); 121 } 122 123 /** 124 * gets the round width of the rectangle 125 * @return the current round width 126 */ 127 public int getRoundWidth() { 128 return roundWidth; 129 } 130 131 /** 132 * sets the round width of the rectangle 133 * @param roundWidth a new round width 134 */ 135 public void setRoundWidth(int roundWidth) { 136 int oldRoundWidth = getRoundWidth(); 137 this.roundWidth = roundWidth; 138 setDirty(true); 139 firePropertyChange("roundWidth",oldRoundWidth,roundWidth); 140 } 141 142 /** 143 * gets the round height of the rectangle 144 * @return the current round height 145 */ 146 public int getRoundHeight() { 147 return roundHeight; 148 } 149 150 /** 151 * sets the round height of the rectangle 152 * @param roundHeight a new round height 153 */ 154 public void setRoundHeight(int roundHeight) { 155 int oldRoundHeight = getRoundHeight(); 156 this.roundHeight = roundHeight; 157 setDirty(true); 158 firePropertyChange("roundHeight",oldRoundHeight,roundHeight); 159 } 160 161 162 /* ======== drawing code ============ */ 163 protected RectangularShape calculateShape(int width, int height) { 164 Insets insets = getInsets(); 165 int x = insets.left; 166 int y = insets.top; 167 168 // use the position calcs from the super class 169 Rectangle bounds = calculateLayout(this.width, this.height, width, height); 170 if(this.width != -1 && !isFillHorizontal()) { 171 width = this.width; 172 x = bounds.x; 173 } 174 if(this.height != -1 && !isFillVertical()) { 175 height = this.height; 176 y = bounds.y; 177 } 178 179 if(isFillHorizontal()) { 180 width = width - insets.left - insets.right; 181 } 182 if(isFillVertical()) { 183 height = height - insets.top - insets.bottom; 184 } 185 186 187 RectangularShape shape = new Rectangle2D.Double(x, y, width, height); 188 if(rounded) { 189 shape = new RoundRectangle2D.Double(x, y, width, height, roundWidth, roundHeight); 190 } 191 return shape; 192 } 193 194 195 196 @Override 197 protected void doPaint(Graphics2D g, Object component, int width, int height) { 198 Shape shape = provideShape(g, component, width, height); 199 switch (getStyle()) { 200 case BOTH: 201 drawBackground(g,shape,width,height); 202 drawBorder(g,shape,width,height); 203 break; 204 case FILLED: 205 drawBackground(g,shape,width,height); 206 break; 207 case OUTLINE: 208 drawBorder(g,shape,width,height); 209 break; 210 } 211 212 // background 213 // border 214 // leave the clip to support masking other painters 215 ShapeUtils.mergeClip(g,shape); 216 /* 217 Area area = new Area(g.getClip()); 218 area.intersect(new Area(shape));//new Rectangle(0,0,width,height))); 219 g.setClip(area);*/ 220 //g.setClip(shape); 221 } 222 223 private void drawBorder(Graphics2D g, Shape shape, int width, int height) { 224 Paint p = getBorderPaint(); 225 if(isPaintStretched()) { 226 p = calculateSnappedPaint(p, width, height); 227 } 228 229 g.setPaint(p); 230 231 g.setStroke(new BasicStroke(getBorderWidth())); 232 233 // shrink the border by 1 px 234 if(shape instanceof Rectangle2D) { 235 Rectangle2D rect = (Rectangle2D) shape; 236 237 g.draw(new Rectangle2D.Double(rect.getX(), rect.getY(), 238 rect.getWidth()-1, rect.getHeight()-1)); 239 } else if(shape instanceof RoundRectangle2D) { 240 RoundRectangle2D rect = (RoundRectangle2D) shape; 241 242 g.draw(new RoundRectangle2D.Double(rect.getX(), rect.getY(), 243 rect.getWidth()-1, rect.getHeight()-1, 244 rect.getArcWidth(), rect.getArcHeight())); 245 } else { 246 g.draw(shape); 247 } 248 } 249 250 private void drawBackground(Graphics2D g, Shape shape, int width, int height) { 251 Paint p = getFillPaint(); 252 if(isPaintStretched()) { 253 p = calculateSnappedPaint(p, width, height); 254 } 255 256 g.setPaint(p); 257 258 g.fill(shape); 259 if(getAreaEffects() != null) { 260 for(AreaEffect ef : getAreaEffects()) { 261 ef.apply(g, shape, width, height); 262 } 263 } 264 } 265 266 @Override 267 protected Shape provideShape(Graphics2D g, Object comp, int width, int height) { 268 return calculateShape(width,height); 269 } 270} 271