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