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;
031:
032: import java.awt.*;
033:
034: import javax.swing.AbstractButton;
035: import javax.swing.UIManager;
036: import javax.swing.border.Border;
037: import javax.swing.plaf.UIResource;
038:
039: import org.jvnet.lafwidget.animation.FadeKind;
040: import org.jvnet.lafwidget.animation.FadeTracker;
041: import org.jvnet.lafwidget.layout.TransitionLayout;
042: import org.jvnet.substance.theme.SubstanceTheme;
043: import org.jvnet.substance.utils.*;
044:
045: /**
046: * Gradient border for the <b>Substance</b> look and feel. This class is <b>for
047: * internal use only</b>.
048: *
049: * @author Kirill Grouchnikov
050: */
051: public class SubstanceBorder implements Border, UIResource {
052: /**
053: * Insets of <code>this</code> border.
054: */
055: protected Insets myInsets;
056:
057: /**
058: * Border opacity.
059: */
060: protected float alpha;
061:
062: /**
063: * When the border is painted, the default radius is multiplied by this
064: * factor.
065: */
066: protected float radiusFactor;
067:
068: /**
069: * Creates a new border with dynamic insets (computed at the invocation time
070: * of {@link #getBorderInsets(Component)} call).
071: */
072: public SubstanceBorder() {
073: super ();
074: this .alpha = 1.0f;
075: this .radiusFactor = 0.5f;
076: }
077:
078: /**
079: * Creates a new border with dynamic insets (computed at the invocation time
080: * of {@link #getBorderInsets(Component)} call).
081: *
082: * @param radiusFactor
083: * Radius factor.
084: */
085: public SubstanceBorder(float radiusFactor) {
086: this ();
087: this .radiusFactor = radiusFactor;
088: }
089:
090: /**
091: * Creates a new border with the specified insets.
092: *
093: * @param insets
094: * Insets.
095: */
096: public SubstanceBorder(Insets insets) {
097: this ();
098: this .myInsets = new Insets(insets.top, insets.left,
099: insets.bottom, insets.right);
100: }
101:
102: /**
103: * Sets the alpha for this border.
104: *
105: * @param alpha
106: * Alpha factor.
107: */
108: public void setAlpha(float alpha) {
109: this .alpha = alpha;
110: }
111:
112: /**
113: * Paints border instance for the specified component.
114: *
115: * @param c
116: * The component.
117: * @param g
118: * Graphics context.
119: * @param x
120: * Component left X (in graphics context).
121: * @param y
122: * Component top Y (in graphics context).
123: * @param width
124: * Component width.
125: * @param height
126: * Component height.
127: * @param isEnabled
128: * Component enabled status.
129: * @param hasFocus
130: * Component focus ownership status.
131: * @param alpha
132: * Alpha value.
133: */
134: private void paintBorder(Component c, Graphics g, int x, int y,
135: int width, int height, boolean isEnabled, boolean hasFocus,
136: float alpha) {
137: // failsafe for LAF change
138: if (!(UIManager.getLookAndFeel() instanceof SubstanceLookAndFeel)) {
139: return;
140: }
141:
142: Graphics2D graphics = (Graphics2D) g.create();
143: graphics.setComposite(TransitionLayout.getAlphaComposite(c,
144: alpha, g));
145:
146: // SubstanceTheme theme1 = null;
147: // SubstanceTheme theme2 = null;
148: float cyclePos = 1.0f;
149:
150: FadeTracker fadeTracker = FadeTracker.getInstance();
151: boolean isFocusAnimated = fadeTracker.isTracked(c,
152: FadeKind.FOCUS);
153: boolean isBorderAnimated = fadeTracker.isTracked(c,
154: SubstanceLookAndFeel.BORDER_ANIMATION_KIND);
155:
156: float radius = this .radiusFactor
157: * SubstanceSizeUtils
158: .getClassicButtonCornerRadius(SubstanceSizeUtils
159: .getComponentFontSize(c));
160: if (isFocusAnimated || isBorderAnimated || c.hasFocus()) {
161: // SubstanceTheme controlActiveTheme = SubstanceCoreUtilities
162: // .getTheme(c, ComponentState.ACTIVE, true, true);
163: // SubstanceTheme controlDefaultTheme = SubstanceCoreUtilities
164: // .getTheme(c, ComponentState.DEFAULT, true, true);
165: // theme1 = controlDefaultTheme;
166: // theme2 = controlActiveTheme;
167: if (isFocusAnimated) {
168: cyclePos = fadeTracker.getFade10(c, FadeKind.FOCUS) / 10.f;
169: } else {
170: if (isBorderAnimated) {
171: cyclePos = fadeTracker.getFade10(c,
172: SubstanceLookAndFeel.BORDER_ANIMATION_KIND) / 10.f;
173: } else {
174: cyclePos = 1.0f;
175: }
176: }
177:
178: SubstanceImageCreator.paintBorder(c, graphics, x, y, width,
179: height, radius, SubstanceThemeUtilities.getTheme(c,
180: ComponentState.DEFAULT));
181: if (cyclePos > 0.0f) {
182: graphics.setComposite(TransitionLayout
183: .getAlphaComposite(c, cyclePos * alpha, g));
184: SubstanceImageCreator.paintBorder(c, graphics, x, y,
185: width, height, radius, SubstanceThemeUtilities
186: .getTheme(c, ComponentState.SELECTED));
187: }
188: // if (c.hasFocus()) {
189: // System.out.println(c.getClass().getSimpleName() + ":"
190: // + cyclePos);
191: // }
192: } else {
193: if (isEnabled) {
194: SubstanceImageCreator.paintBorder(c, graphics, x, y,
195: width, height, radius, SubstanceThemeUtilities
196: .getTheme(c, ComponentState.DEFAULT));
197: } else {
198: SubstanceTheme controlDisabledTheme = SubstanceThemeUtilities
199: .getTheme(c, ComponentState.DISABLED_UNSELECTED);
200:
201: // TODO: remove the following check when the borders
202: // of buttons, toggle buttons and check marks are painted
203: // in a separate flow
204:
205: float disabledTrans = 1.0f;
206: if (!(c instanceof AbstractButton)) {
207: disabledTrans = SubstanceThemeUtilities.getTheme(c)
208: .getThemeAlpha(c,
209: ComponentState.DISABLED_SELECTED);
210: }
211: Graphics2D tempGr = (Graphics2D) graphics.create();
212: tempGr.setComposite(TransitionLayout.getAlphaComposite(
213: c, disabledTrans, graphics));
214: SubstanceImageCreator.paintBorder(c, tempGr, x, y,
215: width, height, radius, controlDisabledTheme);
216: tempGr.dispose();
217: }
218: }
219: if (fadeTracker.isTracked(c, FadeKind.FOCUS_LOOP_ANIMATION)) {
220: float coef = 0.4f;
221: if (fadeTracker.isTracked(c, FadeKind.FOCUS))
222: coef = 0.4f * fadeTracker.getFade10(c, FadeKind.FOCUS) / 10.0f;
223: graphics.setComposite(TransitionLayout.getAlphaComposite(c,
224: coef * alpha, g));
225: int extraPadding = 2 + SubstanceSizeUtils
226: .getExtraPadding(SubstanceSizeUtils
227: .getComponentFontSize(c));
228: SubstanceCoreUtilities.paintFocus(graphics, c, c, null,
229: new Rectangle(1, 1, c.getWidth() - 1,
230: c.getHeight() - 1), coef, extraPadding);
231: }
232: graphics.dispose();
233: }
234:
235: /*
236: * (non-Javadoc)
237: *
238: * @see javax.swing.border.Border#paintBorder(java.awt.Component,
239: * java.awt.Graphics, int, int, int, int)
240: */
241: public void paintBorder(Component c, Graphics g, int x, int y,
242: int width, int height) {
243: paintBorder(c, g, x, y, width, height, c.isEnabled(), c
244: .hasFocus(), this .alpha);
245: }
246:
247: /*
248: * (non-Javadoc)
249: *
250: * @see javax.swing.border.Border#getBorderInsets(java.awt.Component)
251: */
252: public Insets getBorderInsets(Component c) {
253: if (this .myInsets == null) {
254: return SubstanceSizeUtils
255: .getDefaultBorderInsets(SubstanceSizeUtils
256: .getComponentFontSize(c));
257: }
258: return this .myInsets;
259: }
260:
261: /*
262: * (non-Javadoc)
263: *
264: * @see javax.swing.border.Border#isBorderOpaque()
265: */
266: public boolean isBorderOpaque() {
267: return false;
268: }
269: }
|