import java.awt.*;
import java.awt.image.FilteredImageSource;
import java.awt.event.*;
import java.util.Vector;

/** An Image in a Canvas,
 * bordered by a ThreeD Rectangle,
 * drawn Raised or Pressed.
 * <p>
 * Event handling is delegated to an ButtonLikeListener.
 * setListener(ButtonLikeListener) may be used to fit an
 * ImageButton with a different derivation of 
 * ButtonLikeListener after construction.<p>
 *
 * ImageButtons ensure that their Images are completely loaded 
 * before they are displayed.<p>
 * 
 * setEnabled (false) disables response to input and repaints 
 * the image with a black and white version.  setEnabled (true) 
 * restores the original image and enables response to input.
 *
 * @version 1.0, Apr 1 1996
 * @version 1.1, Nov 8 1996
 * @version 1.2, Dec 19 1996
 *
 * 1.1:.........................................................
 * Added default constructor and a constructor taking an Image
 * and an int (for thickness).
 *
 * Added static methods for getting/setting default thickness.
 *
 * Since an ImageButton is a Canvas,
 * it will fire mouse and mouse motion events
 * that can be listened to by others.
 *
 * ImageButton uses a BlackAndWhiteFilter to drain the color out
 * of the button when it is disabled.
 *
 * @author  David Geary
 * @see   ThreeDRectangle
 * @see   ButtonLikeListener
 * @see   SpringyButtonLikeListener
 * @see   StickyButtonLikeListener
 * @see   BleachImageFilter
 * @see   gjt.test.ImageButtonTest
 *
 * Extensive changes to the text book example;
 * simplified event handling,
 * simplified API
 * simplified painting
 * accepts either Image or DrawImage
 * optional separate pressedImage
 * @see   DrawImage
 *
 * additions by Morris Hirsch IPD Inc 1998
 */

