001: /*
002: * Copyright (c) 2005-2008 Substance Kirill Grouchnikov. All Rights Reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, 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 Substance Kirill Grouchnikov nor the names of
015: * its contributors may be used to endorse or promote products derived
016: * from this software without 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,
020: * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
021: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
022: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
025: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
026: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
027: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
028: * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029: */
030: package org.jvnet.substance.painter;
031:
032: import java.awt.*;
033: import java.awt.geom.GeneralPath;
034: import java.awt.image.BufferedImage;
035:
036: import org.jvnet.substance.color.ColorScheme;
037: import org.jvnet.substance.utils.SubstanceCoreUtilities;
038:
039: /**
040: * Base class for gradient painters that overlays wave gradient on top of some
041: * other gradient painter.This class is part of officially supported API. The
042: * implementation borrows heavily from <a
043: * href="http://weblogs.java.net/blog/campbell/archive/2006/07/java_2d_tricker.html">this</a>.
044: *
045: * @author Kirill Grouchnikov.
046: * @author Chris Campbell.
047: */
048: public abstract class WaveDelegateGradientPainter extends
049: BaseGradientPainter {
050: /**
051: * Transformation on a color scheme.
052: *
053: * @author Kirill Grouchnikov.
054: */
055: public static interface ColorSchemeTransformation {
056: /**
057: * Transforms the specified color scheme.
058: *
059: * @param scheme
060: * Color scheme.
061: * @return Transformed color scheme.
062: */
063: public ColorScheme transform(ColorScheme scheme);
064: }
065:
066: /**
067: * Display name of <code>this</code> painter.
068: */
069: protected String painterName;
070:
071: /**
072: * Optional scheme transformation - may be <code>null</code>.
073: */
074: protected ColorSchemeTransformation transformation;
075:
076: /**
077: * Mandatory delegate painter.
078: */
079: protected SubstanceGradientPainter delegate;
080:
081: /**
082: * Creates a new wave-overlaying painter.
083: *
084: * @param painterName
085: * Painter display name.
086: * @param transformation
087: * Optional scheme transformation. If <code>null</code>, the
088: * result will be identical to using the delegate painter.
089: * @param delegate
090: * Delegate painter.
091: */
092: public WaveDelegateGradientPainter(String painterName,
093: ColorSchemeTransformation transformation,
094: SubstanceGradientPainter delegate) {
095: this .painterName = painterName;
096: this .transformation = transformation;
097: this .delegate = delegate;
098: }
099:
100: /*
101: * (non-Javadoc)
102: *
103: * @see org.jvnet.substance.painter.SubstanceGradientPainter#getDisplayName()
104: */
105: public String getDisplayName() {
106: return this .painterName;
107: }
108:
109: /*
110: * (non-Javadoc)
111: *
112: * @see org.jvnet.substance.painter.SubstanceGradientPainter#getContourBackground(int,
113: * int, java.awt.Shape, boolean, org.jvnet.substance.color.ColorScheme,
114: * org.jvnet.substance.color.ColorScheme, float, boolean, boolean)
115: */
116: public BufferedImage getContourBackground(int width, int height,
117: Shape contour, boolean isFocused, ColorScheme colorScheme1,
118: ColorScheme colorScheme2, float cyclePos, boolean hasShine,
119: boolean useCyclePosAsInterpolation) {
120:
121: BufferedImage mixResult = this .getMixContourBackground(width,
122: height, contour, isFocused, colorScheme1, colorScheme2,
123: cyclePos, hasShine, useCyclePosAsInterpolation);
124: if (mixResult != null)
125: return mixResult;
126:
127: // ColorScheme interpolationScheme1 = colorScheme1;
128: // ColorScheme interpolationScheme2 = useCyclePosAsInterpolation ? colorScheme2
129: // : colorScheme1;
130: //
131: // double cycleCoef = 1.0 - cyclePos / 10.0;
132: //
133: // Color topBorderColor = SubstanceColorUtilities.getTopBorderColor(
134: // interpolationScheme1, interpolationScheme2, cycleCoef);
135: // Color midBorderColor = SubstanceColorUtilities.getMidBorderColor(
136: // interpolationScheme1, interpolationScheme2, cycleCoef);
137: // Color bottomBorderColor = SubstanceColorUtilities.getBottomBorderColor(
138: // interpolationScheme1, interpolationScheme2, cycleCoef);
139:
140: BufferedImage topFullImage = this .delegate
141: .getContourBackground(width, height, contour,
142: isFocused, colorScheme1, colorScheme2,
143: cyclePos, hasShine, useCyclePosAsInterpolation);
144:
145: GeneralPath clipBottom = new GeneralPath();
146: clipBottom.moveTo(0, height);
147: clipBottom.lineTo(width, height);
148: clipBottom.lineTo(width, 0);
149: clipBottom.curveTo(5 * width / 6, height / 3, 3 * width / 4,
150: height / 2, width / 2, height / 2);
151: clipBottom.curveTo(width / 3, height / 2, width / 4, height, 0,
152: 7 * height / 8);
153: clipBottom.lineTo(0, height);
154:
155: BufferedImage clipShapeBottom = SubstanceCoreUtilities
156: .createClipImage(clipBottom, width, height);
157:
158: BufferedImage bottomImage = SubstanceCoreUtilities
159: .getBlankImage(width, height);
160: Graphics2D bottomGraphics = (Graphics2D) bottomImage
161: .getGraphics();
162: bottomGraphics.setRenderingHint(
163: RenderingHints.KEY_ANTIALIASING,
164: RenderingHints.VALUE_ANTIALIAS_ON);
165:
166: ColorScheme bottomColorScheme1 = (this .transformation == null) ? colorScheme1
167: : this .transformation.transform(colorScheme1);
168: ColorScheme bottomColorScheme2 = (this .transformation == null) ? colorScheme1
169: : this .transformation.transform(colorScheme2);
170: BufferedImage bottomFullImage = this .delegate
171: .getContourBackground(width, height, contour,
172: isFocused, bottomColorScheme1,
173: bottomColorScheme2, cyclePos, hasShine,
174: useCyclePosAsInterpolation);
175:
176: // Render our clip shape into the image. Note that we enable
177: // antialiasing to achieve the soft clipping effect. Try
178: // commenting out the line that enables antialiasing, and
179: // you will see that you end up with the usual hard clipping.
180: bottomGraphics.setComposite(AlphaComposite.Src);
181: bottomGraphics.setRenderingHint(
182: RenderingHints.KEY_ANTIALIASING,
183: RenderingHints.VALUE_ANTIALIAS_ON);
184: bottomGraphics.drawImage(clipShapeBottom, 0, 0, null);
185:
186: // Here's the trick... We use SrcAtop, which effectively uses the
187: // alpha value as a coverage value for each pixel stored in the
188: // destination. For the areas outside our clip shape, the destination
189: // alpha will be zero, so nothing is rendered in those areas. For
190: // the areas inside our clip shape, the destination alpha will be fully
191: // opaque, so the full color is rendered. At the edges, the original
192: // antialiasing is carried over to give us the desired soft clipping
193: // effect.
194: bottomGraphics.setComposite(AlphaComposite.SrcAtop);
195: bottomGraphics.drawImage(bottomFullImage, 0, 0, null);
196:
197: BufferedImage image = SubstanceCoreUtilities.getBlankImage(
198: width, height);
199: Graphics2D graphics = (Graphics2D) image.getGraphics();
200: graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
201: RenderingHints.VALUE_ANTIALIAS_ON);
202:
203: graphics.setClip(contour);
204: graphics.drawImage(topFullImage, 0, 0, null);
205: graphics.drawImage(bottomImage, 0, 0, null);
206:
207: graphics.setClip(null);
208:
209: // // Draw border
210: // GradientPaint gradientBorderTop = new GradientPaint(0, 0,
211: // topBorderColor, 0, height / 2, midBorderColor);
212: // graphics.setPaint(gradientBorderTop);
213: // graphics.setClip(0, 0, width, height / 2);
214: // graphics.draw(contour);
215: //
216: // GradientPaint gradientBorderBottom = new GradientPaint(0, height / 2,
217: // midBorderColor, 0, height - 2, bottomBorderColor);
218: // graphics.setPaint(gradientBorderBottom);
219: // graphics.setClip(0, height / 2, width, 1 + height / 2);
220: // graphics.draw(contour);
221:
222: return image;
223: }
224: }
|