001    /*
002     * $Id: NeonBorderEffect.java 3166 2009-01-02 13:27:18Z rah003 $
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    
023    package org.jdesktop.swingx.painter.effects;
024    
025    import java.awt.*;
026    
027    /**
028     * An effect which draws a multicolored border around a painter's shape.
029     * It will interpolate between two specified colors, creating a neon like effect.
030     * @author joshy
031     */
032    public class NeonBorderEffect extends AbstractAreaEffect {
033        
034        private Color edgeColor;
035        private Color centerColor;
036        private BorderPosition borderPosition = BorderPosition.Outside;
037        
038        /**
039         * An enum representing the position of the border: inside, outside, or centered on the border.
040         */
041        public enum BorderPosition { Inside, Centered, Outside }
042        
043        
044        /**
045         * Create a new NeonBorderEffect
046         */
047        public NeonBorderEffect() {
048            this(Color.GREEN, Color.WHITE, 10);
049        }
050        
051        /** Creates a new instance of NeonBorderEffect */
052        public NeonBorderEffect(Color edgeColor, Color centerColor, int effectWidth) {
053            super();
054            setEffectWidth(effectWidth);
055            this.setEdgeColor(edgeColor);
056            this.setCenterColor(centerColor);
057            this.setRenderInsideShape(false);
058            this.setShouldFillShape(false);
059            this.setOffset(new Point(0,0));
060        }
061        
062        protected void paintBorderGlow(Graphics2D gfx, Shape clipShape, int width, int height) {
063            
064            /*
065            // draw the effect
066            for(float i=steps-1; i>=0; i=i-1f) {
067                float brushWidth = i * getEffectWidth()/steps;
068                gfx.setPaint(interpolateColor(i/steps,edgeColor,centerColor));
069                gfx.setStroke(new BasicStroke(brushWidth,
070                        BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
071                gfx.draw(clipShape);
072            }*/
073            
074            /* // an interesting outline effect. stroke the shape with a wide brush
075             * // then stroke again with slightly less wide one, then don't fill the middle
076            for(int i=0; i<2; i++) {
077                float brushWidth = (2-i)*5;
078                p("widdth = " + brushWidth);
079                gfx.setPaint(interpolateColor((float)(1-i), Color.BLACK, Color.WHITE));
080                gfx.setStroke(new BasicStroke(brushWidth));
081                gfx.draw(clipShape);
082            }
083             */
084            gfx.translate(getOffset().getX(), getOffset().getY());
085            gfx.setComposite(AlphaComposite.SrcOver);
086            int steps = getEffectWidth();
087            if(borderPosition == BorderPosition.Centered) {
088                steps = steps/2;
089            }
090            for(int i=0; i<steps; i++) {
091                
092                // make the brush width smaller each time until there is nothing left
093                float brushWidth = (float)(steps+1-i);
094                float half = steps/2;
095                
096                if(borderPosition == BorderPosition.Centered) {
097                    gfx.setPaint(interpolateColor((float)(steps-i)/steps, getEdgeColor(), getCenterColor()));
098                } else {
099                    if(i<half) {
100                        gfx.setPaint(interpolateColor((float)(half-i)/half, getEdgeColor(), getCenterColor()));
101                    } else {
102                        gfx.setPaint(interpolateColor((float)(i-half)/half, getEdgeColor(), getCenterColor()));
103                    }
104                }
105                
106                // to make the effect softer use a different stroke
107                gfx.setStroke(new BasicStroke(brushWidth,
108                        BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
109                //gfx.setStroke(new BasicStroke(brushWidth));
110                gfx.draw(clipShape);
111            }
112            gfx.translate(-getOffset().getX(), -getOffset().getY());
113            
114        }
115        
116        protected Color interpolateColor(float t, Color start, Color end) {
117            float[] partsS = start.getRGBComponents(null);
118            float[] partsE = end.getRGBComponents(null);
119            float[] partsR = new float[4];
120            for(int i=0; i<4; i++) {
121                partsR[i] = (partsS[i] - partsE[i])*t + partsE[i];
122            }
123            return new Color(partsR[0],partsR[1],partsR[2],partsR[3]);
124        }
125        
126        /**
127         * Gets the current edge color.
128         * @return current edge color
129         */
130        public Color getEdgeColor() {
131            return edgeColor;
132        }
133        
134        /**
135         * Set the edge color
136         * @param edgeColor 
137         */
138        public void setEdgeColor(Color edgeColor) {
139            this.edgeColor = edgeColor;
140        }
141        
142        /**
143         * 
144         * @return color in the center of the effect
145         */
146        public Color getCenterColor() {
147            return centerColor;
148        }
149        
150        /**
151         * 
152         * @param centerColor color in the center of the effect.
153         * @see #getCenterColor()
154         */
155        public void setCenterColor(Color centerColor) {
156            this.centerColor = centerColor;
157        }
158        
159        /**
160         * 
161         * @return position of the border relative to the edge of painter covered area.
162         * @see BorderPosition
163         */
164        public BorderPosition getBorderPosition() {
165            return borderPosition;
166        }
167        
168        /**
169         * 
170         * @param borderPosition position of the border relative to the edge of painter covered area.
171         * @see #getBorderPosition()
172         * @see BorderPosition
173         */
174        public void setBorderPosition(BorderPosition borderPosition) {
175            this.borderPosition = borderPosition;
176            switch(borderPosition) {
177                case Centered : 
178                    setShapeMasked(false);
179                    break;
180                case Inside :
181                    setShapeMasked(true);
182                    setRenderInsideShape(true);
183                    break;
184                case Outside :
185                    setShapeMasked(true);
186                    setRenderInsideShape(false);
187                    break;
188            }
189            if(borderPosition == BorderPosition.Centered) {
190            }
191        }
192    }