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


// @(#)ColorButtonWidget.java, 1.4, 12/19/96





package marimba.gui;





import java.awt.*;


import marimba.persist.*;





/**


 * A widget for choosing a color. It does not extend


 * ButtonWidget since this button cannot be grouped and


 * never displays a label, but it acts like a button.


 *


 * @author	Klaas Waslander


 * @version 	1.4, 12/19/96


 */


public class ColorButtonWidget extends Widget {


    /**


     * The mode of the button, which can be raised or square.


     * @see #getMode


     * @see #setMode


     */


    public int  mode = RAISED;





    /**


     * The possible options for the mode.


     * @see #getModeOptions()


     * @see #mode


     */


    public static Options  modeOptions = new Options();


    static {


	modeOptions.add("raised", RAISED);


	modeOptions.add("filled", FILLED);


	modeOptions.add("square", SQUARE);


    }





    /**


     * The current color value of this button.


     * @see #getValue


     * @see #getColorValue


     */


    public Color  color;





    /** indicates whether the button is currently down */


    protected boolean  down;





    /**


     * Constructor


     */


    public ColorButtonWidget() {


    }





    /**


     * Constructor which also sets the color.


     */


    public ColorButtonWidget(Color color) {


	this.color = color;


    }





    /**


     * Get the properties of the color button.


     */


    public void getProperties(PropertyList list) {


	super.getProperties(list);


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


	list.setColor("color", color, null);


    }





    /**


     * Set the properties of the color button.


     */


    public void setProperties(PropertyList list) {


	super.setProperties(list);


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


	color = list.getColor("color", null);


	transparent = (mode != FILLED);


    }





    /**


     * Get the possible options for the mode.


     * @see #modeOptions


     */


    public Options getModeOptions() {


	return modeOptions;


    }





    /**


     * 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) {


	if (this.mode != mode) {


	    this.mode = mode;


	    repaint();


	}


    }





    /**


     * Set the current color.


     * @see #color


     */


    public void setValue(Object color) {


	if (color instanceof Color) {


	    setValue((Color)color);


	} else if (color == null) {


	    setValue((Color)null);


	}


    }





    /**


     * Set the current color.


     * @see #color


     */


    public void setValue(Color color) {


	if (color != null) {


	    if (color != this.color && !color.equals(this.color)) {


		this.color = color;


		repaint();


	    }


	} else {


	    this.color = null;


	    repaint();


	}


    }





    /**


     * Get the current color as a Color object.


     * @see #color


     */


    public Color getColorValue() {


	return color;


    }





    /**


     * Get the current color.


     * @see #color


     */


    public Object getValue() {


	return getColorValue();


    }





    /**


     * Paint the button with the current color.


     */


    public void paint(Graphics g) {


	int  offset = (down) ? 1 : 0;





	switch (mode) {


	    case FILLED:


		g.setColor(background);


		g.fillRect(0, 0, width, height);


	    case RAISED:


		g.setColor(background);


		Bevel.drawBorder(g, 0, 0, width, height, !down);


		g.setColor(foreground);


		// the small down arrow


		int  lineY = offset + height / 2 - 1;


		int  lineX = offset + width - 9;


		for (int lines = 0; lines < 3; lines++) {


		    int  lineWidth = 4 - lines*2;


		    g.drawLine(lineX + lines, lineY + lines, lineX + lines + lineWidth, lineY + lines);


		}


		// the vertical 3D line


		g.setColor(background.darker());


		g.drawLine(lineX - 3, offset+3, lineX - 3, offset+height - 5);


		g.setColor(background.brighter());


		g.drawLine(lineX - 2, offset+3, lineX - 2, offset+height - 5);





		// the color area


		g.setColor(foreground);


		g.drawRect(offset+4, offset+3, width - 20, height - 8);


		if (color != null) {


		    g.setColor(color);


		    g.fillRect(offset+5, offset+4, width - 21, height - 9);


		} else {


		    paintNullColor(g, offset+5, offset+4, width - 21, height - 9);


		}


		break;





	    case SQUARE: {


		int siz = Math.min(width, height);


		g.setColor(foreground);


		g.drawRect(offset, offset, siz-1-offset*2, siz-1-offset*2);


		if (color != null) {


		    g.setColor(color);


		    g.fillRect(offset+1, offset+1, siz-2-offset*2, siz-2-offset*2);


		} else {


		    paintNullColor(g, offset+1, offset+1, siz-2-offset*2, siz-2-offset*2);


		}


		break;


	    }


	}


    }





    /**


     * Paint the null color area, which are diagonal lines.


     */


    protected void paintNullColor(Graphics g, int x, int y, int width, int height) {


	Graphics  g2 = null;


	try {


	    g2 = g.create();


	    g2.clipRect(x, y, width, height);


	    int  siz = Math.max(width, height);


	    g2.setColor(background);


	    g2.fillRect(x, y, width, height);


	    g2.setColor(foreground);


	    // this is VERY unoptimized but works well for now


	    for (int i = -siz; i <= siz*2; i += 4) {


		g2.drawLine(x+i, y, x+i+siz, y+siz);


	    }


	} finally {


	    if (g2 != null) {


		g2.dispose();


	    }


	}


    }





    /**


     * Checks whether the given event occured within the button.


     */


    protected boolean eventInButton(Event evt) {


	int  buttonWidth = (mode == SQUARE) ? height : width;


	return evt.x >=0 && evt.x <= buttonWidth && evt.y >= 0 && evt.y <= height;


    }





    /**


     * Handle mouse events.


     */


    public boolean handleEvent(Event evt) {


	switch (evt.id) {


	    case Event.MOUSE_DOWN:


	    case Event.MOUSE_DRAG:


		if (down != eventInButton(evt)) {


		    down = !down;


		    repaint();


		}


		return false;





	    case Event.MOUSE_UP:


		if (down) {


		    new ColorPaletteWidget(this);


		    down = false;


		    repaint();


		}


		break;


	}


	return super.handleEvent(evt);


    }


}


