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.BasicCommandToggleButtonUI;
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.painter.text.SubstanceTextPainter;
052: import org.jvnet.substance.theme.SubstanceTheme;
053: import org.jvnet.substance.utils.*;
054:
055: /**
056: * UI for command buttons {@link JCommandToggleButton} in <b>Substance </b> look
057: * and feel.
058: *
059: * @author Kirill Grouchnikov
060: */
061: public class SubstanceCommandToggleButtonUI extends
062: BasicCommandToggleButtonUI {
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 SubstanceCommandToggleButtonUI();
097: }
098:
099: /**
100: * Creates a new UI delegate for ribbon button.
101: */
102: public SubstanceCommandToggleButtonUI() {
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 (SubstanceCommandToggleButtonUI.this .substanceFadeStateListener != null)
157: SubstanceCommandToggleButtonUI.this .substanceFadeStateListener
158: .unregisterListeners();
159: SubstanceCommandToggleButtonUI.this .substanceFadeStateListener = new FadeStateListener(
160: SubstanceCommandToggleButtonUI.this .commandButton,
161: SubstanceCommandToggleButtonUI.this .commandButton
162: .getModel(), null);
163: SubstanceCommandToggleButtonUI.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: // System.out.println("Painting button background "
235: // + commandButton.getName());
236: if (textPainter.needsBackgroundImage()) {
237: // TODO : check correct alpha for flat buttons and translucent
238: // themes
239: // textPainter.setBackgroundImage(this.commandButton,
240: // this.commandButton.getParent().getBackground(), true, 0, 0);
241: if (this .isPaintingBackground()) {
242: textPainter
243: .attachCallback(new SubstanceTextPainter.BackgroundPaintingCallback() {
244: public void paintBackground(Graphics g) {
245: Graphics2D g2d = (Graphics2D) g
246: .create();
247: // System.out.println("Painting background "
248: // + commandButton.getName());
249: backgroundDelegate.updateBackground(
250: g2d, commandButton);
251: // g2d.setColor(Color.red);
252: // g2d.fillRect(0, 0, 20, 20);
253: // System.out.println(g2d.getClip());
254: // System.out.println(((AlphaComposite) g2d
255: // .getComposite()).getAlpha());
256: // g2d.dispose();
257: };
258: });
259: }
260: } else {
261: this .backgroundDelegate.updateBackground(g,
262: this .commandButton);
263: }
264:
265: Graphics2D graphics = (Graphics2D) g.create();
266: GhostPaintingUtils.paintGhostIcon(graphics, this .commandButton,
267: this .commandButton.getIcon());
268: graphics.dispose();
269: }
270:
271: /*
272: * (non-Javadoc)
273: *
274: * @see org.jvnet.flamingo.ribbon.ui.BasiccommandButtonUI#paintButtonIcon(java.awt.Graphics,
275: * java.awt.Rectangle)
276: */
277: @Override
278: protected void paintButtonIcon(Graphics g, Rectangle iconRect) {
279: Icon icon = this .getIconToPaint();
280: if (icon != null) {
281: Graphics2D g2d = (Graphics2D) g.create();
282: g2d.setComposite(TransitionLayout.getAlphaComposite(
283: this .commandButton, g));
284: FadeTracker fadeTracker = FadeTracker.getInstance();
285: if (fadeTracker.isTracked(this .commandButton,
286: FadeKind.ROLLOVER)) {
287: ComponentState state = ComponentState.getState(
288: this .commandButton.getModel(),
289: this .commandButton);
290: if (state.isKindActive(FadeKind.ROLLOVER)) {// ==
291: // Came from default state
292: getActiveIcon(this .commandButton.getIcon(),
293: this .commandButton,
294: this .commandButton.getModel(), true)
295: .paintIcon(this .commandButton, g2d,
296: iconRect.x, iconRect.y);
297: g2d.setComposite(TransitionLayout
298: .getAlphaComposite(this .commandButton,
299: fadeTracker.getFade10(
300: this .commandButton,
301: FadeKind.ROLLOVER) / 10.0f,
302: g));
303: icon.paintIcon(this .commandButton, g2d, iconRect.x,
304: iconRect.y);
305: } else {
306: // Came from rollover state
307: icon.paintIcon(this .commandButton, g2d, iconRect.x,
308: iconRect.y);
309: g2d.setComposite(TransitionLayout
310: .getAlphaComposite(this .commandButton,
311: fadeTracker.getFade10(
312: this .commandButton,
313: FadeKind.ROLLOVER) / 10.0f,
314: g));
315: this .commandButton.getIcon().paintIcon(
316: this .commandButton, g2d, iconRect.x,
317: iconRect.y);
318: }
319: } else {
320: icon.paintIcon(this .commandButton, g2d, iconRect.x,
321: iconRect.y);
322: }
323: g2d.dispose();
324: }
325: }
326:
327: /*
328: * (non-Javadoc)
329: *
330: * @see org.jvnet.flamingo.ribbon.ui.BasiccommandButtonUI#getIconToPaint()
331: */
332: @Override
333: protected Icon getIconToPaint() {
334: return getActiveIcon(this .commandButton.getIcon(),
335: this .commandButton, this .commandButton.getModel(),
336: false);
337: }
338:
339: private Icon getActiveIcon(Icon origIcon, JComponent comp,
340: ButtonModel model, boolean ignoreRolloverSetting) {
341: if (origIcon == null)
342: return null;
343: Icon result = origIcon;
344: if (SubstanceCoreUtilities.useThemedDefaultIcon(comp)) {
345: boolean useThemedVersion = !model.isArmed()
346: && !model.isPressed() && !model.isSelected();
347: if (!ignoreRolloverSetting)
348: useThemedVersion = useThemedVersion
349: && !model.isRollover();
350: if (useThemedVersion) {
351: result = new ImageIcon(SubstanceImageCreator
352: .getThemeImage(comp, result,
353: SubstanceThemeUtilities.getTheme(comp,
354: ComponentState.DEFAULT), false));
355: }
356: }
357: return result;
358: }
359:
360: /*
361: * (non-Javadoc)
362: *
363: * @see org.jvnet.flamingo.common.ui.BasicCommandButtonUI#isPaintingBackground()
364: */
365: @Override
366: protected boolean isPaintingBackground() {
367: if (super .isPaintingBackground())
368: return true;
369: return FadeTracker.getInstance().isTracked(this .commandButton,
370: FadeKind.ROLLOVER);
371: }
372:
373: /*
374: * (non-Javadoc)
375: *
376: * @see org.jvnet.flamingo.common.ui.BasicCommandButtonUI#isPaintingSeparators()
377: */
378: @Override
379: protected boolean isPaintingSeparators() {
380: return false;
381: }
382:
383: /*
384: * (non-Javadoc)
385: *
386: * @see org.jvnet.flamingo.common.ui.BasicCommandButtonUI#paint(java.awt.Graphics,
387: * javax.swing.JComponent)
388: */
389: @Override
390: public void paint(Graphics g, JComponent c) {
391: Graphics2D g2d = (Graphics2D) g.create();
392: SubstanceTextPainter textPainter = SubstanceLookAndFeel
393: .getCurrentTextPainter();
394: textPainter.init(c, null, false);
395:
396: // if (this.isPaintingBackground()) {
397: this .paintButtonBackground(g2d, new Rectangle(0, 0, c
398: .getWidth(), c.getHeight()));
399: // } else {
400: // if (textPainter.needsBackgroundImage()) {
401: // textPainter.setBackgroundImage(this.commandButton,
402: // this.commandButton.getParent().getBackground(), true,
403: // 0, 0);
404: // }
405: // }
406:
407: g2d.setFont(FlamingoUtilities.getFont("Ribbon.font",
408: "Button.font", "Panel.font"));
409:
410: JCommandButton.CommandButtonKind buttonKind = (commandButton instanceof JCommandButton) ? ((JCommandButton) commandButton)
411: .getCommandButtonKind()
412: : JCommandButton.CommandButtonKind.ACTION_ONLY;
413:
414: this .actionClickArea = new Rectangle(0, 0, 0, 0);
415: this .popupClickArea = new Rectangle(0, 0, 0, 0);
416:
417: Rectangle iconRect = new Rectangle();
418: Rectangle bigLabel1Rect = new Rectangle();
419: Rectangle bigLabel2Rect = new Rectangle();
420: Rectangle midLabelRect = new Rectangle();
421: Rectangle midExtraLabelRect = new Rectangle();
422: Rectangle actionArrowLabelRect = new Rectangle();
423:
424: layoutButtonComponents(g2d, c, buttonKind, iconRect,
425: bigLabel1Rect, bigLabel2Rect, midLabelRect,
426: midExtraLabelRect, actionArrowLabelRect);
427:
428: ComponentState state = ComponentState.getState(
429: this .commandButton.getModel(), this .commandButton);
430: ComponentState prevState = SubstanceCoreUtilities
431: .getPrevComponentState(this .commandButton);
432:
433: // compute color scheme
434: SubstanceTheme theme = SubstanceThemeUtilities.getTheme(
435: this .commandButton, state);
436:
437: Color fgColor = this .commandButton.getForeground();
438: if (fgColor instanceof UIResource) {
439: fgColor = SubstanceCoreUtilities
440: .getInterpolatedForegroundColor(this .commandButton,
441: null, theme, state, prevState,
442: FadeKind.ROLLOVER, FadeKind.SELECTION,
443: FadeKind.PRESS);
444: }
445:
446: int mnemonicIndex = this .commandButton
447: .getDisplayedMnemonicIndex();
448: if (bigLabel1Rect.getWidth() > 0) {
449: int firstMnemonicIndex = -1;
450: if ((mnemonicIndex >= 0)
451: && (mnemonicIndex <= titlePart1.length())) {
452: firstMnemonicIndex = mnemonicIndex;
453: }
454: textPainter.attachText(c, bigLabel1Rect, titlePart1,
455: firstMnemonicIndex, g2d.getFont(), fgColor, g2d
456: .getClipBounds());
457: }
458: if (bigLabel2Rect.getWidth() > 0) {
459: int secondMnemonicIndex = -1;
460: if ((mnemonicIndex >= 0)
461: && (mnemonicIndex > titlePart1.length())) {
462: secondMnemonicIndex = mnemonicIndex
463: - titlePart1.length() - 1;
464: }
465: textPainter.attachText(c, bigLabel2Rect, titlePart2,
466: secondMnemonicIndex, g2d.getFont(), fgColor, g2d
467: .getClipBounds());
468: }
469: if (midLabelRect.getWidth() > 0) {
470: String str = this .commandButton.getTitle();
471: str = FlamingoUtilities.clipString(g.getFontMetrics(),
472: midLabelRect.width, str);
473: int xDelta = 0;
474: int width = g.getFontMetrics().stringWidth(str);
475: if (commandButton.getState() == ElementState.BIG_FIXED_LANDSCAPE) {
476: Insets ins = c.getInsets();
477: int availableWidth = c.getWidth() - ins.left
478: - ins.right;
479: xDelta = (availableWidth - width) / 2;
480: }
481: textPainter.attachText(c, new Rectangle(xDelta
482: + midLabelRect.x, midLabelRect.y, width,
483: midLabelRect.height),
484: this .commandButton.getTitle(), mnemonicIndex, g2d
485: .getFont(), fgColor, g2d.getClipBounds());
486: }
487: if (midExtraLabelRect.getWidth() > 0) {
488: Color disabledFgColor = SubstanceThemeUtilities.getTheme(
489: this .commandButton,
490: ComponentState.DISABLED_UNSELECTED)
491: .getForegroundColor();
492: textPainter.attachText(c, midExtraLabelRect,
493: this .commandButton.getExtraText(), -1, g2d
494: .getFont(), disabledFgColor, g2d
495: .getClipBounds());
496: }
497: textPainter.renderSurface(g2d);
498: // textPainter.paintText(g2d, this.commandButton, textLines);
499:
500: if (iconRect != null) {
501: this .paintButtonIcon(g2d, iconRect);
502: }
503: if (actionArrowLabelRect.getWidth() > 0) {
504: actionIcon.paintIcon(this .commandButton, g2d,
505: actionArrowLabelRect.x, actionArrowLabelRect.y);
506: }
507: if (buttonKind.isHasAction() && buttonKind.isHasPopup()
508: && this .isPaintingSeparators()
509: && (actionClickArea.width > 0)
510: && (popupClickArea.width > 0)) {
511: switch (commandButton.getState()) {
512: case CUSTOM:
513: case BIG:
514: case ORIG:
515: this.paintButtonHorizontalSeparator(g2d,
516: actionClickArea.height);
517: break;
518: default:
519: this.paintButtonVerticalSeparator(g2d,
520: actionClickArea.width);
521: }
522: }
523: g2d.dispose();
524: }
525: }
|