/*************************************************** * * cismet GmbH, Saarbruecken, Germany * * ... and it just works. * ****************************************************/ package de.cismet.tools.gui; import java.awt.event.ActionEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.image.BufferedImage; import javax.swing.*; /** * An implementation of a "popup menu button". See a short <a href="http://flexo.cismet.de/gadgets/JPopupMenuButton/"> * description and demo</a> on the website. * * <p>Very easy to use:<br> * - Create the Button<br> * - Add an icon<br> * - Add an popup menu<br> * - Add an action event listener for the main action<br> * - Add an action event listener for the menu items<br> * - Ready<br> * </p> * <br> * <br> * * <p>License: <a href="http://www.gnu.org/copyleft/lesser.html#TOC1">GNU LESSER GENERAL PUBLIC LICENSE</a><br> * <img src="http://opensource.org/trademarks/osi-certified/web/osi-certified-60x50.gif"> <img * src="http://opensource.org/trademarks/opensource/web/opensource-55x48.gif"></p> * * @author thorsten.hell@cismet.de * @version $Revision$, $Date$ */ public class JPopupMenuButton extends JButton implements MouseListener, MouseMotionListener { //~ Instance fields -------------------------------------------------------- protected boolean showPopupMenu = true; JPopupMenu popupMenu = null; boolean mouseInPopupArea = false; Icon downArrow = new javax.swing.ImageIcon(getClass().getResource("/de/cismet/tools/gui/res/down.png")); // NOI18N Icon downArrow2 = new javax.swing.ImageIcon(getClass().getResource("/de/cismet/tools/gui/res/down2.png")); // NOI18N Icon userDefinedIcon = null; Icon userDefinedSelectedIcon = null; private int arrowXOffset = 0; private int arrowSelectedXOffset = 0; //~ Constructors ----------------------------------------------------------- /** * Creates a new instance of JPopupMenuButton. */ public JPopupMenuButton() { this(true); } /** * Creates a new instance of JPopupMenuButton. * * @param showPopupMenu do not use the popup menu funtionality */ public JPopupMenuButton(final boolean showPopupMenu) { this.showPopupMenu = showPopupMenu; setIcon(null); setVerticalTextPosition(SwingConstants.CENTER); setHorizontalTextPosition(SwingConstants.LEFT); this.addMouseMotionListener(this); this.addMouseListener(this); this.setFocusPainted(false); } //~ Methods ---------------------------------------------------------------- /** * Returns whether the given point x,y is in the popup area or not. * * @param x DOCUMENT ME! * @param y DOCUMENT ME! * * @return DOCUMENT ME! */ private boolean isOverMenuPopupArea(final int x, final int y) { return (x >= (getWidth() - getIcon().getIconWidth() + arrowXOffset - getInsets().right)) && (x <= (getWidth() - 1)); } /** * Invoked when the mouse cursor has been moved onto a component but no buttons have been pushed. * * @param e DOCUMENT ME! */ @Override public void mouseMoved(final java.awt.event.MouseEvent e) { final boolean oldValue = mouseInPopupArea; mouseInPopupArea = isOverMenuPopupArea((int)e.getPoint().getX(), (int)e.getPoint().getY()); if (oldValue != mouseInPopupArea) { evaluateIcon(isSelected()); } } /** * Invoked when a mouse button is pressed on a component and then dragged. <code>MOUSE_DRAGGED</code> events will * continue to be delivered to the component where the drag originated until the mouse button is released * (regardless of whether the mouse position is within the bounds of the component). * * <p>Due to platform-dependent Drag&Drop implementations, <code>MOUSE_DRAGGED</code> events may not be delivered * during a native Drag&Drop operation.</p> * * @param e DOCUMENT ME! */ @Override public void mouseDragged(final java.awt.event.MouseEvent e) { } /** * Invoked when a mouse button has been released on a component. * * @param e DOCUMENT ME! */ @Override public void mouseReleased(final java.awt.event.MouseEvent e) { } /** * Invoked when a mouse button has been pressed on a component. * * @param e DOCUMENT ME! */ @Override public void mousePressed(final java.awt.event.MouseEvent e) { } /** * Invoked when the mouse exits a component. * * @param e DOCUMENT ME! */ @Override public void mouseExited(final java.awt.event.MouseEvent e) { mouseInPopupArea = false; evaluateIcon(isSelected()); } /** * Invoked when the mouse enters a component. * * @param e DOCUMENT ME! */ @Override public void mouseEntered(final java.awt.event.MouseEvent e) { } /** * Invoked when the mouse button has been clicked (pressed and released) on a component. * * @param e DOCUMENT ME! */ @Override public void mouseClicked(final java.awt.event.MouseEvent e) { if (this.isEnabled()) { if (((popupMenu == null) || (popupMenu.getComponentCount() == 0)) && mouseInPopupArea) { actionPerformed(new ActionEvent(this, 0, "")); // NOI18N } else if (mouseInPopupArea || e.isPopupTrigger()) { popupMenu.show(this, 0, getHeight()); popupMenu.setVisible(true); } } } /** * Invoked when an action occurs. * * @param e DOCUMENT ME! */ public void actionPerformed(final java.awt.event.ActionEvent e) { final ActionEvent thisEvent = new ActionEvent(this, 0, "ACTION"); // NOI18N fireActionPerformed(thisEvent); } /** * Sets the button's default icon. This icon is also used as the "pressed" and "disabled" icon if there is no * explicitly set pressed icon. * * @param defaultIcon the icon used as the default image * * @see #getIcon * @see #setPressedIcon * * @beaninfo * attribute: visualUpdate true * bound: true * description: The button's default icon */ @Override public void setIcon(final javax.swing.Icon defaultIcon) { userDefinedIcon = defaultIcon; evaluateIcon(false); } @Override public void setSelectedIcon(final javax.swing.Icon defaultSelectedIcon) { userDefinedSelectedIcon = defaultSelectedIcon; evaluateIcon(true); } /** * Sets the right down arrow icon. * * @param isSelected DOCUMENT ME! */ private void evaluateIcon(final boolean isSelected) { if (mouseInPopupArea && isEnabled()) { evaluateIcon(downArrow2, isSelected); } else { evaluateIcon(downArrow, isSelected); } } /** * Sets the given Icon as down arrow. * * @param arrow the icon used as the arrow * @param isSelected DOCUMENT ME! */ private void evaluateIcon(final Icon arrow, final boolean isSelected) { final Icon icon = ((userDefinedSelectedIcon != null) && isSelected) ? userDefinedSelectedIcon : userDefinedIcon; if (icon != null) { final int newWidth = icon.getIconWidth() + arrow.getIconWidth(); int newHeight = icon.getIconHeight(); int arrowYOffset = (icon.getIconHeight() - arrow.getIconHeight()) / 2; arrowXOffset = icon.getIconWidth(); int iconYOffset = 0; if (arrow.getIconHeight() > newHeight) { newHeight = arrow.getIconHeight(); arrowYOffset = 0; iconYOffset = (arrow.getIconHeight() - icon.getIconHeight()) / 2; } final BufferedImage tmp = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB); icon.paintIcon(this, tmp.getGraphics(), 0, iconYOffset); if (showPopupMenu) { arrow.paintIcon(this, tmp.getGraphics(), icon.getIconWidth(), arrowYOffset); } if (isSelected) { super.setSelectedIcon(new ImageIcon(tmp)); } else { super.setIcon(new ImageIcon(tmp)); } } else { if (isSelected) { super.setSelectedIcon(arrow); } else { super.setIcon(arrow); } } } /** * Sets the popupmenu. * * @param pop the popup menu */ public void setPopupMenu(final JPopupMenu pop) { popupMenu = pop; } /** * Notifies all listeners that have registered interest for notification on this event type. The event instance is * lazily created using the <code>event</code> parameter. * * @param event the <code>ActionEvent</code> object * * @see EventListenerList */ @Override protected void fireActionPerformed(final ActionEvent event) { if ((popupMenu == null) || (mouseInPopupArea == false)) { super.fireActionPerformed(event); } } }