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.components.border;
031:
032: import java.awt.Component;
033: import java.awt.Graphics;
034: import java.awt.Insets;
035: import java.awt.Rectangle;
036:
037: import javax.swing.border.Border;
038:
039: import com.jeta.forms.gui.effects.LinearGradientPainter;
040: import com.jeta.forms.gui.effects.RadialGradientPainter;
041: import com.jeta.forms.store.properties.ColorProperty;
042: import com.jeta.forms.store.properties.ShadowBorderProperty;
043: import com.jeta.forms.store.properties.effects.GradientProperty;
044: import com.jeta.forms.store.properties.effects.RadialGradientProperty;
045:
046: /**
047: * This border paints a shadow on the right/bottom sides of a component. A
048: * shadow border is painted only on the right and bottom sides of a component.
049: * There are two types of shadows: solid and gradient. A gradient shadow changes
050: * from a start color to an end color. The end color is normally the same color
051: * as the background of the current form. This provides a fade effect for the
052: * shadow. On OSX, the shadow border is less useful because the Aqua look and
053: * feel uses a striped pattern for panel backgrounds. At some point in the
054: * future, the shadow border will need to be updated to support a fade to
055: * transparency.
056: *
057: * @author Jeff Tassin
058: */
059: public class ShadowBorder implements Border {
060: /**
061: * The property that contains the attributes for this border
062: */
063: private ShadowBorderProperty m_prop;
064:
065: /**
066: * The insets for the border
067: */
068: private Insets m_insets;
069:
070: /**
071: * For gradient shadow borders only
072: */
073: private LinearGradientPainter m_right_painter;
074: private LinearGradientPainter m_bottom_painter;
075: private RadialGradientPainter m_bottom_right_painter;
076: private RadialGradientPainter m_top_right_painter;
077: private RadialGradientPainter m_bottom_left_painter;
078: private Rectangle m_rect;
079:
080: /**
081: * ctor needed for JavaBeans persistence.
082: */
083: public ShadowBorder() {
084:
085: }
086:
087: /**
088: * ctor
089: */
090: public ShadowBorder(int type, int thickness,
091: ColorProperty startColor, ColorProperty endColor,
092: boolean symmetric) {
093: m_prop = new ShadowBorderProperty(type, thickness, startColor,
094: endColor, symmetric);
095: getBorderInsets(null);
096: }
097:
098: /**
099: * ctor
100: */
101: public ShadowBorder(ShadowBorderProperty prop) {
102: m_prop = new ShadowBorderProperty();
103: m_prop.setValue(prop);
104: getBorderInsets(null);
105: }
106:
107: /**
108: * @return the border insets
109: */
110: public Insets getBorderInsets(Component c) {
111: assert (m_prop != null);
112: if (m_insets == null) {
113: if (isSymmetric()) {
114: m_insets = new Insets(m_prop.getThickness(), m_prop
115: .getThickness(), m_prop.getThickness(), m_prop
116: .getThickness());
117: } else {
118: m_insets = new Insets(0, 0, m_prop.getThickness(),
119: m_prop.getThickness());
120: }
121: }
122: return m_insets;
123: }
124:
125: public boolean isSymmetric() {
126: return m_prop.isSymmetric();
127: }
128:
129: public boolean isBorderOpaque() {
130: return false;
131: }
132:
133: public ColorProperty getStartColor() {
134: return m_prop.getStartColor();
135: }
136:
137: public ColorProperty getEndColor() {
138: return m_prop.getEndColor();
139: }
140:
141: public ShadowBorderProperty getBorderProperty() {
142: return m_prop;
143: }
144:
145: public void setBorderProperty(ShadowBorderProperty prop) {
146: m_prop = prop;
147: getBorderInsets(null);
148: m_right_painter = null;
149: }
150:
151: public void paintBorder(Component c, Graphics g, int x, int y,
152: int width, int height) {
153: if (m_prop.getType() == ShadowBorderProperty.SOLID) {
154: int thickness = m_prop.getThickness();
155: int rheight_offset = 0;
156: int bwidth_offset = 0;
157:
158: if (thickness < 8) {
159: rheight_offset = 1;
160: bwidth_offset = 1;
161: }
162:
163: if (isSymmetric()) {
164: g.setColor(m_prop.getEndColor().getColor());
165: rheight_offset += thickness;
166: bwidth_offset += thickness;
167:
168: /** clear the top and left sides */
169: g.fillRect(x, y, width + thickness, thickness);
170: g.fillRect(x, y, thickness, height + thickness);
171: }
172:
173: /** render the shadow offsets */
174: g.setColor(m_prop.getEndColor().getColor());
175: /**
176: * right shadown offset
177: */
178: g.fillRect(x + width - thickness, y, thickness, thickness
179: + rheight_offset);
180: /**
181: * bottom shadown offset
182: */
183: g.fillRect(x, y + height - thickness, thickness
184: + bwidth_offset, thickness);
185:
186: /** render the shadow */
187: g.setColor(m_prop.getStartColor().getColor());
188: /**
189: * right shadow
190: */
191: g.fillRect(x + width - thickness, y + thickness
192: + rheight_offset, thickness, height);
193: /**
194: * bottom shadow
195: */
196: g.fillRect(x + thickness + bwidth_offset, y + height
197: - thickness, width, thickness);
198: } else {
199: paintGradient(g, x, y, width, height);
200: }
201: }
202:
203: /**
204: * Renders this border as a gradient
205: */
206: public void paintGradient(Graphics g, int x, int y, int width,
207: int height) {
208: if (m_right_painter == null) {
209: m_right_painter = new LinearGradientPainter(
210: new GradientProperty(getStartColor(),
211: getEndColor(), GradientProperty.LEFT_RIGHT));
212:
213: m_bottom_painter = new LinearGradientPainter(
214: new GradientProperty(getStartColor(),
215: getEndColor(), GradientProperty.TOP_BOTTOM));
216:
217: m_bottom_right_painter = new RadialGradientPainter(
218: new RadialGradientProperty(getStartColor(),
219: getEndColor(),
220: RadialGradientProperty.TOP_LEFT, 200));
221: m_bottom_right_painter
222: .setRadiusType(RadialGradientPainter.WIDTH_BASED);
223:
224: m_top_right_painter = new RadialGradientPainter(
225: new RadialGradientProperty(getStartColor(),
226: getEndColor(),
227: RadialGradientProperty.BOTTOM_LEFT, 200));
228: m_top_right_painter
229: .setRadiusType(RadialGradientPainter.WIDTH_BASED);
230:
231: m_bottom_left_painter = new RadialGradientPainter(
232: new RadialGradientProperty(getStartColor(),
233: getEndColor(),
234: RadialGradientProperty.TOP_RIGHT, 200));
235: m_bottom_left_painter
236: .setRadiusType(RadialGradientPainter.HEIGHT_BASED);
237: }
238:
239: if (m_rect == null)
240: m_rect = new Rectangle();
241:
242: int thickness = m_prop.getThickness();
243: int padding = 1;
244: int rheight_offset = -1 * padding;
245: int bwidth_offset = -1 * padding;
246:
247: if (isSymmetric()) {
248: /** clear the top and left sides */
249: g.setColor(m_prop.getEndColor().getColor());
250: rheight_offset += thickness;
251: bwidth_offset += thickness;
252: g.fillRect(x, y, width + thickness, thickness);
253: g.fillRect(x, y, thickness, height + thickness);
254: padding = 0;
255: }
256:
257: /** render the shadow offsets */
258: g.setColor(m_prop.getEndColor().getColor());
259: /**
260: * right shadow offset
261: */
262: g.fillRect(x + width - thickness, y, thickness, thickness
263: + rheight_offset);
264: /**
265: * bottom shadow offset
266: */
267: g.fillRect(x, y + height - thickness,
268: thickness + bwidth_offset, thickness);
269:
270: /** render the right shadow */
271: m_rect.setBounds(x + width - thickness, y + thickness
272: + rheight_offset, thickness + 1, height - thickness * 2
273: + padding);
274: m_right_painter.paint(null, g, m_rect);
275:
276: /** render the top right shadow */
277: m_rect.setBounds(x + width - thickness, y + thickness
278: + rheight_offset, thickness, thickness);
279: m_top_right_painter.paint(null, g, m_rect);
280:
281: /** render the bottom shadow */
282: m_rect
283: .setBounds(x + thickness + bwidth_offset, y + height
284: - thickness, width - thickness * 2 + padding,
285: thickness);
286: m_bottom_painter.paint(null, g, m_rect);
287:
288: /** render the bottom left shadow */
289: m_rect.setBounds(x + thickness + bwidth_offset, y + height
290: - thickness, thickness, thickness);
291: m_bottom_left_painter.paint(null, g, m_rect);
292:
293: /** render the bottom right shadow */
294: m_rect.setBounds(x + width - thickness, y + height - thickness,
295: thickness, thickness);
296: m_bottom_right_painter.paint(null, g, m_rect);
297:
298: }
299: }
|