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.*;
033: import java.awt.geom.GeneralPath;
034: import java.util.Map;
035: import java.util.Set;
036:
037: import javax.swing.AbstractButton;
038: import javax.swing.Icon;
039: import javax.swing.border.Border;
040:
041: import org.jvnet.substance.SubstanceButtonBorder;
042: import org.jvnet.substance.SubstanceLookAndFeel;
043: import org.jvnet.substance.utils.*;
044: import org.jvnet.substance.utils.SubstanceConstants.Side;
045:
046: /**
047: * Button shaper that returns buttons with completely rounded corners (ala Mac
048: * 10.4). This class is part of officially supported API.
049: *
050: * @author Kirill Grouchnikov
051: */
052: public class StandardButtonShaper extends BaseButtonShaper implements
053: RectangularButtonShaper {
054: // /**
055: // * The default width of button
056: // */
057: // public static final int DEFAULT_WIDTH = 70;
058: //
059: // /**
060: // * The default height of button
061: // */
062: // public static final int DEFAULT_HEIGHT = 20;
063:
064: /**
065: * Cache of already computed contours.
066: */
067: public static Map<String, GeneralPath> contours = new SoftHashMap<String, GeneralPath>();
068:
069: /*
070: * (non-Javadoc)
071: *
072: * @see org.jvnet.substance.button.SubstanceButtonShaper#getDisplayName()
073: */
074: public String getDisplayName() {
075: return "Standard";
076: }
077:
078: /*
079: * (non-Javadoc)
080: *
081: * @see org.jvnet.substance.button.SubstanceButtonShaper#getButtonOutline(javax.swing.AbstractButton,
082: * java.awt.Insets, int, int)
083: */
084: public GeneralPath getButtonOutline(AbstractButton button,
085: Insets insets, int width, int height) {
086: Set<SubstanceConstants.Side> straightSides = SubstanceCoreUtilities
087: .getSides(button,
088: SubstanceLookAndFeel.BUTTON_SIDE_PROPERTY);
089:
090: float radius = this .getCornerRadius(button, insets);
091: String key = width + ":" + height + ":";
092: if (straightSides != null) {
093: for (Side side : straightSides)
094: key += (side + ":");
095: }
096: key += radius + ":";
097: key += (insets == null) ? "null" : insets.toString();
098:
099: GeneralPath result = contours.get(key);
100: if (result != null) {
101: return result;
102: }
103:
104: result = getBaseOutline(width, height, radius, straightSides,
105: insets);
106: contours.put(key, result);
107: return result;
108: }
109:
110: /*
111: * (non-Javadoc)
112: *
113: * @see org.jvnet.substance.button.SubstanceButtonShaper#getButtonBorder(javax.swing.AbstractButton)
114: */
115: public Border getButtonBorder(AbstractButton button) {
116: return new SubstanceButtonBorder(StandardButtonShaper.class) {
117: public Insets getBorderInsets(Component c) {
118: int extraPadding = SubstanceSizeUtils
119: .getExtraPadding(SubstanceSizeUtils
120: .getComponentFontSize(c));
121: if (c instanceof AbstractButton) {
122: AbstractButton button = (AbstractButton) c;
123: if (SubstanceCoreUtilities.hasText(button)) {
124: int dh = SubstanceSizeUtils
125: .getMinButtonHeight(SubstanceSizeUtils
126: .getComponentFontSize(button));
127: return new Insets(extraPadding, extraPadding
128: + dh / 2, extraPadding, extraPadding
129: + dh / 2);
130: }
131: }
132: return new Insets(extraPadding, extraPadding,
133: extraPadding, extraPadding);
134: }
135: };
136: }
137:
138: /*
139: * (non-Javadoc)
140: *
141: * @see org.jvnet.substance.button.SubstanceButtonShaper#getPreferredSize(javax.swing.AbstractButton,
142: * java.awt.Dimension)
143: */
144: public Dimension getPreferredSize(AbstractButton button,
145: Dimension uiPreferredSize) {
146: Dimension result;
147: boolean toTweakWidth = false;
148: boolean toTweakHeight = false;
149:
150: Icon icon = button.getIcon();
151: boolean hasIcon = SubstanceCoreUtilities.hasIcon(button);
152: boolean hasText = SubstanceCoreUtilities.hasText(button);
153: Insets margin = button.getMargin();
154:
155: result = uiPreferredSize;
156:
157: boolean hasNoMinSizeProperty = SubstanceCoreUtilities
158: .hasNoMinSizeProperty(button);
159: if ((!hasNoMinSizeProperty) && hasText) {
160: int baseWidth = uiPreferredSize.width;
161: baseWidth = Math.max(baseWidth, SubstanceSizeUtils
162: .getMinButtonWidth(SubstanceSizeUtils
163: .getComponentFontSize(button)));
164: // if (baseWidth < DEFAULT_WIDTH) {
165: // baseWidth = DEFAULT_WIDTH;
166: // }
167: result = new Dimension(baseWidth, uiPreferredSize.height);
168: int baseHeight = result.height;
169: baseHeight = Math.max(baseHeight, SubstanceSizeUtils
170: .getMinButtonHeight(SubstanceSizeUtils
171: .getComponentFontSize(button)));
172: result = new Dimension(result.width, baseHeight);
173: } else {
174: if (hasNoMinSizeProperty) {
175: if (margin != null) {
176: result = new Dimension(result.width + margin.left
177: + margin.right, result.height + margin.top
178: + margin.bottom);
179: }
180: }
181: }
182:
183: int extraPadding = SubstanceSizeUtils
184: .getExtraPadding(SubstanceSizeUtils
185: .getComponentFontSize(button));
186: int iconPaddingWidth = 6 + 2 * extraPadding;
187: int iconPaddingHeight = 6 + 2 * extraPadding;
188: if (margin != null) {
189: iconPaddingWidth = Math.max(iconPaddingWidth, margin.left
190: + margin.right);
191: iconPaddingHeight = Math.max(iconPaddingHeight, margin.top
192: + margin.bottom);
193: }
194: if (hasIcon) {
195: // check the icon height
196: int iconHeight = icon.getIconHeight();
197: if (iconHeight > (result.getHeight() - iconPaddingHeight)) {
198: result = new Dimension(result.width, iconHeight);
199: toTweakHeight = true;
200: }
201: int iconWidth = icon.getIconWidth();
202: if (iconWidth > (result.getWidth() - iconPaddingWidth)) {
203: result = new Dimension(iconWidth, result.height);
204: toTweakWidth = true;
205: }
206: }
207:
208: if (SubstanceCoreUtilities.isScrollBarButton(button)) {
209: toTweakWidth = false;
210: toTweakHeight = false;
211: }
212:
213: if (toTweakWidth) {
214: result = new Dimension(result.width + iconPaddingWidth,
215: result.height);
216: }
217: if (toTweakHeight) {
218: result = new Dimension(result.width, result.height
219: + iconPaddingHeight);
220: }
221:
222: if (result.height % 2 == 1)
223: result.height++;
224:
225: return result;
226: }
227:
228: /**
229: * Returns indication whether the specified button should be drawn with
230: * completely round corners.
231: *
232: * @param button
233: * A button.
234: * @return <code>true</code> if the specified button should be drawn with
235: * completely round corners, <code>false</code> otherwise.
236: */
237: public static boolean isRoundButton(AbstractButton button) {
238: return (!SubstanceCoreUtilities.isComboBoxButton(button))
239: && (!SubstanceCoreUtilities.isScrollButton(button))
240: && SubstanceCoreUtilities.hasText(button);
241: }
242:
243: /*
244: * (non-Javadoc)
245: *
246: * @see org.jvnet.substance.button.SubstanceButtonShaper#isProportionate()
247: */
248: public boolean isProportionate() {
249: return true;
250: }
251:
252: /*
253: * (non-Javadoc)
254: *
255: * @see org.jvnet.substance.button.RectangularButtonShaper#getCornerRadius(javax.swing.AbstractButton,
256: * java.awt.Insets)
257: */
258: public float getCornerRadius(AbstractButton button, Insets insets) {
259: int width = button.getWidth();
260: int height = button.getHeight();
261:
262: boolean isRoundCorners = isRoundButton(button);
263: float radius = SubstanceSizeUtils
264: .getClassicButtonCornerRadius(SubstanceSizeUtils
265: .getComponentFontSize(button));
266: if (insets != null) {
267: width -= (insets.left + insets.right);
268: height -= (insets.top + insets.bottom);
269: }
270: if (isRoundCorners) {
271: if (width > height) {
272: radius = (height) / 2.0f;
273: } else {
274: radius = (width) / 2.0f;
275: }
276: }
277:
278: if (SubstanceCoreUtilities.isToolBarButton(button)) {
279: radius = SubstanceCoreUtilities
280: .getToolbarButtonCornerRadius(button, insets);
281: }
282: return radius;
283: }
284: }
|