/* * ImageButton.java * * Copyright (C) 1996 Shaun Terry. All Rights Reserved. */ package spt.gui; import java.awt.Panel; import java.awt.Graphics; import java.awt.Font; import java.awt.Event; import java.awt.Color; import java.awt.Image; import java.awt.FontMetrics; import java.awt.Toolkit; import java.applet.AudioClip; import spt.gui.Rectangle3D; import spt.gui.ImagePanel; /** * A push button with an image on it. A text label * may also be displayed. * * @author Shaun Terry */ public class ImageButton extends Panel { private boolean isDown = false; private int borderW = Rectangle3D.borderWidthOfMode(Rectangle3D.IN); /** Left of the image */ public static final int LEFT = 0; /** Top of the image */ public static final int TOP = 1; /** Right of the image */ public static final int RIGHT = 2; /** Bottom of the image */ public static final int BOTTOM = 3; private String label; private Image img; private Image inactive_img; private Image shadowed_img; private float imageScale = 1; private AudioClip audio; private boolean fShowBorder = true; private boolean fDrawPushedIn = true; private int pos = RIGHT; private int padding = 2; private int gap = 0; private int ix=0, iy=0, iw=0, ih=0; // Internal image info public ImageButton(Image image) { this(image, null); } /** A null image or label is ok; a null image and label * is pretty darn useless. */ public ImageButton(Image image, String label) { this.label = label; setLayout(null); img = image; resize(); } public synchronized void addNotify() { resize(); super.addNotify(); } public void setFont(Font f) { super.setFont(f); resize(); } /** Show the border of the button? Useful when you just want * the image without the 3D button look around it. */ public void setShowBorder(boolean b) { fShowBorder = b; if (b) borderW = Rectangle3D.borderWidthOfMode(Rectangle3D.IN); else borderW = 0; resize(); } /** Make the button "depress" when clicked? If false the button * will behave normally, except when pushed it will give no * visual feedback. */ public void setDrawPushedIn(boolean b) { fDrawPushedIn = b; } public int getLabelPosition() { return pos; } /** Set the position of the label in relation to the image: * TOP, LEFT, RIGHT or BOTTOM. */ public void setLabelPosition(int a) { if (a != LEFT && a != TOP && a != RIGHT && a != BOTTOM) throw new IllegalArgumentException(); pos = a; resize(); } public String getLabel() { return label; } public void setLabel(String l) { label = l; resize(); repaint(); } /** Set the audio clip to play when the button is pushed. */ public void setAudioClip(AudioClip a) { audio = a; } /** Set the padding, in pixels, between the button border and * its image. */ public void setPadding(int p) { padding = p; resize(); repaint(); } public int getPadding() { return padding; } /** Set the gap, in pixels, between the label, if any, and image. */ public void setImageLabelGap(int g) { gap = g; resize(); repaint(); } public int getImageLabelGap() { return gap; } /** The image to be shown. */ public void setImage(Image i) { if (i == null || img == null) { img = i; resize(); } else if (i.getWidth(this) != img.getWidth(this) || i.getHeight(this) != img.getHeight(this)) { img = i; // If new image has a different size, then resize resize(); } else img = i; repaintImage(); } /** Scale the image to the given value (1.0 = 100%). */ public void setImageScale(double f) { setImageScale((float) f); } /** Scale the image to the given value (1.0 = 100%). */ public void setImageScale(float pct) { if (pct <= 0) pct = 1; imageScale = pct; resize(); } /** Enables the button. */ public void enable() { if (!isEnabled()) { isDown = false; super.enable(); repaint(); } } /** Disables the button. A grayed-out version of the image is * shown. */ public void disable() { if (isEnabled()) { isDown = false; super.disable(); repaint(); } } /** Resize the button the the size of its image plus padding * and border. */ public void resize() { Font f = getFont(); FontMetrics fm = null; if (f != null && label != null) fm = getToolkit().getFontMetrics(f); int iw=0, ih=0, _gap=0; if (img != null) { iw = (int) (img.getWidth(this) * imageScale); ih = (int) (img.getHeight(this) * imageScale); _gap = gap; } int w, h; w = iw + (2*(padding+borderW)); h = ih + (2*(padding+borderW)); if (fm != null) { if (pos == LEFT || pos == RIGHT) { w += _gap + fm.stringWidth(label); // Cuz the text could be taller than the image h = Math.max(h, fm.getAscent() + (2*(padding+borderW))); } else { h += _gap + fm.getAscent(); // Cause the text could be wider than the image w = Math.max(w, fm.stringWidth(label) + (2*(padding+borderW))); } } resize(w, h); } protected void repaintImage() { if (img != null) { Graphics g = getGraphics(); if (g == null) return; g.clearRect(ix, iy, iw, ih); if (imageScale == 1) g.drawImage(isEnabled() ? img : inactive_img, ix, iy, this); else g.drawImage(isEnabled() ? img : inactive_img, ix, iy, iw, ih, this); } } public synchronized void paint(Graphics g) { if (!isEnabled() && inactive_img == null) { inactive_img = ImagePanel.createDisabledImage(img, this); } int w = size().width; int h = size().height; if (fShowBorder) { Rectangle3D r = new Rectangle3D(this, 0, 0, w, h); if (isDown && fDrawPushedIn) r.setDrawingMode(Rectangle3D.IN); else r.setDrawingMode(Rectangle3D.OUT); r.paint(g); } int o = padding + borderW + ((isDown && fDrawPushedIn) ? 1 : 0); iw=0; ih=0; int _gap=0; if (img != null) { iw = (int) (img.getWidth(this) * imageScale); ih = (int) (img.getHeight(this) * imageScale); _gap = gap; } FontMetrics fm=null; if (label != null) { fm = getFontMetrics(getFont()); if (pos == RIGHT) ix = o; else if (pos == LEFT) ix = o + _gap + fm.stringWidth(label); else ix = (int) ((w-iw)/2) + ((isDown && fDrawPushedIn) ? 1 : 0); if (pos == TOP) iy = o + _gap + fm.getAscent(); else if (pos == BOTTOM) iy = o; else iy = (int) ((h-ih)/2) + ((isDown && fDrawPushedIn) ? 1 : 0); } else { ix = iy = o; } repaintImage(); int x, y; if (label != null) { if (pos == LEFT) x = o; else if (pos == RIGHT) x = o + _gap + iw; else x = (int) ((w-fm.stringWidth(label))/2) + ((isDown && fDrawPushedIn) ? 1 : 0); if (pos == TOP) y = o + fm.getAscent(); else if (pos == BOTTOM) y = o + _gap + fm.getAscent() + ih; else y = h - (int) ((h-fm.getAscent())/2) + ((isDown && fDrawPushedIn) ? 1 : 0) - 1; g.setColor(getForeground()); if (!isEnabled()) { g.setColor(Color.white); g.drawString(label, x+1, y+1); g.setColor(getBackground().darker()); } g.drawString(label, x, y); } } public boolean mouseDown(Event e, int x, int y) { if (isEnabled()) { isDown = true; repaint(); if (audio != null) audio.play(); } return true; } public boolean mouseUp(Event e, int x, int y) { if (isEnabled() && isDown) { isDown = false; repaint(); e.id = Event.ACTION_EVENT; postEvent(e); } return true; } public boolean mouseExit(Event e, int x, int y) { if (isEnabled() && isDown) { isDown = false; repaint(); } return true; } }