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.button;
031:
032: import java.awt.Insets;
033: import java.awt.geom.GeneralPath;
034: import java.util.Set;
035:
036: import javax.swing.AbstractButton;
037:
038: import org.jvnet.substance.utils.SubstanceConstants.Side;
039:
040: /**
041: * Base button shaper. Provides common functionality that can be used by actual
042: * button shapers. This class is part of officially supported API.
043: *
044: * @author Kirill Grouchnikov
045: */
046: public abstract class BaseButtonShaper implements SubstanceButtonShaper {
047: /**
048: * Returns basic outline for the specified button. The basic outline is a
049: * rectangle with rounded corners. Some corners may not be rounded based on
050: * the contents of <code>straightSide</code> parameter.
051: *
052: * @param button
053: * A button.
054: * @param radius
055: * Corner radius.
056: * @param straightSides
057: * Contains all sides which are straight.
058: * @return The basic outline for the specified parameters.
059: */
060: public static GeneralPath getBaseOutline(AbstractButton button,
061: float radius, Set<Side> straightSides) {
062: int width = button.getWidth();
063: int height = button.getHeight();
064:
065: return getBaseOutline(width, height, radius, straightSides);
066: }
067:
068: /**
069: * Returns basic outline for the specified parameters. The basic outline is
070: * a rectangle with rounded corners. Some corners may not be rounded based
071: * on the contents of <code>straightSide</code> parameter.
072: *
073: * @param width
074: * Width of some UI component.
075: * @param height
076: * Height of some UI component.
077: * @param radius
078: * Corner radius.
079: * @param straightSides
080: * Contains all sides which are straight.
081: * @return The basic outline for the specified parameters.
082: */
083: public static GeneralPath getBaseOutline(int width, int height,
084: float radius, Set<Side> straightSides) {
085: return getBaseOutline(width, height, radius, straightSides,
086: null);
087: }
088:
089: /**
090: * Returns basic outline for the specified parameters. The basic outline is
091: * a rectangle with rounded corners. Some corners may not be rounded based
092: * on the contents of <code>straightSides</code> parameter.
093: *
094: * @param width
095: * Width of some UI component.
096: * @param height
097: * Height of some UI component.
098: * @param radius
099: * Corner radius.
100: * @param straightSides
101: * Contains all sides which are straight.
102: * @param insets
103: * Shape insets.
104: * @return The basic outline for the specified parameters.
105: */
106: public static GeneralPath getBaseOutline(int width, int height,
107: float radius, Set<Side> straightSides, int insets) {
108: return getBaseOutline(width, height, radius, straightSides,
109: new Insets(insets, insets, insets, insets));
110: }
111:
112: /**
113: * Returns basic outline for the specified parameters. The basic outline is
114: * a rectangle with rounded corners. Some corners may not be rounded based
115: * on the contents of <code>straightSides</code> parameter.
116: *
117: * @param width
118: * Width of some UI component.
119: * @param height
120: * Height of some UI component.
121: * @param radius
122: * Corner radius.
123: * @param straightSides
124: * Contains all sides which are straight.
125: * @param insets
126: * Shape insets.
127: * @return The basic outline for the specified parameters.
128: */
129: public static GeneralPath getBaseOutline(int width, int height,
130: float radius, Set<Side> straightSides, Insets insets) {
131: boolean isTopLeftCorner = (straightSides != null)
132: && (straightSides.contains(Side.LEFT) || straightSides
133: .contains(Side.TOP));
134: boolean isTopRightCorner = (straightSides != null)
135: && (straightSides.contains(Side.RIGHT) || straightSides
136: .contains(Side.TOP));
137: boolean isBottomRightCorner = (straightSides != null)
138: && (straightSides.contains(Side.RIGHT) || straightSides
139: .contains(Side.BOTTOM));
140: boolean isBottomLeftCorner = (straightSides != null)
141: && (straightSides.contains(Side.LEFT) || straightSides
142: .contains(Side.BOTTOM));
143:
144: int xs = (insets == null) ? 0 : insets.left;
145: int ys = (insets == null) ? 0 : insets.top;
146: if (insets != null) {
147: width -= (insets.right + insets.left);
148: }
149: if (insets != null) {
150: height -= (insets.top + insets.bottom);
151: }
152:
153: GeneralPath result = new GeneralPath();
154: float radius3 = (float) (radius / (1.5 * Math.pow(height, 0.5)));
155: if (Math.max(width, height) < 15)
156: radius3 /= 2;
157:
158: if (isTopLeftCorner) {
159: result.moveTo(xs, ys);
160: } else {
161: result.moveTo(xs + radius, ys);
162: }
163:
164: if (isTopRightCorner) {
165: result.lineTo(xs + width - 1, ys);
166: } else {
167: if (isTopLeftCorner
168: || ((xs + width - radius - 1) >= radius)) {
169: result.lineTo(xs + width - radius - 1, ys);
170: }
171: result.quadTo(xs + width - 1 - radius3, ys + radius3, xs
172: + width - 1, ys + radius);
173: }
174:
175: if (isBottomRightCorner) {
176: result.lineTo(xs + width - 1, ys + height - 1);
177: } else {
178: if (isTopRightCorner
179: || ((ys + height - radius - 1) >= radius)) {
180: result.lineTo(xs + width - 1, ys + height - radius - 1);
181: }
182: result
183: .quadTo(xs + width - 1 - radius3, ys + height - 1
184: - radius3, xs + width - radius - 1, ys
185: + height - 1);
186: }
187:
188: if (isBottomLeftCorner) {
189: result.lineTo(xs, ys + height - 1);
190: } else {
191: if (isBottomRightCorner
192: || ((xs + width - radius - 1) >= radius)) {
193: result.lineTo(xs + radius, ys + height - 1);
194: }
195: result.quadTo(xs + radius3, ys + height - 1 - radius3, xs,
196: ys + height - radius - 1);
197: }
198:
199: if (isTopLeftCorner) {
200: result.lineTo(xs, ys);
201: } else {
202: if (isBottomLeftCorner
203: || ((ys + height - radius - 1) >= radius)) {
204: result.lineTo(xs, ys + radius);
205: }
206: result.quadTo(xs + radius3, ys + radius3, xs + radius, ys);
207: }
208:
209: return result;
210: }
211:
212: /**
213: * Returns outline that has a triangle poiting downwards. The top two
214: * corners in the outline are rounded. This function can be used to draw
215: * slider thumbs.
216: *
217: * @param width
218: * Width of some UI component.
219: * @param height
220: * Height of some UI component.
221: * @param radius
222: * Corner radius for the top two corners.
223: * @param insets
224: * Insets to compute the outline.
225: * @return Outline that has a triangle poiting downwards.
226: */
227: public static GeneralPath getTriangleButtonOutline(int width,
228: int height, float radius, int insets) {
229: return getTriangleButtonOutline(width, height, radius,
230: new Insets(insets, insets, insets, insets));
231:
232: }
233:
234: /**
235: * Returns outline that has a triangle poiting downwards. The top two
236: * corners in the outline are rounded. This function can be used to draw
237: * slider thumbs.
238: *
239: * @param width
240: * Width of some UI component.
241: * @param height
242: * Height of some UI component.
243: * @param radius
244: * Corner radius for the top two corners.
245: * @param insets
246: * Insets to compute the outline.
247: * @return Outline that has a triangle poiting downwards.
248: */
249: public static GeneralPath getTriangleButtonOutline(int width,
250: int height, float radius, Insets insets) {
251:
252: int xs = (insets == null) ? 0 : insets.left;
253: int ys = (insets == null) ? 0 : insets.top;
254: int xe = (insets == null) ? width : width - insets.right;
255: int ye = (insets == null) ? height : height - insets.bottom;
256: if (insets != null) {
257: width -= (insets.right + insets.left);
258: height -= (insets.top + insets.bottom);
259: }
260:
261: GeneralPath result = new GeneralPath();
262: float radius3 = (float) (radius / (1.5 * Math.pow(height, 0.5)));
263: if (Math.max(width, height) < 15)
264: radius3 /= 2;
265:
266: result.moveTo(radius + xs, ys);
267:
268: if ((xe - radius - 1) >= radius) {
269: result.lineTo(xe - radius - 1, ys);
270: }
271: result.quadTo(xe - 1 - radius3, xs + radius3, xe - 1, xs
272: + radius);
273:
274: float h2 = (ye - 1.0f) / 2.0f;
275: if (h2 >= radius) {
276: result.lineTo(xe - 1, h2);
277: }
278:
279: result.lineTo((xe - 1.f) / 2, ye - 1);
280: result.lineTo(xs, h2);
281:
282: if (h2 >= radius) {
283: result.lineTo(xs, h2);
284: }
285:
286: if ((height - radius - 1) >= radius) {
287: result.lineTo(xs, radius + ys);
288: }
289: result.quadTo(xs + radius3, ys + radius3, xs + radius, ys);
290:
291: return result;
292: }
293:
294: /*
295: * (non-Javadoc)
296: *
297: * @see org.jvnet.substance.button.SubstanceButtonShaper#getButtonOutline(javax.swing.AbstractButton,
298: * java.awt.Insets)
299: */
300: public GeneralPath getButtonOutline(AbstractButton button,
301: Insets insets) {
302: return this .getButtonOutline(button, insets, button.getWidth(),
303: button.getHeight());
304: }
305:
306: /*
307: * (non-Javadoc)
308: *
309: * @see org.jvnet.substance.button.SubstanceButtonShaper#getButtonOutline(javax.swing.AbstractButton)
310: */
311: public GeneralPath getButtonOutline(AbstractButton button) {
312: return this.getButtonOutline(button, null);
313: }
314: }
|