2
* Copyright (c) 2005-2010 Substance Kirill Grouchnikov. All Rights Reserved.
4
* Redistribution and use in source and binary forms, with or without
5
* modification, are permitted provided that the following conditions are met:
7
* o Redistributions of source code must retain the above copyright notice,
8
* this list of conditions and the following disclaimer.
10
* o Redistributions in binary form must reproduce the above copyright notice,
11
* this list of conditions and the following disclaimer in the documentation
12
* and/or other materials provided with the distribution.
14
* o Neither the name of Substance Kirill Grouchnikov nor the names of
15
* its contributors may be used to endorse or promote products derived
16
* from this software without specific prior written permission.
18
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
22
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
package org.pushingpixels.substance.internal.ui;
32
import java.awt.Component;
33
import java.awt.Dimension;
35
import java.awt.FontMetrics;
36
import java.awt.Graphics;
37
import java.awt.Graphics2D;
38
import java.awt.Insets;
39
import java.awt.Rectangle;
40
import java.awt.event.MouseEvent;
41
import java.beans.PropertyChangeEvent;
42
import java.beans.PropertyChangeListener;
44
import javax.swing.AbstractButton;
45
import javax.swing.Icon;
46
import javax.swing.JCheckBox;
47
import javax.swing.JComponent;
48
import javax.swing.JRadioButton;
49
import javax.swing.JToggleButton;
50
import javax.swing.LookAndFeel;
51
import javax.swing.SwingUtilities;
52
import javax.swing.border.Border;
53
import javax.swing.plaf.ComponentUI;
54
import javax.swing.plaf.basic.BasicButtonListener;
55
import javax.swing.plaf.basic.BasicHTML;
56
import javax.swing.plaf.basic.BasicToggleButtonUI;
57
import javax.swing.text.View;
59
import org.pushingpixels.lafwidget.LafWidgetUtilities;
60
import org.pushingpixels.lafwidget.animation.AnimationConfigurationManager;
61
import org.pushingpixels.lafwidget.animation.AnimationFacet;
62
import org.pushingpixels.substance.api.SubstanceLookAndFeel;
63
import org.pushingpixels.substance.api.shaper.SubstanceButtonShaper;
64
import org.pushingpixels.substance.internal.animation.StateTransitionTracker;
65
import org.pushingpixels.substance.internal.animation.TransitionAwareUI;
66
import org.pushingpixels.substance.internal.utils.ButtonBackgroundDelegate;
67
import org.pushingpixels.substance.internal.utils.ButtonVisualStateTracker;
68
import org.pushingpixels.substance.internal.utils.SubstanceCoreUtilities;
69
import org.pushingpixels.substance.internal.utils.SubstanceSizeUtils;
70
import org.pushingpixels.substance.internal.utils.SubstanceTextUtilities;
71
import org.pushingpixels.substance.internal.utils.border.SubstanceButtonBorder;
72
import org.pushingpixels.substance.internal.utils.icon.GlowingIcon;
75
* UI for toggle buttons in <b>Substance</b> look and feel.
77
* @author Kirill Grouchnikov
79
public class SubstanceToggleButtonUI extends BasicToggleButtonUI implements
84
private ButtonBackgroundDelegate delegate;
87
* The matching glowing icon. Is used only when
88
* {@link AnimationConfigurationManager#isAnimationAllowed(AnimationFacet, Component)}
89
* returns true on {@link AnimationFacet#ICON_GLOW}.
91
protected GlowingIcon glowingIcon;
94
* Property change listener. Listens on changes to the
95
* {@link SubstanceLookAndFeel#BUTTON_SHAPER_PROPERTY} property and
96
* {@link AbstractButton#MODEL_CHANGED_PROPERTY} property.
98
protected PropertyChangeListener substancePropertyListener;
101
* Tracker for visual state transitions.
103
protected ButtonVisualStateTracker substanceVisualStateTracker;
105
protected JToggleButton toggleButton;
107
private Rectangle viewRect = new Rectangle();
109
private Rectangle iconRect = new Rectangle();
111
private Rectangle textRect = new Rectangle();
116
* @see javax.swing.plaf.ComponentUI#createUI(javax.swing.JComponent)
118
public static ComponentUI createUI(JComponent comp) {
119
SubstanceCoreUtilities.testComponentCreationThreadingViolation(comp);
120
return new SubstanceToggleButtonUI((JToggleButton) comp);
124
* Simple constructor.
126
public SubstanceToggleButtonUI(JToggleButton toggleButton) {
127
this.toggleButton = toggleButton;
128
this.delegate = new ButtonBackgroundDelegate();
134
* @seejavax.swing.plaf.basic.BasicButtonUI#installDefaults(javax.swing.
138
public void installDefaults(AbstractButton b) {
139
super.installDefaults(b);
140
if (b.getClientProperty(SubstanceButtonUI.BORDER_ORIGINAL) == null)
141
b.putClientProperty(SubstanceButtonUI.BORDER_ORIGINAL, b
144
if (b.getClientProperty(SubstanceButtonUI.BORDER_ORIGINAL) == null)
145
b.putClientProperty(SubstanceButtonUI.BORDER_ORIGINAL, b
148
SubstanceButtonShaper shaper = SubstanceCoreUtilities
151
if (b.getClientProperty(SubstanceButtonUI.BORDER_COMPUTED) == null) {
152
b.setBorder(shaper.getButtonBorder(b));
154
Border currBorder = b.getBorder();
155
if (!(currBorder instanceof SubstanceButtonBorder)) {
156
b.setBorder(shaper.getButtonBorder(b));
158
SubstanceButtonBorder sbCurrBorder = (SubstanceButtonBorder) currBorder;
159
if (shaper.getClass() != sbCurrBorder.getButtonShaperClass())
160
b.setBorder(shaper.getButtonBorder(b));
163
b.putClientProperty(SubstanceButtonUI.OPACITY_ORIGINAL, b.isOpaque());
164
// fix for defect 140
167
b.setRolloverEnabled(true);
169
LookAndFeel.installProperty(b, "iconTextGap", SubstanceSizeUtils
170
.getTextIconGap(SubstanceSizeUtils.getComponentFontSize(b)));
176
* @seejavax.swing.plaf.basic.BasicButtonUI#uninstallDefaults(javax.swing.
180
public void uninstallDefaults(AbstractButton b) {
181
super.uninstallDefaults(b);
183
b.setBorder((Border) b
184
.getClientProperty(SubstanceButtonUI.BORDER_ORIGINAL));
185
b.setOpaque((Boolean) b
186
.getClientProperty(SubstanceButtonUI.OPACITY_ORIGINAL));
187
b.putClientProperty(SubstanceButtonUI.OPACITY_ORIGINAL, null);
194
* javax.swing.plaf.basic.BasicButtonUI#createButtonListener(javax.swing
198
protected BasicButtonListener createButtonListener(AbstractButton b) {
205
* @seejavax.swing.plaf.basic.BasicButtonUI#installListeners(javax.swing.
209
protected void installListeners(final AbstractButton b) {
210
super.installListeners(b);
212
this.substanceVisualStateTracker = new ButtonVisualStateTracker();
213
this.substanceVisualStateTracker.installListeners(b, true);
215
this.trackGlowingIcon();
217
this.substancePropertyListener = new PropertyChangeListener() {
219
public void propertyChange(PropertyChangeEvent evt) {
220
if (AbstractButton.ICON_CHANGED_PROPERTY.equals(evt
221
.getPropertyName())) {
226
b.addPropertyChangeListener(this.substancePropertyListener);
232
* @seejavax.swing.plaf.basic.BasicButtonUI#uninstallListeners(javax.swing.
236
protected void uninstallListeners(AbstractButton b) {
237
this.substanceVisualStateTracker.uninstallListeners(b);
238
this.substanceVisualStateTracker = null;
240
b.removePropertyChangeListener(this.substancePropertyListener);
241
this.substancePropertyListener = null;
243
super.uninstallListeners(b);
249
* @see javax.swing.plaf.basic.BasicToggleButtonUI#paint(java.awt.Graphics,
250
* javax.swing.JComponent)
253
public void paint(Graphics g, JComponent c) {
254
final AbstractButton b = (AbstractButton) c;
256
FontMetrics fm = g.getFontMetrics();
258
Insets i = c.getInsets();
262
viewRect.width = b.getWidth() - (i.right + viewRect.x);
263
viewRect.height = b.getHeight() - (i.bottom + viewRect.y);
265
textRect.x = textRect.y = textRect.width = textRect.height = 0;
266
iconRect.x = iconRect.y = iconRect.width = iconRect.height = 0;
268
Font f = c.getFont();
270
// layout the text and icon
271
String text = SwingUtilities.layoutCompoundLabel(c, fm, b.getText(), b
272
.getIcon(), b.getVerticalAlignment(), b
273
.getHorizontalAlignment(), b.getVerticalTextPosition(), b
274
.getHorizontalTextPosition(), viewRect, iconRect, textRect, b
275
.getText() == null ? 0 : b.getIconTextGap());
277
Graphics2D g2d = (Graphics2D) g.create();
279
View v = (View) c.getClientProperty(BasicHTML.propertyKey);
282
this.delegate.updateBackground(g2d, b);
284
v.paint(g2d, textRect);
286
this.paintButtonText(g2d, b, textRect, text);
290
if (b.getIcon() != null) {
291
paintIcon(g2d, b, iconRect);
294
if (b.isFocusPainted()) {
295
SubstanceCoreUtilities.paintFocus(g, b, b, this, null, textRect,
296
1.0f, SubstanceSizeUtils
297
.getFocusRingPadding(SubstanceSizeUtils
298
.getComponentFontSize(b)));
306
* javax.swing.plaf.ComponentUI#getPreferredSize(javax.swing.JComponent)
309
public Dimension getPreferredSize(JComponent c) {
310
AbstractButton button = (AbstractButton) c;
311
SubstanceButtonShaper shaper = SubstanceCoreUtilities
312
.getButtonShaper(button);
314
// fix for defect 263
315
Dimension superPref = super.getPreferredSize(button);
316
if (superPref == null)
322
return shaper.getPreferredSize(button, superPref);
328
* @see javax.swing.plaf.ComponentUI#contains(javax.swing.JComponent, int,
332
public boolean contains(JComponent c, int x, int y) {
333
return ButtonBackgroundDelegate.contains((JToggleButton) c, x, y);
340
* javax.swing.plaf.basic.BasicToggleButtonUI#paintIcon(java.awt.Graphics,
341
* javax.swing.AbstractButton, java.awt.Rectangle)
344
protected void paintIcon(Graphics g, AbstractButton b, Rectangle iconRect) {
345
Graphics2D graphics = (Graphics2D) g.create();
346
// We have three types of icons:
347
// 1. The original button icon
348
// 2. The themed version of 1.
349
// 3. The glowing version of 1.
350
Icon originalIcon = SubstanceCoreUtilities.getOriginalIcon(b, b
352
Icon themedIcon = (!(b instanceof JRadioButton)
353
&& !(b instanceof JCheckBox) && SubstanceCoreUtilities
354
.useThemedDefaultIcon(b)) ? SubstanceCoreUtilities
355
.getThemedIcon(b, originalIcon) : originalIcon;
357
graphics.setComposite(LafWidgetUtilities.getAlphaComposite(b, g));
358
float activeAmount = this.substanceVisualStateTracker
359
.getStateTransitionTracker().getActiveStrength();
360
if (activeAmount >= 0.0f) {
361
if (AnimationConfigurationManager.getInstance().isAnimationAllowed(
362
AnimationFacet.ICON_GLOW, b)
363
&& this.substanceVisualStateTracker
364
.getStateTransitionTracker().getIconGlowTracker()
366
this.glowingIcon.paintIcon(b, graphics, iconRect.x, iconRect.y);
368
themedIcon.paintIcon(b, graphics, iconRect.x, iconRect.y);
369
graphics.setComposite(LafWidgetUtilities.getAlphaComposite(b,
371
originalIcon.paintIcon(b, graphics, iconRect.x, iconRect.y);
374
originalIcon.paintIcon(b, graphics, iconRect.x, iconRect.y);
392
protected void paintButtonText(Graphics g, AbstractButton button,
393
Rectangle textRect, String text) {
394
SubstanceTextUtilities.paintText(g, button, textRect, text, (button)
395
.getDisplayedMnemonicIndex());
399
* Tracks possible usage of glowing icon.
402
protected void trackGlowingIcon() {
403
Icon currIcon = this.toggleButton.getIcon();
404
if (currIcon instanceof GlowingIcon)
406
if (currIcon == null)
408
this.glowingIcon = new GlowingIcon(currIcon,
409
this.substanceVisualStateTracker.getStateTransitionTracker()
410
.getIconGlowTracker());
416
* @see javax.swing.plaf.ComponentUI#update(java.awt.Graphics,
417
* javax.swing.JComponent)
420
public void update(Graphics g, JComponent c) {
425
public boolean isInside(MouseEvent me) {
426
return this.contains(this.toggleButton, me.getX(), me.getY());
430
public StateTransitionTracker getTransitionTracker() {
431
return this.substanceVisualStateTracker.getStateTransitionTracker();
b'\\ No newline at end of file'