// Copyright 1996, Marimba Inc. All Rights Reserved.

// @(#)CommandButtonWidget.java, 1.63, 10/20/96



package marimba.gui;



import java.awt.*;



import marimba.persist.*;



/**

 * A command button widget.

 *

 * @author	Arthur van Hoff

 * @author	Klaas Waslander

 * @version 	1.63, 10/20/96

 */

public class CommandButtonWidget extends ButtonWidget {

    /**

     * A CommandButton can be invisible, raised, filled, square,

     * rounded and can contain a picture.

     * @see #getMode

     * @see #setMode

     * @see #modeOptions

     */

    public int mode;



    /**

     * The possible options for the mode.

     * @see #getModeOptions()

     * @see #mode

     */

    public static Options modeOptions = new Options();

    static {

	modeOptions.add("invisible", INVISIBLE);

	modeOptions.add("raised", RAISED);

	modeOptions.add("filled", FILLED);

	modeOptions.add("square", SQUARE);

	modeOptions.add("rounded", ROUNDED);

	modeOptions.add("picture", PICTURE);

    }



    /**

     * A sticky button remains down or up after a mouse-click

     * to visualize that the value remains set or unset.

     * @see #isSticky

     * @see #setSticky

     */

    public boolean sticky;



    /**

     * The source-file for the image.

     * @see #getSource

     * @see #setSource

     */

    public String  src;



    /**

     * A button can be the default button.

     * @see #isDefault

     * @see #setDefault

     */

    public boolean  isDefault;



    /**

     * The image that is used for the command button.

     * You can set the image by setting the source

     * and in that way persistify it, or set the image

     * directly.

     * @see #getImage

     * @see #setImage

     */

    public Image  img;





    /**

     * Constructor

     */

    public CommandButtonWidget() {

	this("Button", RAISED);

    }



    /**

     * Constructor

     */

    public CommandButtonWidget(String label) {

	this(label, RAISED);

    }

    /**

     * Constructor

     */

    public CommandButtonWidget(String label, int mode) {

	this.label = label;

	this.mode = mode;

    }



    /**

     * Get the properties of this widget.

     */

    public void getProperties(PropertyList list) {

	super.getProperties(list);

	list.setBoolean("default", isDefault, false);

	list.setBoolean("sticky", sticky, false);

	list.setOption("mode", modeOptions, mode, RAISED);

	list.setURL("src", src, null);

    }



    /**

     * Set the properties of this widget.

     */

    public void setProperties(PropertyList list) {

	super.setProperties(list);

	setDefault(list.getBoolean("default", false));

	setSticky(list.getBoolean("sticky", false));

	mode = list.getOption("mode", modeOptions, RAISED);

	src = list.getURL("src", null);

	transparent = (mode == INVISIBLE) || (mode == RAISED) || (mode == PICTURE);

    }



    /**

     * Get the possible options for the mode.

     * @see #modeOptions

     */

    public Options getModeOptions() {

	return modeOptions;

    }



    /**

     * Check if this commandbutton is the default one.

     * @see #isDefault

     */

    public boolean isDefault() {

	return isDefault;

    }



    /**

     * Set if this button is the default button or not.

     * @see #isDefault

     */

    public void setDefault(boolean isDefault) {

	this.isDefault = isDefault && (!sticky) && (!disabled);

	repaint();

    }



    /**

     * Get the editor.

     */

    public String getEditor() {

	return "marimba.builder.CommandButtonWidgetEditor";

    }



    /**

     * Get the sticky-ness.

     * @see #sticky

     */

    public boolean isSticky() {

	return sticky;

    }



    /**

     * Set the sticky-ness.

     * @see #sticky

     */

    public void setSticky(boolean sticky) {

	this.sticky = sticky;

	if (!sticky) {

	    down = false;

	} else {

	    isDefault = false;

	}

	repaint();

    }



    /**

     * Get the source-file for the image.

     * @see #src

     */

    public String getSource() {

	return src;

    }



    /**

     * Set the source-file for the image.

     * @see #src

     */

    public void setSource(String src) {

	this.src = src;

	img = null;

	if (isShowing()) {

	    start();

	}

	repaint();

    }



    /**

     * The image for the command button.

     */

    public Image getImage() {

	return img;

    }



    /**

     * Set the image for the command button.

     */

    public void setImage(Image img) {

	this.img = img;

	if (img == null) {

	    src = null;

	}

	repaint();

    }



    /**

     * Get the mode of this button.

     * @see #mode

     */

    public int getMode() {

	return mode;

    }



    /**

     * Set the mode for the button.

     * @see #mode

     */

    public void setMode(int mode) {

	this.mode = mode;

	if (mode == PICTURE) {

	    setSource(src);

	}

	repaint();

    }



    /**

     * Start loading the image label (if any)

     */

    public void start() {

	img = null;

	if ((mode == PICTURE) && (src != null)) {

	    Image newimg = getImage(src);

	    if (Toolkit.getDefaultToolkit().prepareImage(newimg, -1, -1, this)) {

		img = newimg;

		repaint();

	    }

	}

    }



    /**

     * Update the image.

     */

    public boolean imageUpdate(Image newimg, int flags, int x, int y, int w, int h) {

	if ((flags & ALLBITS) != 0) {

	    img = newimg;

	    repaint();

	    return false;

	}

	return (flags & ERROR) == 0;

    }



    /**

     * A sticky commandButton cannot request the focus.

     * So when the button is sticky this method won't do anything.

     */

    public void requestFocus() {

	if (!sticky) {

	    super.requestFocus();

	}

    }



    /**

     * Paint the button label.

     */

