001: /*
002: * Copyright (c) 2005-2008 Flamingo / 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 Flamingo 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.flamingo.common.ui;
031:
032: import java.awt.*;
033: import java.beans.PropertyChangeEvent;
034: import java.beans.PropertyChangeListener;
035:
036: import javax.swing.*;
037: import javax.swing.plaf.*;
038:
039: import org.jvnet.flamingo.common.*;
040: import org.jvnet.flamingo.common.ui.BasicCommandButtonUI;
041: import org.jvnet.flamingo.common.ui.BasicPopupButtonListener;
042: import org.jvnet.flamingo.utils.FlamingoUtilities;
043: import org.jvnet.lafwidget.animation.*;
044: import org.jvnet.lafwidget.animation.effects.GhostPaintingUtils;
045: import org.jvnet.lafwidget.animation.effects.GhostingListener;
046: import org.jvnet.lafwidget.layout.TransitionLayout;
047: import org.jvnet.substance.SubstanceImageCreator;
048: import org.jvnet.substance.SubstanceLookAndFeel;
049: import org.jvnet.substance.button.ClassicButtonShaper;
050: import org.jvnet.substance.button.SubstanceButtonShaper;
051: import org.jvnet.substance.color.ColorScheme;
052: import org.jvnet.substance.painter.text.SubstanceTextPainter;
053: import org.jvnet.substance.theme.SubstanceTheme;
054: import org.jvnet.substance.utils.*;
055:
056: /**
057: * UI for command buttons {@link JCommandButton} in <b>Substance </b> look and
058: * feel.
059: *
060: * @author Kirill Grouchnikov
061: */
062: public class SubstanceCommandButtonUI extends BasicCommandButtonUI {
063: /**
064: * Delegate for painting the background.
065: */
066: protected ButtonBackgroundDelegate backgroundDelegate;
067:
068: /**
069: * The rollover button listener.
070: */
071: // private RolloverButtonListener substanceButtonListener;
072: /**
073: * Listener for fade animations.
074: */
075: protected FadeStateListener substanceFadeStateListener;
076:
077: /**
078: * Property change listener. Listens on changes to
079: * {@link AbstractButton#MODEL_CHANGED_PROPERTY} property.
080: */
081: protected PropertyChangeListener substancePropertyListener;
082:
083: /**
084: * Model change listener for ghost image effects.
085: */
086: private GhostingListener substanceModelChangeListener;
087:
088: private static SubstanceButtonShaper shaper = new ClassicButtonShaper();
089:
090: /*
091: * (non-Javadoc)
092: *
093: * @see javax.swing.plaf.ComponentUI#createUI(javax.swing.JComponent)
094: */
095: public static ComponentUI createUI(JComponent c) {
096: return new SubstanceCommandButtonUI();
097: }
098:
099: /**
100: * Creates a new UI delegate for ribbon button.
101: */
102: public SubstanceCommandButtonUI() {
103: super ();
104: this .backgroundDelegate = new ButtonBackgroundDelegate();
105: }
106:
107: /*
108: * (non-Javadoc)
109: *
110: * @see org.jvnet.flamingo.ribbon.ui.BasiccommandButtonUI#installDefaults()
111: */
112: @Override
113: protected void installDefaults() {
114: super .installDefaults();
115: this .commandButton.putClientProperty(
116: SubstanceLookAndFeel.FLAT_PROPERTY, Boolean.TRUE);
117: this .commandButton.putClientProperty(
118: SubstanceLookAndFeel.BUTTON_SHAPER_PROPERTY, shaper);
119: this .commandButton.setRolloverEnabled(true);
120:
121: Insets extra = SubstanceSizeUtils
122: .getDefaultBorderInsets(SubstanceSizeUtils
123: .getComponentFontSize(this .commandButton));
124: this .commandButton
125: .setBorder(new BorderUIResource.EmptyBorderUIResource(
126: 2 + extra.top, 4 + extra.left,
127: 2 + extra.bottom, 4 + extra.right));
128: }
129:
130: /*
131: * (non-Javadoc)
132: *
133: * @see org.jvnet.flamingo.ribbon.ui.BasiccommandButtonUI#installListeners()
134: */
135: @Override
136: protected void installListeners() {
137: super .installListeners();
138:
139: // this.substanceButtonListener = new RolloverButtonListener(
140: // this.commandButton);
141: // this.commandButton.addMouseListener(this.substanceButtonListener);
142: // this.commandButton.addMouseMotionListener(this.substanceButtonListener);
143: // this.commandButton.addFocusListener(this.substanceButtonListener);
144: // this.commandButton
145: // .addPropertyChangeListener(this.substanceButtonListener);
146: // this.commandButton.addChangeListener(this.substanceButtonListener);
147:
148: this .substanceFadeStateListener = new FadeStateListener(
149: this .commandButton, this .commandButton.getModel(), null);
150: this .substanceFadeStateListener.registerListeners();
151:
152: this .substancePropertyListener = new PropertyChangeListener() {
153: public void propertyChange(PropertyChangeEvent evt) {
154: if (AbstractButton.MODEL_CHANGED_PROPERTY.equals(evt
155: .getPropertyName())) {
156: if (SubstanceCommandButtonUI.this .substanceFadeStateListener != null)
157: SubstanceCommandButtonUI.this .substanceFadeStateListener
158: .unregisterListeners();
159: SubstanceCommandButtonUI.this .substanceFadeStateListener = new FadeStateListener(
160: SubstanceCommandButtonUI.this .commandButton,
161: SubstanceCommandButtonUI.this .commandButton
162: .getModel(), null);
163: SubstanceCommandButtonUI.this .substanceFadeStateListener
164: .registerListeners();
165:
166: if (substanceModelChangeListener != null)
167: substanceModelChangeListener
168: .unregisterListeners();
169: substanceModelChangeListener = new GhostingListener(
170: commandButton, commandButton.getModel());
171: substanceModelChangeListener.registerListeners();
172: }
173: }
174: };
175: this .commandButton
176: .addPropertyChangeListener(this .substancePropertyListener);
177:
178: this .substanceModelChangeListener = new GhostingListener(
179: this .commandButton, this .commandButton.getModel());
180: this .substanceModelChangeListener.registerListeners();
181: }
182:
183: /*
184: * (non-Javadoc)
185: *
186: * @see org.jvnet.flamingo.ribbon.ui.BasiccommandButtonUI#uninstallListeners()
187: */
188: @Override
189: protected void uninstallListeners() {
190: // this.commandButton.removeMouseListener(this.substanceButtonListener);
191: // this.commandButton
192: // .removeMouseMotionListener(this.substanceButtonListener);
193: // this.commandButton.removeFocusListener(this.substanceButtonListener);
194: // this.commandButton
195: // .removePropertyChangeListener(this.substanceButtonListener);
196: // this.commandButton.removeChangeListener(this.substanceButtonListener);
197: // this.substanceButtonListener = null;
198:
199: this .substanceFadeStateListener.unregisterListeners();
200: this .substanceFadeStateListener = null;
201:
202: this .commandButton
203: .removePropertyChangeListener(this .substancePropertyListener);
204: this .substancePropertyListener = null;
205:
206: this .substanceModelChangeListener.unregisterListeners();
207: this .substanceModelChangeListener = null;
208:
209: super .uninstallListeners();
210: }
211:
212: /*
213: * (non-Javadoc)
214: *
215: * @see org.jvnet.flamingo.common.ui.BasicCommandButtonUI#createButtonListener(org.jvnet.flamingo.common.AbstractCommandButton)
216: */
217: @Override
218: protected BasicPopupButtonListener createButtonListener(
219: AbstractCommandButton b) {
220: return new RolloverPopupButtonListener(b);
221: }
222:
223: /*
224: * (non-Javadoc)
225: *
226: * @see org.jvnet.flamingo.ribbon.ui.BasiccommandButtonUI#paintButtonBackground(java.awt.Graphics,
227: * java.awt.Rectangle)
228: */
229: @Override
230: protected void paintButtonBackground(Graphics g, Rectangle toFill) {
231: SubstanceTextPainter textPainter = SubstanceLookAndFeel
232: .getCurrentTextPainter();
233:
234: if (textPainter.needsBackgroundImage()) {
235: // TODO : check correct alpha for flat buttons and translucent
236: // themes
237: textPainter.setBackgroundFill(this .commandButton,
238: this .commandButton.getParent().getBackground(),
239: true, 0, 0);
240: textPainter
241: .attachCallback(new SubstanceTextPainter.BackgroundPaintingCallback() {
242: public void paintBackground(Graphics g) {
243: backgroundDelegate.updateBackground(g,
244: commandButton);
245: };
246: });
247: } else {
248: this .backgroundDelegate.updateBackground(g,
249: this .commandButton);
250: }
251:
252: Graphics2D graphics = (Graphics2D) g.create();
253: GhostPaintingUtils.paintGhostIcon(graphics, this .commandButton,
254: this .commandButton.getIcon());
255: graphics.dispose();
256: }
257:
258: /*
259: * (non-Javadoc)
260: *
261: * @see org.jvnet.flamingo.ribbon.ui.BasiccommandButtonUI#paintButtonIcon(java.awt.Graphics,
262: * java.awt.Rectangle)
263: */
264: @Override
265: protected void paintButtonIcon(Graphics g, Rectangle iconRect) {
266: Icon icon = this .getIconToPaint();
267: if (icon != null) {
268: Graphics2D g2d = (Graphics2D) g.create();
269: g2d.setComposite(TransitionLayout.getAlphaComposite(
270: this .commandButton, g));
271: FadeTracker fadeTracker = FadeTracker.getInstance();
272: if (fadeTracker.isTracked(this .commandButton,
273: FadeKind.ROLLOVER)) {
274: ComponentState state = ComponentState.getState(
275: this .commandButton.getModel(),
276: this .commandButton);
277: if (state.isKindActive(FadeKind.ROLLOVER)) {// ==
278: // Came from default state
279: getActiveIcon(this .commandButton.getIcon(),
280: this .commandButton,
281: this .commandButton.getModel(), true)
282: .paintIcon(this .commandButton, g2d,
283: iconRect.x, iconRect.y);
284: g2d.setComposite(TransitionLayout
285: .getAlphaComposite(this .commandButton,
286: fadeTracker.getFade10(
287: this .commandButton,
288: FadeKind.ROLLOVER) / 10.0f,
289: g));
290: icon.paintIcon(this .commandButton, g2d, iconRect.x,
291: iconRect.y);
292: } else {
293: // Came from rollover state
294: icon.paintIcon(this .commandButton, g2d, iconRect.x,
295: iconRect.y);
296: g2d.setComposite(TransitionLayout
297: .getAlphaComposite(this .commandButton,
298: fadeTracker.getFade10(
299: this .commandButton,
300: FadeKind.ROLLOVER) / 10.0f,
301: g));
302: this .commandButton.getIcon().paintIcon(
303: this .commandButton, g2d, iconRect.x,
304: iconRect.y);
305: }
306: } else {
307: icon.paintIcon(this .commandButton, g2d, iconRect.x,
308: iconRect.y);
309: }
310: g2d.dispose();
311: }
312: }
313:
314: /*
315: * (non-Javadoc)
316: *
317: * @see org.jvnet.flamingo.ribbon.ui.BasiccommandButtonUI#getIconToPaint()
318: */
319: @Override
320: protected Icon getIconToPaint() {
321: return getActiveIcon(this .commandButton.getIcon(),
322: this .commandButton, this .commandButton.getModel(),
323: false);
324: }
325:
326: private Icon getActiveIcon(Icon origIcon, JComponent comp,
327: ButtonModel model, boolean ignoreRolloverSetting) {
328: if (origIcon == null)
329: return null;
330: Icon result = origIcon;
331: if (SubstanceCoreUtilities.useThemedDefaultIcon(comp)) {
332: boolean useThemedVersion = !model.isArmed()
333: && !model.isPressed() && !model.isSelected();
334: if (!ignoreRolloverSetting)
335: useThemedVersion = useThemedVersion
336: && !model.isRollover();
337: if (useThemedVersion) {
338: result = new ImageIcon(SubstanceImageCreator
339: .getThemeImage(comp, result,
340: SubstanceThemeUtilities.getTheme(comp,
341: ComponentState.DEFAULT), false));
342: }
343: }
344: return result;
345: }
346:
347: @Override
348: protected void paintButtonHorizontalSeparator(Graphics graphics,
349: int separatorY) {
350: Graphics2D g2d = (Graphics2D) graphics.create();
351: g2d.translate(0, separatorY);
352:
353: SubstanceTheme theme = SubstanceThemeUtilities
354: .getTheme(this .commandButton);
355: boolean isDark = SubstanceCoreUtilities.isThemeDark(theme
356: .getActiveTheme());
357: ColorScheme colorScheme = theme.getActiveTheme()
358: .getColorScheme();
359:
360: ComponentState state = ComponentState.getState(
361: this .commandButton.getModel(), this .commandButton);
362: if (FadeTracker.getInstance().isTracked(this .commandButton,
363: FadeKind.ROLLOVER)
364: && !state.isKindActive(FadeKind.SELECTION)
365: && state.isKindActive(FadeKind.ENABLE)) {
366: float fadeCoef = FadeTracker.getInstance().getFade10(
367: this .commandButton, FadeKind.ROLLOVER);
368: g2d.setComposite(AlphaComposite.getInstance(
369: AlphaComposite.SRC_OVER, fadeCoef / 10.0f));
370: }
371:
372: SubstanceCoreUtilities.paintSeparator(this .commandButton, g2d,
373: colorScheme, isDark, this .commandButton.getWidth(), 1,
374: JSlider.HORIZONTAL, true, 4);
375:
376: g2d.dispose();
377: }
378:
379: @Override
380: protected void paintButtonVerticalSeparator(Graphics graphics,
381: int separatorX) {
382: Graphics2D g2d = (Graphics2D) graphics.create();
383: g2d.translate(separatorX, 0);
384:
385: SubstanceTheme theme = SubstanceThemeUtilities
386: .getTheme(this .commandButton);
387: boolean isDark = SubstanceCoreUtilities.isThemeDark(theme
388: .getActiveTheme());
389: ColorScheme colorScheme = theme.getActiveTheme()
390: .getColorScheme();
391:
392: ComponentState state = ComponentState.getState(
393: this .commandButton.getModel(), this .commandButton);
394: if (FadeTracker.getInstance().isTracked(this .commandButton,
395: FadeKind.ROLLOVER)
396: && !state.isKindActive(FadeKind.SELECTION)
397: && state.isKindActive(FadeKind.ENABLE)) {
398: float fadeCoef = FadeTracker.getInstance().getFade10(
399: this .commandButton, FadeKind.ROLLOVER);
400: g2d.setComposite(AlphaComposite.getInstance(
401: AlphaComposite.SRC_OVER, fadeCoef / 10.0f));
402: }
403:
404: SubstanceCoreUtilities.paintSeparator(this .commandButton, g2d,
405: colorScheme, isDark, 1, this .commandButton.getHeight(),
406: JSlider.VERTICAL, true, 4);
407:
408: g2d.dispose();
409: }
410:
411: /*
412: * (non-Javadoc)
413: *
414: * @see org.jvnet.flamingo.common.ui.BasicCommandButtonUI#isPaintingBackground()
415: */
416: @Override
417: protected boolean isPaintingBackground() {
418: if (super .isPaintingBackground())
419: return true;
420: return FadeTracker.getInstance().isTracked(this .commandButton,
421: FadeKind.ROLLOVER);
422: }
423:
424: /*
425: * (non-Javadoc)
426: *
427: * @see org.jvnet.flamingo.common.ui.BasicCommandButtonUI#isPaintingSeparators()
428: */
429: @Override
430: protected boolean isPaintingSeparators() {
431: if (super .isPaintingSeparators())
432: return true;
433: return FadeTracker.getInstance().isTracked(this .commandButton,
434: FadeKind.ROLLOVER);
435: }
436:
437: /*
438: * (non-Javadoc)
439: *
440: * @see org.jvnet.flamingo.common.ui.BasicCommandButtonUI#paint(java.awt.Graphics,
441: * javax.swing.JComponent)
442: */
443: @Override
444: public void paint(Graphics g, JComponent c) {
445: Graphics2D g2d = (Graphics2D) g.create();
446: SubstanceTextPainter textPainter = SubstanceLookAndFeel
447: .getCurrentTextPainter();
448: textPainter.init(c, null, false);
449:
450: // if (this.isPaintingBackground()) {
451: this .paintButtonBackground(g2d, new Rectangle(0, 0, c
452: .getWidth(), c.getHeight()));
453: // } else {
454: // if (textPainter.needsBackgroundImage()) {
455: // textPainter.setBackgroundImage(this.commandButton,
456: // this.commandButton.getParent().getBackground(), true,
457: // 0, 0);
458: // }
459: // }
460:
461: g2d.setFont(FlamingoUtilities.getFont("Ribbon.font",
462: "Button.font", "Panel.font"));
463:
464: JCommandButton.CommandButtonKind buttonKind = (commandButton instanceof JCommandButton) ? ((JCommandButton) commandButton)
465: .getCommandButtonKind()
466: : JCommandButton.CommandButtonKind.ACTION_ONLY;
467:
468: this .actionClickArea = new Rectangle(0, 0, 0, 0);
469: this .popupClickArea = new Rectangle(0, 0, 0, 0);
470:
471: Rectangle iconRect = new Rectangle();
472: Rectangle bigLabel1Rect = new Rectangle();
473: Rectangle bigLabel2Rect = new Rectangle();
474: Rectangle midLabelRect = new Rectangle();
475: Rectangle midExtraLabelRect = new Rectangle();
476: Rectangle actionArrowLabelRect = new Rectangle();
477:
478: layoutButtonComponents(g2d, c, buttonKind, iconRect,
479: bigLabel1Rect, bigLabel2Rect, midLabelRect,
480: midExtraLabelRect, actionArrowLabelRect);
481:
482: ComponentState state = ComponentState.getState(
483: this .commandButton.getModel(), this .commandButton);
484: ComponentState prevState = SubstanceCoreUtilities
485: .getPrevComponentState(this .commandButton);
486:
487: // compute color scheme
488: SubstanceTheme theme = SubstanceThemeUtilities.getTheme(
489: this .commandButton, state);
490:
491: Color fgColor = this .commandButton.getForeground();
492: if (fgColor instanceof UIResource) {
493: fgColor = SubstanceCoreUtilities
494: .getInterpolatedForegroundColor(this .commandButton,
495: null, theme, state, prevState,
496: FadeKind.ROLLOVER, FadeKind.SELECTION,
497: FadeKind.PRESS);
498: }
499:
500: int mnemonicIndex = this .commandButton
501: .getDisplayedMnemonicIndex();
502: if (bigLabel1Rect.getWidth() > 0) {
503: int firstMnemonicIndex = -1;
504: if ((mnemonicIndex >= 0)
505: && (mnemonicIndex <= titlePart1.length())) {
506: firstMnemonicIndex = mnemonicIndex;
507: }
508: textPainter.attachText(c, bigLabel1Rect, titlePart1,
509: firstMnemonicIndex, g2d.getFont(), fgColor, g2d
510: .getClipBounds());
511: }
512: if (bigLabel2Rect.getWidth() > 0) {
513: int secondMnemonicIndex = -1;
514: if ((mnemonicIndex >= 0)
515: && (mnemonicIndex > titlePart1.length())) {
516: secondMnemonicIndex = mnemonicIndex
517: - titlePart1.length() - 1;
518: }
519: textPainter.attachText(c, bigLabel2Rect, titlePart2,
520: secondMnemonicIndex, g2d.getFont(), fgColor, g2d
521: .getClipBounds());
522: }
523: if (midLabelRect.getWidth() > 0) {
524: String str = this .commandButton.getTitle();
525: str = FlamingoUtilities.clipString(g.getFontMetrics(),
526: midLabelRect.width, str);
527: int xDelta = 0;
528: int width = g.getFontMetrics().stringWidth(str);
529: if (commandButton.getState() == ElementState.BIG_FIXED_LANDSCAPE) {
530: Insets ins = c.getInsets();
531: int availableWidth = c.getWidth() - ins.left
532: - ins.right;
533: xDelta = (availableWidth - width) / 2;
534: }
535: textPainter.attachText(c, new Rectangle(xDelta
536: + midLabelRect.x, midLabelRect.y, width,
537: midLabelRect.height),
538: this .commandButton.getTitle(), mnemonicIndex, g2d
539: .getFont(), fgColor, g2d.getClipBounds());
540: }
541: if (midExtraLabelRect.getWidth() > 0) {
542: Color disabledFgColor = SubstanceThemeUtilities.getTheme(
543: this .commandButton,
544: ComponentState.DISABLED_UNSELECTED)
545: .getForegroundColor();
546: textPainter.attachText(c, midExtraLabelRect,
547: this .commandButton.getExtraText(), -1, g2d
548: .getFont(), disabledFgColor, g2d
549: .getClipBounds());
550: }
551: textPainter.renderSurface(g2d);
552: // textPainter.paintText(g2d, this.commandButton, textLines);
553:
554: if (iconRect != null) {
555: this .paintButtonIcon(g2d, iconRect);
556: }
557: if (actionArrowLabelRect.getWidth() > 0) {
558: actionIcon.paintIcon(this .commandButton, g2d,
559: actionArrowLabelRect.x, actionArrowLabelRect.y);
560: }
561: if (buttonKind.isHasAction() && buttonKind.isHasPopup()
562: && this .isPaintingSeparators()
563: && (actionClickArea.width > 0)
564: && (popupClickArea.width > 0)) {
565: switch (commandButton.getState()) {
566: case CUSTOM:
567: case BIG:
568: case ORIG:
569: this.paintButtonHorizontalSeparator(g2d,
570: actionClickArea.height);
571: break;
572: default:
573: this.paintButtonVerticalSeparator(g2d,
574: actionClickArea.width);
575: }
576: }
577: g2d.dispose();
578: }
579: }
|