public class ImageButton extends Component
implements ButtonLike {

    private static BlackAndWhiteFilter _bwFilter;

    private boolean Pressed = false;
    private boolean       Enabled = true;

    private Dimension       prefSize   = new Dimension(0,0);
    private int         thickness;

    private Image
	mainImage = null,
	disabledImage = null,
	pressedImage = null,
	pressed_disabledImage = null;

    private String text = null;

    private DrawImage drawImage = null;

    private ButtonLikeListener listener = null;

/* Constructors and param setting methods */

/** Construct an ImageButton.
 * @param listener,
 * @param image,
 * @param thickness,
 * @param text
 */

    public ImageButton (ButtonLikeListener listener, Image image, int thickness, String text) {
        setListener (listener);
        setImage (image);
        setThickness (thickness);
	setText (text);
    }

/** Construct an ImageButton,
 * using a DrawImage instead of an Image.
 * @param listener,
 * @param drawImage,
 * @param thickness,
 * @param text
 */

    public ImageButton (ButtonLikeListener listener, DrawImage drawImage, int thickness, String text) {
        setListener (listener);
        setDrawImage (drawImage);
        setThickness (thickness);
	setText (text);
    }

/** Set 3D edge thickness.
 * @param thickness,
 */

    public void setThickness(int thickness) {
        if (thickness < 0)
	    thickness = 0;

        this.thickness = thickness;

        if (isShowing ()) {
            invalidate ();
            getParent ().validate();
        }
    }

    public void setText (String text) {
        this.text = text;
    }

    public String getText  () {
        return text;
    }

/** Set the main Image */

    public void setImage (Image mainImage) {
        this.mainImage = mainImage;

        if (isShowing ()) {
            invalidate ();
            getParent ().validate();
        }
    }

/* Set a distinct Pressed / Inset Image.
 * Must be same width and height as mainImage. */

    public void setPressedImage (Image pressedImage) {
        this.pressedImage = pressedImage;
    }

/* Set a drawing to use instead of fixed Image */

    public void setDrawImage (DrawImage drawImage) {
	this.drawImage = drawImage;
	drawImage.setButton (this);
    }

/** Set the Listener to provide some button behavior.
 * It will listen for both kinds of Mouse events,
 * so register it as both kinds of listener. */

    public void setListener (ButtonLikeListener ibl) {
        if (listener != null) {
            removeMouseListener(listener);
            removeMouseMotionListener(listener);
        }
        listener = ibl;
        addMouseListener(listener);
        addMouseMotionListener(listener);
    }

/** Get the current Listener. */

    public ButtonLikeListener getListener () {
        return listener;
    }

/* Sizing methods */

/** * @deprecated as of JDK1.1 */

    public Dimension minimumSize () {
        return getMinimumSize ();
    }

    public Dimension getMinimumSize () {
        return getPreferredSize ();
    }

/** * @deprecated as of JDK1.1 */

    public Dimension preferredSize () {
        return getPreferredSize ();
    }

    public Dimension getPreferredSize () {
	if (null != drawImage) {
	    prefSize.width  = drawImage.getWidth ();
	    prefSize.height = drawImage.getHeight ();
	}

	else {
            if (null == mainImage) {
	        //throw new IllegalStateException ("null image");
		prefSize.width  = 32;
		prefSize.height = 32;
	    }

            else {
                Util.waitForImage(this, mainImage);
                prefSize.width  = mainImage.getWidth (this);
                prefSize.height = mainImage.getHeight(this);
	    }
	}

        prefSize.width  += (2*thickness);
        prefSize.height += (2*thickness);

        return prefSize;
    }

/** * @deprecated as of JDK1.1 */

    public void resize(int w, int h) {
        setBounds(getLocation ().x, getLocation().y, w, h);
    }

    public void setSize(int w, int h) {
        resize(w,h);
    }

/** * @deprecated as of JDK1.1 */

    public void reshape(int x, int y, int w, int h) {

    // compiler will issue deprecation warning,
    // but we can't call super.setBounds ()

        super.reshape(x,y,w,h);
    }
        
    public void setBounds(int x, int y, int w, int h) { 
        reshape(x,y,w,h);
    }

/** Set appearance Pressed or not */

    public void setPressed (boolean Pressed) {
	if (this.Pressed == Pressed)
	    return;

        this.Pressed = Pressed;

        if (isShowing ()) repaint();
    }

    public boolean isPressed () {
        return Pressed;
    }

/* Enable / Disable methods */

    public void setEnabled (boolean enable) {
	if (Enabled == enable)
	    return;

        Enabled = enable;

        if (isShowing ())
	    repaint();
    }

    public boolean isEnabled () {
        return Enabled;
    }

/** * @deprecated as of JDK1.1 */

    public void enable () {
	setEnabled (true);
    }

/** * @deprecated as of JDK1.1 */

    public void disable () {
	setEnabled (false);
    }

/* Paint */

    public void paint (Graphics g) {

/* offset to center PS within larger S */

            Dimension PS = getPreferredSize ();

            Dimension S = getSize ();
        
            Point  upperLeft = new Point
		((S.width - PS.width) /2, 
                 (S.height - PS.height) /2);

	    int ulx = upperLeft.x,
		uly = upperLeft.y;

/* This should take another arg for Pressed... */

	    if (null != drawImage)
		drawImage.draw (g,
		  ulx + thickness,
		  uly + thickness,
		  Enabled);

	    else {
                if (null == mainImage)
		    throw new IllegalStateException ("null image");

                Image   pImage;

                if (Enabled) {
		    if ((null != pressedImage) && Pressed)
			pImage = pressedImage;
		    else
			pImage = mainImage;
		}

		else {
		    if (null == disabledImage)
                        disabledImage
			 = createDisabledImage (mainImage);

                    if (null == pressed_disabledImage)
                        pressed_disabledImage
			 = createDisabledImage (pressedImage);

		    if ((null != pressed_disabledImage) && Pressed)
			pImage = pressed_disabledImage;
		    else
			pImage = disabledImage;
		}
		
                g.drawImage (pImage,
		  ulx + thickness, 
                  uly + thickness,
	          this);
            }

/* Not Pressed --
 * Top and Left edges brighter than BG,
 * Bottom and Right edges darker than BG
 *
 * Pressed --
 * Top and Left edges darker than BG,
 * Bottom and Right edges brighter than BG */

            Util.paint3DRect (g, getBackground (),
		ulx, uly, PS.width, PS.height,
		thickness, false,
		!Pressed);
     }

      private Image createDisabledImage (Image fromImage) {
	    Image grayImage;

	    if (null == fromImage)
		return null;

            Util.waitForImage (this, fromImage);

            if (_bwFilter == null)
              _bwFilter = new BlackAndWhiteFilter ();
        
            FilteredImageSource fis = 
              new FilteredImageSource (fromImage.getSource (), 
                          _bwFilter);
        
            Util.waitForImage (this, grayImage = createImage (fis));

	    return grayImage;
      }

/** Extensions should override one or both of these, */

    public void processStateChange (boolean s) { }

    public void processAction () { }
}
/* <IMG SRC="/cgi-bin/counter">*/
