/**
* Copyright (C) 2001-2017 by RapidMiner and the contributors
*
* Complete list of developers available at our web site:
*
* http://rapidminer.com
*
* This program is free software: you can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License as published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* This program 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License along with this program.
* If not, see http://www.gnu.org/licenses/.
*/
package com.rapidminer.gui.tools.components;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.GeneralPath;
import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.SwingConstants;
import org.jdesktop.swingx.border.DropShadowBorder;
/**
* This is a {@link JButton} which looks fancier. The background is transparent and only when
* hovering over the button it is highlighted (floating above the background).
*
* @author Marco Boeck
*
*/
public class FancyButton extends JButton implements FancyConstants {
private static final int HEIGHT_EXTENSION = 20;
private static final long serialVersionUID = 6492754313852421831L;
private int preferredHeightExtension = HEIGHT_EXTENSION;
/** flag indicating if the button is hovered */
private boolean hovered;
/** flag indicating whether to draw trailing arrow */
private boolean drawArrow;
/** the color used to display the text when not hovered */
private Color normalTextColor = NORMAL_TEXTCOLOR;
/** the color used to display the text when hovered */
private Color hoveredTextColor = HOVERED_TEXTCOLOR;
private Color customBackgroundColor;
private Color customBorderColor;
private MouseListener hoverListener = new MouseAdapter() {
@Override
public void mouseExited(MouseEvent e) {
hovered = false;
setBorderPainted(false);
setForeground(normalTextColor);
repaint();
}
@Override
public void mouseEntered(MouseEvent e) {
hovered = true;
setBorderPainted(true);
setForeground(hoveredTextColor);
repaint();
}
};
private FocusListener focusListener = new FocusAdapter() {
@Override
public void focusLost(FocusEvent e) {
hovered = false;
setBorderPainted(false);
setForeground(normalTextColor);
repaint();
}
};
/**
* Creates a button with no set text or icon.
*/
public FancyButton() {
this(null, null);
}
/**
* Creates a button with an icon.
*
* @param icon
* the Icon image to display on the button
*/
public FancyButton(Icon icon) {
this(null, icon);
}
/**
* Creates a button with text.
*
* @param text
* the text of the button
*/
public FancyButton(String text) {
this(text, null);
}
/**
* 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 FancyButton(String text, Icon icon) {
super(text, icon);
// setup fancy button things
addMouseListener(hoverListener);
addFocusListener(focusListener);
setBorderPainted(false);
setBorder(new DropShadowBorder(SHADOW_COLOR, 5, 0.5f, 12, false, false, true, true));
setFocusPainted(false);
setContentAreaFilled(false);
setHorizontalAlignment(SwingConstants.LEFT);
setHorizontalTextPosition(SwingConstants.RIGHT);
setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
setForeground(normalTextColor);
drawArrow = true;
}
/**
* Creates a button where properties are taken from the <code>Action</code> supplied.
*
* @param a
* the <code>Action</code> used to specify the new button
*
*/
public FancyButton(Action a) {
this();
super.setAction(a);
}
/**
* If set to <code>true</code>, the trailing arrow will not be drawn.
*
* @param flag
*/
public void setDrawArrow(boolean flag) {
drawArrow = flag;
}
/**
* Sets the text color when the {@link FancyButton} is not hovered over.
*
* @param textColor
*/
public void setTextColor(Color textColor) {
this.normalTextColor = textColor;
setForeground(textColor);
}
/**
* Sets the text color when the {@link FancyButton} is hovered over.
*
* @param textColor
*/
public void setHoveredTextColor(Color textColor) {
this.hoveredTextColor = textColor;
}
/**
* Sets how much the height of the button should be enhanced. Default is
* {@link FancyButton#HEIGHT_EXTENSION}
*
* @param heightExtension
*/
public void setButtonHeightEnhancement(int heightExtension) {
this.preferredHeightExtension = heightExtension;
}
@Override
public Dimension getPreferredSize() {
Dimension prefSize = super.getPreferredSize();
prefSize.setSize(prefSize.getWidth() + (drawArrow ? 75 : -5), prefSize.getHeight() + preferredHeightExtension);
return prefSize;
}
@Override
public boolean isRolloverEnabled() {
// force it to disable rollover because we have custom hover highlighting
return false;
}
public void setBackgroundColor(Color backgroundColor) {
customBackgroundColor = backgroundColor;
};
public void setBorderColor(Color borderColor) {
customBorderColor = borderColor;
}
@Override
public void paintComponent(Graphics g) {
if (getModel().isArmed()) {
((Graphics2D) g).translate(1.1, 1.1);
}
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Graphics2D g2 = (Graphics2D) g.create();
// the default background is transparent
if (hovered || customBackgroundColor != null) {
// fill background
g2.setColor(customBackgroundColor != null ? customBackgroundColor : BACKGROUND_COLOR);
g2.fillRect(0, 0, getWidth() - 6, getHeight() - 6);
}
if (hovered) {
// draw border which complements the DropShadow
g2.setColor(customBorderColor != null ? customBorderColor : BORDER_LIGHTEST_GRAY);
g2.drawRect(0, 0, getWidth() - 6, getHeight() - 6);
} else if (customBorderColor != null) {
g2.setColor(customBorderColor);
g2.drawRect(0, 0, getWidth() - 6, getHeight() - 6);
}
if (hovered) {
if (drawArrow) {
// draw arrow
GeneralPath path = new GeneralPath();
path.moveTo(getWidth() * 0.82, getHeight() * 0.3);
path.lineTo(getWidth() * 0.92, getHeight() * 0.5);
path.lineTo(getWidth() * 0.82, getHeight() * 0.7);
Stroke arrowStroke = new BasicStroke(5f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL);
g2.setStroke(arrowStroke);
g2.setColor(HOVERED_TEXTCOLOR);
g2.draw(path);
}
// cut off arrow ends so the cut looks like an imaginary vertical line
g2.setColor(customBackgroundColor != null ? customBackgroundColor : BACKGROUND_COLOR);
g2.fillRect((int) (getWidth() * 0.81), (int) (getHeight() * 0.29), 7, (int) (getHeight() * 0.5));
}
g2.dispose();
super.paintComponent(g);
}
}