    public void paintLabel(Graphics g, String str, int x, int y) {

	g.drawString(str, x, y);

    }



    /**

     * Paint the button label.

     */

    public void paintLabel(Graphics g) {

	if (editor == null) {

	    switch (mode) {

	      case PICTURE:

		if (img != null) {

		    int w = img.getWidth(this);

		    int h = img.getHeight(this);

		    if ((w > 0) && (h > 0)) {

			int  lx = (width - w)/2;

			int  ly = (height - h)/2;

			int  clipX = 1;

			int  clipY = 1;

			if (value ^ down) {

			    lx++;

			    ly++;

			    clipX++;

			    clipY++;

			}

			Graphics g2 = g.create();

			try {

			    g2.clipRect(clipX, clipY, width-3, height-3);

			    g2.drawImage(img, lx, ly, this);

			} finally {

			    g2.dispose();

			}

			//g.drawImage(img, lx, ly, this);

		    }

		}

		break;



	      case INVISIBLE:

		break;



	      default:

		FontMetrics fm = g.getFontMetrics();

		int lx = (width - fm.stringWidth(label))/2;

		int ly = (height - fm.getHeight())/2 + fm.getAscent();

		if (value ^ down) {

		    lx += 1;

		    ly += 1;

		}

		if (disabled) {

		    Color back = (mode == RAISED) ? parent.background : background;

		    g.setColor(Bevel.getBrighter(back, true));

		    paintLabel(g, label, lx+1, ly+1);

		    g.setColor(Bevel.getDarker(back, true));

		    paintLabel(g, label, lx, ly);

		} else {

		    g.setColor(foreground);

		    paintLabel(g, label, lx, ly);

		}

	    }

	}

    }



    /**

     * Paint the button.

     */

    public void paintButton(Graphics g) {

	int x = 0;

	int y = 0;

	int width = this.width;

	int height = this.height;

	boolean  drawDefaultRect = false;



	// Draw as default if the button is not sticky and: has the focus or is

	// the default and the focus is held by something which is not a button.

	if (!sticky && (focus || (isDefault && !(currentFocus() instanceof CommandButtonWidget)))) {

	    drawDefaultRect = true;

	    x += 1;

	    y += 1;

	    width -= 2;

	    height -= 2;

	}



	switch (mode) {

	  case INVISIBLE:

	    return;



	  case SQUARE:

	    if (drawDefaultRect) {

	      g.setColor(Color.black);

	      g.drawRect(0, 0, this.width-1, this.height-1);

	    }

	    g.setColor((value ^ down) ? hilite : background);

	    g.fillRect(x + 1, y + 1, width-2, height-2);

	    g.setColor(foreground);

	    g.drawRect(x, y, width-1, height-1);

	    break;



	  case ROUNDED:

	    if (drawDefaultRect) {

	      g.setColor(Color.black);

	      g.drawRoundRect(0, 0, this.width-1, this.height-1, 14, 14);

	    }

	    g.setColor((value ^ down) ? hilite : background);

	    g.fillRoundRect(x, y, width-1, height-1, 14, 14);

	    g.setColor(foreground);

	    g.drawRoundRect(x, y, width-1, height-1, 14, 14);

	    break;



	  case FILLED:

	    if (drawDefaultRect) {

	      g.setColor(Color.black);

	      g.drawRect(0, 0, this.width-1, this.height-1);

	    }

	    g.setColor(background);

	    Bevel.fillBorder(g, x, y, width, height, !(value ^ down));

	    break;



	  default:

	    g.setColor(Color.red);

	    g.drawRect(0, 0, this.width-1, this.height-1);



	    if (drawDefaultRect) {

	      g.setColor(Color.black);

	      g.drawRect(0, 0, this.width-1, this.height-1);

	    }

	    g.setColor(parent.background);

	    Bevel.drawBorder(g, x, y, width, height, !(value ^ down));

	    break;

	}



	if (!sticky && focus && !disabled) {

	    paintFocus(g);

	}

    }   



    /**

     * Paint something more when focused.

     */

    public void paintFocus(Graphics g) {

	g.setColor(getFocusColor());

	Dash.drawFocusRect(g, 3, 3, this.width - 7, this.height - 7);

    }



    /**

     * Handle keyboard event when pressing return and do

     * some defaultButton operations when it gets the focus.

     */

    public boolean handleEvent(Event evt) {

	if (!disabled) {

	    switch (evt.id) {

	      case Event.KEY_PRESS: {

		  switch (evt.key) {

		    case '\n':

		      down = false;

		      repaint();

		      action();

		      return true;

		  }

		  break;

	      }



	      case Event.LOST_FOCUS:

	      case Event.GOT_FOCUS: {

		  repaint();

		  Widget defaultButton = getDefaultButton();

		  if (defaultButton != null) {

		      defaultButton.repaint();

		  }

		  return true;

	      }

	    }

	}

	return super.handleEvent(evt);

    }



    /**

     * CommandButtons can only support input focus when they

     * are not sticky and their mode is not invisible.

     */

    public boolean focusInterest() {

	if (!getSticky() && mode!=INVISIBLE) {

	    return super.focusInterest();

	} else {

	    return false;

	}

    }



    /**

     * Debugging.

     */

    public void paramString(StringBuffer buf) {

	super.paramString(buf);

	buf.append(",mode=");

	buf.append(modeOptions.get(mode));

    }



    /**

     * This function has been replaced by isSticky().

     * It is only here for backward compatibility but will be

     * removed in a future version.

     * @see #isSticky

     */

    public boolean getSticky() {

	return sticky;

    }

}

