001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui;
003
004import java.awt.BorderLayout;
005import java.awt.Color;
006import java.awt.Image;
007import java.awt.Insets;
008import java.awt.event.ActionListener;
009import java.beans.PropertyChangeEvent;
010import java.beans.PropertyChangeListener;
011
012import javax.swing.Action;
013import javax.swing.BorderFactory;
014import javax.swing.Icon;
015import javax.swing.ImageIcon;
016import javax.swing.JButton;
017import javax.swing.SwingConstants;
018import javax.swing.plaf.basic.BasicArrowButton;
019
020import org.openstreetmap.josm.tools.Destroyable;
021import org.openstreetmap.josm.tools.ImageProvider;
022
023/**
024 * Button that is usually used in toggle dialogs
025 */
026public class SideButton extends JButton implements Destroyable {
027    private final static int iconHeight = 20;
028
029    private PropertyChangeListener propertyChangeListener;
030
031    public SideButton(Action action) {
032        super(action);
033        fixIcon(action);
034        doStyle();
035    }
036
037    public SideButton(Action action, boolean usename) {
038        super(action);
039        if(!usename) {
040            setText(null);
041            fixIcon(action);
042            doStyle();
043        }
044    }
045
046    public SideButton(Action action, String imagename) {
047        super(action);
048        setIcon(makeIcon(imagename));
049        doStyle();
050    }
051
052    private void fixIcon(Action action) {
053        // need to listen for changes, so that putValue() that are called after the
054        // SideButton is constructed get the proper icon size
055        if (action != null) {
056            action.addPropertyChangeListener(propertyChangeListener = new PropertyChangeListener() {
057                @Override
058                public void propertyChange(PropertyChangeEvent evt) {
059                    if (evt.getPropertyName() == javax.swing.Action.SMALL_ICON) {
060                        fixIcon(null);
061                    }
062                }
063            });
064        }
065        Icon i = getIcon();
066        if (i instanceof ImageIcon && i.getIconHeight() != iconHeight) {
067            setIcon(getScaledImage(((ImageIcon) i).getImage()));
068        }
069    }
070
071    /** scales the given image proportionally so that the height is "iconHeight" **/
072    private static ImageIcon getScaledImage(Image im) {
073        int newWidth = im.getWidth(null) *  iconHeight / im.getHeight(null);
074        return new ImageIcon(im.getScaledInstance(newWidth, iconHeight, Image.SCALE_SMOOTH));
075    }
076
077    public static ImageIcon makeIcon(String imagename) {
078        Image im = ImageProvider.get("dialogs", imagename).getImage();
079        return getScaledImage(im);
080    }
081
082    private void doStyle() {
083        setLayout(new BorderLayout());
084        setIconTextGap(2);
085        setMargin(new Insets(-1,0,-1,0));
086    }
087
088    public void createArrow(ActionListener listener) {
089        setMargin(new Insets(0,0,0,0));
090        BasicArrowButton arrowButton = new BasicArrowButton(SwingConstants.SOUTH, null, null, Color.BLACK, null);
091        arrowButton.setBorder(BorderFactory.createEmptyBorder());
092        add(arrowButton, BorderLayout.EAST);
093        arrowButton.addActionListener(listener);
094    }
095
096    @Override
097    public void destroy() {
098        Action action = getAction();
099        if (action instanceof Destroyable) {
100            ((Destroyable) action).destroy();
101        }
102        if (action != null) {
103            if (propertyChangeListener != null) {
104                action.removePropertyChangeListener(propertyChangeListener);
105            }
106            setAction(null);
107        }
108    }
109}