001: /*
002: * Copyright (c) 2004 JETA Software, Inc. All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without modification,
005: * are permitted provided that the following conditions are met:
006: *
007: * o Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * o Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * o Neither the name of JETA Software nor the names of its contributors may
015: * be used to endorse or promote products derived from this software without
016: * specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
021: * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
022: * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
023: * INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
024: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
025: * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
026: * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
027: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028: */
029:
030: package com.jeta.forms.gui.effects;
031:
032: import java.awt.Color;
033: import java.awt.Component;
034: import java.awt.Graphics;
035: import java.awt.Graphics2D;
036: import java.awt.Paint;
037: import java.awt.Rectangle;
038:
039: import javax.swing.LookAndFeel;
040: import javax.swing.UIManager;
041:
042: import org.apache.batik.ext.awt.RadialGradientPaint;
043:
044: import com.jeta.forms.store.properties.effects.RadialGradientProperty;
045:
046: /**
047: * This class is an implementation of a Painter that renders a radial gradient
048: * on part of a canvas or component. This class uses the Batik SVG library for
049: * rendering the gradient. See <a
050: * href="http://xml.apache.org/batik/">http://xml.apache.org/batik/</a>
051: *
052: * @author Jeff Tassin
053: */
054: public class RadialGradientPainter implements Painter {
055: /**
056: * The property that defines the gradient settings.
057: */
058: private RadialGradientProperty m_gradient_prop;
059:
060: /**
061: * A paint object derived from the gradient property. It is cached so we
062: * don't have to re-instantiate with every paint.
063: */
064: private Paint m_cached_paint;
065:
066: /**
067: * A rectangle used as a basis for the gradient paint. This value is checked
068: * everytime the paint method is called. If the paint area has changed, we
069: * regenerate the Paint object.
070: */
071: private Rectangle m_last_rect = new Rectangle();
072:
073: /**
074: * We keep track of the look and feel. If it changes, we need to regenerate
075: * the paint
076: */
077: private LookAndFeel m_look_and_feel;
078:
079: /**
080: * Flag that determines how the radius of this gradient is calculated
081: */
082: private int m_radius_type = SQUARE_BASED;
083:
084: /**
085: * The radius is calculated based on the distance from the center of a
086: * rectangle to its corners or sides.
087: */
088: public static final int SQUARE_BASED = 0;
089:
090: /**
091: * The radius is calculated as the width of the paint area.
092: */
093: public static final int WIDTH_BASED = 1;
094:
095: /**
096: * The radius is calculated as the height of the paint area.
097: */
098: public static final int HEIGHT_BASED = 2;
099:
100: /**
101: * Creates a <code>RadialGradientProperty</code> instance with no paint
102: * attributes.
103: */
104: public RadialGradientPainter() {
105:
106: }
107:
108: /**
109: * Creates a <code>RadialGradientProperty</code> instance with the
110: * specified paint properties.
111: */
112: public RadialGradientPainter(RadialGradientProperty prop) {
113: m_gradient_prop = prop;
114: }
115:
116: /**
117: * Calculate the radius used for this radial gradient.
118: *
119: * @return the radius for the radial paint
120: */
121: private double calculateRadius(double width, double height,
122: int magnitude) {
123: if (m_radius_type == WIDTH_BASED)
124: return width * magnitude / 100.0;
125: else if (m_radius_type == HEIGHT_BASED)
126: return height * magnitude / 100.0;
127: else
128: return Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2))
129: * magnitude / 100.0;
130: }
131:
132: /**
133: * Creates a paint object based on the given rectangle and gradient
134: * property.
135: *
136: * @param rect
137: * the rectangle that defines the area for the gradient.
138: * @param gp
139: * the gradient properties used to define the paint.
140: * @return a paint object used for rendering the gradient on a graphics
141: * context.
142: */
143: private Paint createPaint(Rectangle rect, RadialGradientProperty gp) {
144: double w_half = rect.getWidth() / 2.0;
145: double h_half = rect.getHeight() / 2.0;
146:
147: double x = rect.getX() + w_half;
148: double y = rect.getY() + h_half;
149: double radius = gp.getMagnitude() * rect.getWidth() / 400.0;
150:
151: if (gp.getPosition() == RadialGradientProperty.TOP_LEFT) {
152: x = rect.getX();
153: y = rect.getY();
154: radius = calculateRadius(w_half, h_half, gp.getMagnitude());
155: } else if (gp.getPosition() == RadialGradientProperty.TOP_CENTER) {
156: x = w_half;
157: y = rect.getY();
158: radius = w_half * gp.getMagnitude() / 100.0;
159: } else if (gp.getPosition() == RadialGradientProperty.TOP_RIGHT) {
160: x = rect.getX() + rect.getWidth();
161: y = rect.getY();
162: radius = calculateRadius(w_half, h_half, gp.getMagnitude());
163: } else if (gp.getPosition() == RadialGradientProperty.BOTTOM_LEFT) {
164: x = rect.getX();
165: y = rect.getY() + rect.getHeight();
166: radius = calculateRadius(w_half, h_half, gp.getMagnitude());
167: } else if (gp.getPosition() == RadialGradientProperty.BOTTOM_CENTER) {
168: x = w_half;
169: y = rect.getY() + rect.getHeight();
170: radius = w_half * gp.getMagnitude() / 100.0;
171: } else if (gp.getPosition() == RadialGradientProperty.BOTTOM_RIGHT) {
172: x = rect.getX() + rect.getWidth();
173: y = rect.getY() + rect.getHeight();
174: radius = calculateRadius(w_half, h_half, gp.getMagnitude());
175: } else if (gp.getPosition() == RadialGradientProperty.LEFT_CENTER) {
176: x = rect.getX();
177: y = rect.getY() + h_half;
178: radius = h_half * gp.getMagnitude() / 100.0;
179: } else if (gp.getPosition() == RadialGradientProperty.RIGHT_CENTER) {
180: x = rect.getX() + rect.getWidth();
181: y = rect.getY() + h_half;
182: radius = h_half * gp.getMagnitude() / 100.0;
183: }
184:
185: float[] fractions = new float[] { 0.0f, 1.0f };
186: Color[] colors = new Color[] { gp.getStartColor().getColor(),
187: gp.getEndColor().getColor() };
188: RadialGradientPaint paint = new RadialGradientPaint((float) x,
189: (float) y, (float) radius, fractions, colors);
190: return paint;
191: }
192:
193: /**
194: * Painter implementation. Paints a radial gradient on a given graphics
195: * context.
196: *
197: * @param g
198: * the graphics context
199: * @param rect
200: * the rectangle that defines the region to paint. Note, that
201: * this is different than the clipping rectangle.
202: */
203: public void paint(Component c, Graphics g, Rectangle rect) {
204: if (rect == null || m_gradient_prop == null)
205: return;
206:
207: Graphics2D g2 = (Graphics2D) g;
208: Paint old_paint = g2.getPaint();
209:
210: LookAndFeel lf = UIManager.getLookAndFeel();
211: if (m_look_and_feel != lf) {
212: m_cached_paint = null;
213: m_look_and_feel = lf;
214: }
215:
216: if (m_cached_paint == null || !rect.equals(m_last_rect)) {
217: m_last_rect.setBounds(rect.x, rect.y, rect.width,
218: rect.height);
219: m_cached_paint = createPaint(rect, m_gradient_prop);
220: }
221:
222: g2.setPaint(m_cached_paint);
223:
224: Rectangle clip_rect = g.getClipBounds();
225: if (rect.intersects(clip_rect)) {
226: Rectangle irect = rect.intersection(clip_rect);
227: g.fillRect(irect.x, irect.y, irect.width, irect.height);
228: g2.setPaint(old_paint);
229: }
230:
231: g2.setPaint(old_paint);
232: }
233:
234: /**
235: * Sets the gradient attributes for this painter
236: *
237: * @param prop
238: * the gradient property to associate with this painter.
239: */
240: public void setGradientProperty(RadialGradientProperty prop) {
241: m_cached_paint = null;
242: m_gradient_prop = prop;
243: }
244:
245: /**
246: * Sets the radius type for this painter. Valid values are:
247: * RadialGradientPainter.SQUARE_BASED RadialGradientPainter.WIDTH_BASED
248: * RadialGradientPainter.HEIGHT_BASED
249: *
250: * @param rtype
251: * the radius type to set.
252: */
253: public void setRadiusType(int rtype) {
254: m_radius_type = rtype;
255: }
256: }
|