001/* 002 * $Id: ShapePainter.java 4147 2012-02-01 17:13:24Z 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 022package org.jdesktop.swingx.painter; 023 024import static org.jdesktop.swingx.painter.PainterUtils.getBackgroundPaint; 025import static org.jdesktop.swingx.painter.PainterUtils.getForegroundPaint; 026 027import java.awt.BasicStroke; 028import java.awt.Color; 029import java.awt.Graphics2D; 030import java.awt.Paint; 031import java.awt.Rectangle; 032import java.awt.Shape; 033import java.awt.geom.Ellipse2D; 034 035import org.jdesktop.beans.JavaBean; 036import org.jdesktop.swingx.painter.effects.AreaEffect; 037 038 039/** 040 * <p>A Painter that paints java.awt.Shapes. It uses a stroke and a fillPaint to do so. The 041 * shape is painted as is, at a specific location. If no Shape is specified, nothing 042 * will be painted. If no stroke is specified, the default for the Graphics2D 043 * will be used. If no fillPaint is specified, the component background color 044 * will be used. The shape can be positioned using the insets, horizontal, and 045 * vertical properties.</p> 046 * 047 * <p>Here is an example that draws a rectangle aligned on the center right: 048 * <pre><code> 049 * Rectangle2D.Double rect = new Rectangle2D.Double(0, 0, 50, 50); 050 * ShapePainter p = new ShapePainter(rect); 051 * p.setHorizontal(HorizontalAlignment.RIGHT); 052 * p.setVertical(VerticalAlignment.CENTER); 053 * </code></pre> 054 * @author rbair 055 */ 056@JavaBean 057@SuppressWarnings("nls") 058public class ShapePainter extends AbstractAreaPainter<Object> { 059 /** 060 * The Shape to fillPaint. If null, nothing is painted. 061 */ 062 private Shape shape; 063 064 /** 065 * Create a new ShapePainter 066 */ 067 public ShapePainter() { 068 super(); 069 this.shape = new Ellipse2D.Double(0,0,100,100); 070 this.setBorderWidth(3); 071 this.setFillPaint(Color.RED); 072 this.setBorderPaint(Color.BLACK); 073 } 074 075 /** 076 * Create a new ShapePainter with the specified shape. 077 * 078 * 079 * @param shape the shape to fillPaint 080 */ 081 public ShapePainter(Shape shape) { 082 super(); 083 this.shape = shape; 084 } 085 086 /** 087 * Create a new ShapePainter with the specified shape and fillPaint. 088 * 089 * 090 * @param shape the shape to fillPaint 091 * @param paint the fillPaint to be used to fillPaint the shape 092 */ 093 public ShapePainter(Shape shape, Paint paint) { 094 super(); 095 this.shape = shape; 096 this.setFillPaint(paint); 097 } 098 099 /** 100 * Create a new ShapePainter with the specified shape and fillPaint. The shape 101 * can be filled or stroked (only the outline is painted). 102 * 103 * 104 * @param shape the shape to fillPaint 105 * @param paint the fillPaint to be used to fillPaint the shape 106 * @param style specifies the ShapePainter.Style to use for painting this shape. 107 * If null, then Style.BOTH is used 108 */ 109 public ShapePainter(Shape shape, Paint paint, Style style) { 110 super(); 111 this.shape = shape; 112 this.setFillPaint(paint); 113 this.setStyle(style == null ? Style.BOTH : style); 114 } 115 116 /** 117 * Sets the shape to fillPaint. This shape is not resized when the component 118 * bounds are. To do that, create a custom shape that is bound to the 119 * component width/height 120 * 121 * 122 * @param s the Shape to fillPaint. May be null 123 */ 124 public void setShape(Shape s) { 125 Shape old = getShape(); 126 this.shape = s; 127 setDirty(true); 128 firePropertyChange("shape", old, getShape()); 129 } 130 131 /** 132 * Gets the current shape 133 * @return the Shape to fillPaint. May be null 134 */ 135 public Shape getShape() { 136 return shape; 137 } 138 139 /** 140 * {@inheritDoc} 141 */ 142 @Override 143 protected void doPaint(Graphics2D g, Object component, int w, int h) { 144 g.setStroke(new BasicStroke(this.getBorderWidth())); 145 146 if(getShape() != null) { 147 Shape s = provideShape(g,component, w, h); 148 Rectangle bounds = s.getBounds(); 149 Rectangle rect = calculateLayout(bounds.width, bounds.height, w, h); 150 //u.p("rect = " + rect); 151 g = (Graphics2D)g.create(); 152 153 try { 154 g.translate(rect.x, rect.y); 155 //draw/fill the shape 156 drawPathEffects(g, s, rect.width, rect.height); 157 switch (getStyle()) { 158 case BOTH: 159 drawShape(g, s, component, rect.width, rect.height); 160 fillShape(g, s, component, rect.width, rect.height); 161 break; 162 case FILLED: 163 fillShape(g, s, component, rect.width, rect.height); 164 break; 165 case OUTLINE: 166 drawShape(g, s, component, rect.width, rect.height); 167 break; 168 } 169 } finally { 170 g.dispose(); 171 } 172 } 173 } 174 175 private void drawShape(Graphics2D g, Shape s, Object component, int w, int h) { 176 g.setPaint(calculateStrokePaint(component, w, h)); 177 g.draw(s); 178 } 179 180 private void fillShape(Graphics2D g, Shape s, Object component, int w, int h) { 181 g.setPaint(calculateFillPaint(component, w, h)); 182 g.fill(s); 183 } 184 185 // shape effect stuff 186 @Override 187 protected Shape provideShape(Graphics2D g, Object comp, int width, int height) { 188 return getShape(); 189 } 190 191 private Paint calculateStrokePaint(Object component, int width, int height) { 192 Paint p = getForegroundPaint(getBorderPaint(), component); 193 if(isPaintStretched()) { 194 p = calculateSnappedPaint(p, width, height); 195 } 196 return p; 197 } 198 199 private Paint calculateFillPaint(Object component, int width, int height) { 200 //set the fillPaint 201 Paint p = getBackgroundPaint(getFillPaint(), component); 202 if(isPaintStretched()) { 203 p = calculateSnappedPaint(p, width, height); 204 } 205 return p; 206 } 207 208 private void drawPathEffects(Graphics2D g, Shape s, int w, int h) { 209 if(getAreaEffects() != null) { 210 //Paint pt = calculateFillPaint(component, w, h); 211 for(AreaEffect ef : getAreaEffects()) { 212 ef.apply(g, s, w, h); 213 } 214 } 215 } 216}