org.jdesktop.swingx.JXButton Maven / Gradle / Ivy
Show all versions of swingx-all Show documentation
/*
* $Id: JXButton.java 4257 2012-11-14 17:08:20Z kschaefe $
*
* Copyright 2006 Sun Microsystems, Inc., 4150 Network Circle,
* Santa Clara, California 95054, U.S.A. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package org.jdesktop.swingx;
import org.jdesktop.beans.JavaBean;
import org.jdesktop.swingx.graphics.FilterComposite;
import org.jdesktop.swingx.painter.AbstractPainter;
import org.jdesktop.swingx.painter.Painter;
import org.jdesktop.swingx.painter.PainterPaint;
import org.jdesktop.swingx.util.GraphicsUtilities;
import org.jdesktop.swingx.util.PaintUtils;
import javax.swing.Action;
import javax.swing.ButtonModel;
import javax.swing.CellRendererPane;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.SwingUtilities;
import javax.swing.plaf.basic.BasicGraphicsUtils;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
/**
* A {@link Painter} enabled subclass of {@link JButton}.
* This class supports setting the foreground and background painters of the button separately.
*
* For example, if you wanted to blur just the text on the button, and let everything else be
* handled by the UI delegate for your look and feel, then you could:
*
* JXButton b = new JXButton("Execute");
* AbstractPainter fgPainter = (AbstractPainter)b.getForegroundPainter();
* StackBlurFilter filter = new StackBlurFilter();
* fgPainter.setFilters(filter);
*
*
* If either the foreground painter or the background painter is set,
* then super.paintComponent() is not called. By setting both the foreground and background
* painters to null, you get exactly the same painting behavior as JButton.
*
* @author rbair
* @author rah003
* @author Jan Stola
* @author Karl George Schaefer
*/
@JavaBean
@SuppressWarnings("nls")
public class JXButton extends JButton implements BackgroundPaintable {
private class BackgroundButton extends JButton {
/**
* {@inheritDoc}
*/
@Override
public boolean isDefaultButton() {
return JXButton.this.isDefaultButton();
}
/**
* {@inheritDoc}
*/
@Override
public Icon getDisabledIcon() {
return null;
}
/**
* {@inheritDoc}
*/
@Override
public Icon getDisabledSelectedIcon() {
return null;
}
/**
* {@inheritDoc}
*/
@Override
public int getDisplayedMnemonicIndex() {
return -1;
}
/**
* {@inheritDoc}
*/
@Override
public int getHorizontalAlignment() {
return JXButton.this.getHorizontalAlignment();
}
/**
* {@inheritDoc}
*/
@Override
public int getHorizontalTextPosition() {
return JXButton.this.getHorizontalTextPosition();
}
/**
* {@inheritDoc}
*/
@Override
public Icon getIcon() {
return null;
}
/**
* {@inheritDoc}
*/
@Override
public int getIconTextGap() {
return JXButton.this.getIconTextGap();
}
/**
* {@inheritDoc}
*/
@Override
public Insets getMargin() {
return JXButton.this.getMargin();
}
/**
* {@inheritDoc}
*/
@Override
public int getMnemonic() {
return -1;
}
/**
* {@inheritDoc}
*/
@Override
public ButtonModel getModel() {
return JXButton.this.getModel();
}
/**
* {@inheritDoc}
*/
@Override
public Icon getPressedIcon() {
return null;
}
/**
* {@inheritDoc}
*/
@Override
public Icon getRolloverIcon() {
return null;
}
/**
* {@inheritDoc}
*/
@Override
public Icon getRolloverSelectedIcon() {
return null;
}
/**
* {@inheritDoc}
*/
@Override
public Icon getSelectedIcon() {
return null;
}
/**
* {@inheritDoc}
*/
@Override
public String getText() {
return "";
}
/**
* {@inheritDoc}
*/
@Override
public int getVerticalAlignment() {
return JXButton.this.getVerticalAlignment();
}
/**
* {@inheritDoc}
*/
@Override
public int getVerticalTextPosition() {
return JXButton.this.getVerticalTextPosition();
}
/**
* {@inheritDoc}
*/
@Override
public boolean isBorderPainted() {
return JXButton.this.isBorderPainted();
}
/**
* {@inheritDoc}
*/
@Override
public boolean isContentAreaFilled() {
return JXButton.this.isContentAreaFilled();
}
/**
* {@inheritDoc}
*/
@Override
public boolean isFocusPainted() {
return false;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isRolloverEnabled() {
return JXButton.this.isRolloverEnabled();
}
/**
* {@inheritDoc}
*/
@Override
public boolean isSelected() {
return JXButton.this.isSelected();
}
}
private class ForegroundButton extends JButton {
@Override
public Font getFont() {
return JXButton.this.getFont();
}
/**
* {@inheritDoc}
*/
@Override
public Color getForeground() {
if (fgPainter == null) {
return JXButton.this.getForeground();
}
return PaintUtils.setAlpha(JXButton.this.getForeground(), 0);
}
/**
* {@inheritDoc}
*/
@Override
public boolean isDefaultButton() {
return JXButton.this.isDefaultButton();
}
/**
* {@inheritDoc}
*/
@Override
public Icon getDisabledIcon() {
return JXButton.this.getDisabledIcon();
}
/**
* {@inheritDoc}
*/
@Override
public Icon getDisabledSelectedIcon() {
return JXButton.this.getDisabledSelectedIcon();
}
/**
* {@inheritDoc}
*/
@Override
public int getDisplayedMnemonicIndex() {
return JXButton.this.getDisplayedMnemonicIndex();
}
/**
* {@inheritDoc}
*/
@Override
public int getHorizontalAlignment() {
return JXButton.this.getHorizontalAlignment();
}
/**
* {@inheritDoc}
*/
@Override
public int getHorizontalTextPosition() {
return JXButton.this.getHorizontalTextPosition();
}
/**
* {@inheritDoc}
*/
@Override
public Icon getIcon() {
return JXButton.this.getIcon();
}
/**
* {@inheritDoc}
*/
@Override
public int getIconTextGap() {
return JXButton.this.getIconTextGap();
}
/**
* {@inheritDoc}
*/
@Override
public Insets getMargin() {
return JXButton.this.getMargin();
}
/**
* {@inheritDoc}
*/
@Override
public int getMnemonic() {
return JXButton.this.getMnemonic();
}
/**
* {@inheritDoc}
*/
@Override
public ButtonModel getModel() {
return JXButton.this.getModel();
}
/**
* {@inheritDoc}
*/
@Override
public Icon getPressedIcon() {
return JXButton.this.getPressedIcon();
}
/**
* {@inheritDoc}
*/
@Override
public Icon getRolloverIcon() {
return JXButton.this.getRolloverIcon();
}
/**
* {@inheritDoc}
*/
@Override
public Icon getRolloverSelectedIcon() {
return JXButton.this.getRolloverSelectedIcon();
}
/**
* {@inheritDoc}
*/
@Override
public Icon getSelectedIcon() {
return JXButton.this.getSelectedIcon();
}
/**
* {@inheritDoc}
*/
@Override
public String getText() {
return JXButton.this.getText();
}
/**
* {@inheritDoc}
*/
@Override
public int getVerticalAlignment() {
return JXButton.this.getVerticalAlignment();
}
/**
* {@inheritDoc}
*/
@Override
public int getVerticalTextPosition() {
return JXButton.this.getVerticalTextPosition();
}
/**
* {@inheritDoc}
*/
@Override
public boolean isBorderPainted() {
return JXButton.this.isBorderPainted();
}
/**
* {@inheritDoc}
*/
@Override
public boolean isContentAreaFilled() {
return false;
}
/**
* {@inheritDoc}
*/
@Override
public boolean hasFocus() {
return JXButton.this.hasFocus();
}
/**
* {@inheritDoc}
*/
@Override
public boolean isFocusPainted() {
return JXButton.this.isFocusPainted();
}
/**
* {@inheritDoc}
*/
@Override
public boolean isRolloverEnabled() {
return JXButton.this.isRolloverEnabled();
}
/**
* {@inheritDoc}
*/
@Override
public boolean isSelected() {
return JXButton.this.isSelected();
}
}
private ForegroundButton fgStamp;
@SuppressWarnings("rawtypes")
private Painter fgPainter;
@SuppressWarnings("rawtypes")
private PainterPaint fgPaint;
private BackgroundButton bgStamp;
@SuppressWarnings("rawtypes")
private Painter bgPainter;
private boolean paintBorderInsets = true;
private final Rectangle viewRect = new Rectangle();
private final Rectangle textRect = new Rectangle();
private final Rectangle iconRect = new Rectangle();
/**
* Creates a button with no set text or icon.
*/
public JXButton() {
init();
}
/**
* Creates a button with text.
*
* @param text the text of the button
*/
public JXButton(String text) {
super(text);
init();
}
/**
* Creates a button where properties are taken from the {@code Action} supplied.
*
* @param a the {@code Action} used to specify the new button
*/
public JXButton(Action a) {
super(a);
init();
}
/**
* Creates a button with an icon.
*
* @param icon the Icon image to display on the button
*/
public JXButton(Icon icon) {
super(icon);
init();
}
/**
* Creates a button with initial text and an icon.
*
* @param text the text of the button
* @param icon the Icon image to display on the button
*/
public JXButton(String text, Icon icon) {
super(text, icon);
init();
}
private void init() {
fgStamp = new ForegroundButton();
}
/**
* {@inheritDoc}
*/
@Override
@SuppressWarnings("rawtypes")
public Painter getBackgroundPainter() {
return bgPainter;
}
/**
* {@inheritDoc}
*/
@Override
@SuppressWarnings("rawtypes")
public void setBackgroundPainter(Painter p) {
Painter old = getBackgroundPainter();
this.bgPainter = p;
firePropertyChange("backgroundPainter", old, getBackgroundPainter());
repaint();
}
/**
* @return the foreground painter for this button
*/
@SuppressWarnings("rawtypes")
public Painter getForegroundPainter() {
return fgPainter;
}
@SuppressWarnings({"unchecked", "rawtypes"})
public void setForegroundPainter(Painter p) {
Painter old = getForegroundPainter();
this.fgPainter = p;
if (fgPainter == null) {
fgPaint = null;
} else {
fgPaint = new PainterPaint(fgPainter, this);
if (bgStamp == null) {
bgStamp = new BackgroundButton();
}
}
firePropertyChange("foregroundPainter", old, getForegroundPainter());
repaint();
}
/**
* Returns true if the background painter should paint where the border is
* or false if it should only paint inside the border. This property is
* true by default. This property affects the width, height,
* and initial transform passed to the background painter.
*/
@Override
public boolean isPaintBorderInsets() {
return paintBorderInsets;
}
/**
* Sets the paintBorderInsets property.
* Set to true if the background painter should paint where the border is
* or false if it should only paint inside the border. This property is true by default.
* This property affects the width, height,
* and initial transform passed to the background painter.
*
* This is a bound property.
*/
@Override
public void setPaintBorderInsets(boolean paintBorderInsets) {
boolean old = this.isPaintBorderInsets();
this.paintBorderInsets = paintBorderInsets;
firePropertyChange("paintBorderInsets", old, isPaintBorderInsets());
}
/**
* {@inheritDoc}
*/
@Override
public Dimension getPreferredSize() {
if (getComponentCount() == 1 && getComponent(0) instanceof CellRendererPane) {
return BasicGraphicsUtils.getPreferredButtonSize(fgStamp, getIconTextGap());
}
return super.getPreferredSize();
}
/**
* {@inheritDoc}
*/
@Override
protected void paintComponent(Graphics g) {
if (fgPainter == null && bgPainter == null) {
super.paintComponent(g);
} else {
if (fgPainter == null) {
Graphics2D g2d = (Graphics2D) g.create();
try {
paintWithoutForegroundPainter(g2d);
} finally {
g2d.dispose();
}
} else if (fgPainter instanceof AbstractPainter && ((AbstractPainter>) fgPainter).getFilters().length > 0) {
paintWithForegroundPainterWithFilters(g);
} else {
Graphics2D g2d = (Graphics2D) g.create();
try {
paintWithForegroundPainterWithoutFilters(g2d);
} finally {
g2d.dispose();
}
}
}
}
private void paintWithoutForegroundPainter(Graphics2D g2d) {
if (bgPainter == null) {
SwingUtilities.paintComponent(g2d, bgStamp, this, 0, 0, getWidth(), getHeight());
} else {
SwingXUtilities.paintBackground(this, g2d);
}
SwingUtilities.paintComponent(g2d, fgStamp, this, 0, 0, getWidth(), getHeight());
}
private void paintWithForegroundPainterWithoutFilters(Graphics2D g2d) {
paintWithoutForegroundPainter(g2d);
if (getText() != null && !getText().isEmpty()) {
Insets i = getInsets();
viewRect.x = i.left;
viewRect.y = i.top;
viewRect.width = getWidth() - (i.right + viewRect.x);
viewRect.height = getHeight() - (i.bottom + viewRect.y);
textRect.x = textRect.y = textRect.width = textRect.height = 0;
iconRect.x = iconRect.y = iconRect.width = iconRect.height = 0;
// layout the text and icon
String text = SwingUtilities.layoutCompoundLabel(
this, g2d.getFontMetrics(), getText(), getIcon(),
getVerticalAlignment(), getHorizontalAlignment(),
getVerticalTextPosition(), getHorizontalTextPosition(),
viewRect, iconRect, textRect,
getText() == null ? 0 : getIconTextGap()
);
if (!isPaintBorderInsets()) {
g2d.translate(i.left, i.top);
}
g2d.setPaint(fgPaint);
BasicGraphicsUtils.drawStringUnderlineCharAt(
g2d, text, getDisplayedMnemonicIndex(), textRect.x, textRect.y + g2d.getFontMetrics().getAscent()
);
}
}
private void paintWithForegroundPainterWithFilters(Graphics g) {
BufferedImage im = GraphicsUtilities.createCompatibleTranslucentImage(getWidth(), getHeight());
Graphics2D g2d = im.createGraphics();
try {
Graphics gfx = getComponentGraphics(g2d);
assert gfx == g2d;
paintWithForegroundPainterWithoutFilters(g2d);
} finally {
g2d.dispose();
}
Graphics2D filtered = (Graphics2D) g.create();
try {
for (BufferedImageOp filter : ((AbstractPainter>) fgPainter).getFilters()) {
filtered.setComposite(new FilterComposite(filtered.getComposite(), filter));
}
filtered.drawImage(im, 0, 0, this);
} finally {
filtered.dispose();
}
}
/**
* Notification from the UIManager
that the L&F has changed.
* Replaces the current UI object with the latest version from the UIManager
.
*
* @see javax.swing.JComponent#updateUI
*/
@Override
public void updateUI() {
super.updateUI();
if (bgStamp != null) {
bgStamp.updateUI();
}
if (fgStamp != null) {
fgStamp.updateUI();
}
}
}