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


// @(#)WindowWidget.java, 1.14, 12/17/96





package marimba.gui;





import java.awt.*;





import marimba.persist.*;





/**


 * This group has an outline and potentially a label.


 *


 * @author	Arthur van Hoff


 * @version 	1.14, 12/17/96


 */


public class WindowWidget extends ContainerWidget {


    final static Font defaultTitleFont = new Font("Dialog", Font.BOLD, 10);


    final static Color defaultTitleColor = new Color(0, 0, 124);


    public final static int INDRAG  = 1;


    public final static int INCLOSE = 2;


    public final static int INSIZE  = 3;





    /**


     * The title of this window, which is displayed in the titlebar.


     * @see #getText


     * @see #setText


     */


    public String title = "Floating";





    /**


     * The font of the title.


     * @see #getTitleFont


     * @see #setTitleFont


     * @see #title


     */


    public Font titleFont = defaultTitleFont;





    /**


     * The color of the title bar.


     * @see #getTitleColor


     * @see #setTitleColor


     */


    public Color titleColor = defaultTitleColor;





    /**


     * The window can be moveable or stay on one position.


     * @see #isMoveable


     * @see #setMoveable


     */


    public boolean moveable = true;





    /**


     * The window can have a closeBox, which hides the window.


     * @see #hasCloseBox


     * @see #setCloseBox


     */


    public boolean closeBox = true;





    /**


     * The window can have a sizebox, which is displayed in


     * the right bottom corner and with which the window can


     * be resized.


     * @see #hasSizeBox


     * @see #setSizeBox


     */


    public boolean sizeBox = true;





    /**


     * A window widget can allow resizing or disable it.


     * @see #isResizable


     * @see #setResizable


     */


    public boolean  resizable = true;





    public int mx, my;


    public int mwhere;


    public boolean closeDown;





    /**


     * Get the properties of this widget.


     */


    public void getProperties(PropertyList list) {


	super.getProperties(list);


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


	list.setBoolean("moveable", moveable, true);


	list.setBoolean("resizable", resizable, true);


	list.setBoolean("closebox", closeBox, true);


	list.setBoolean("sizebox", sizeBox, true);


	list.setString("title", title, null);


	list.setFont("titlefont", titleFont, defaultTitleFont);


	list.setColor("titlecolor", titleColor, defaultTitleColor);


    }





    /**


     * Set the properties of this widget.


     */


    public void setProperties(PropertyList list) {


	super.setProperties(list);


	disabled = list.getBoolean("disabled", false);


	moveable = list.getBoolean("moveable", true);


	resizable = list.getBoolean("resizable", true);


	closeBox = list.getBoolean("closebox", true);


	sizeBox = list.getBoolean("sizebox", true);


	title = list.getString("title", null);


	titleFont = list.getFont("titlefont", defaultTitleFont);


	titleColor = list.getColor("titlecolor", defaultTitleColor);


	transparent = false;


    }





    /**


     * Allocate the content.


     */


    public Widget newContent() {


	GroupWidget w = new GroupWidget();


	w.lineMode = NONE;


	return w;


    }





    /**


     * Get the title.


     * @see #title


     */


    public String getText() {


	return title;


    }





    /**


     * Set the title.


     * @see #title


     */


    public void setText(String title) {


	if ((title != this.title) || ((title != null) && !title.equals(this.title))) {


	    this.title = title;


	    invalidate();


	    repaint();


	}


    }





    /**


     * Get the title.


     * @see #getText


     */


    public String getTitle() {


	return getText();


    }





    /**


     * Set the title.


     * @see #setText


     */


    public void setLabel(String title) {


	setText(title);


    }





    /**


     * Get the font of the title.


     * @see #titleFont


     */


    public Font getTitleFont() {


	return titleFont;


    }





    /**


     * Set the font of the title. If null is passed,


     * the font is set to the default font.


     * @see #titleFont


     */


    public void setTitleFont(Font titleFont) {


	if (titleFont == null) {


	    this.titleFont = defaultTitleFont;


	    invalidate();


	    repaint();


	} else if (!titleFont.equals(this.titleFont)) {


	    this.titleFont = titleFont;


	    invalidate();


	    repaint();


	}


    }





    /**


     * Get the color of the title bar.


     * @see #titleColor


     */


    public Color getTitleColor() {


	return titleColor;


    }





    /**


     * Set the color of the title bar. If null is passed,


     * the color is set to the default color.


     * @see #titleColor


     */


    public void setTitleColor(Color titleColor) {


	if (titleColor == null) {


	    this.titleColor = defaultTitleColor;


	    repaint();


	} else if (!titleColor.equals(this.titleColor)) {


	    this.titleColor = titleColor;


	    repaint();


	}


    }





    /**


     * Check whether the window is moveable.


     * @see #moveable


     */


    public boolean isMoveable() {


	return moveable;


    }





    /**


     * Allow or prevent moving the window.


     * @see #moveable


     */


    public void setMoveable(boolean moveable) {


	this.moveable = moveable;


    }





    /**


     * Check whether this window is resizable.


     * @see #resizable


     */


    public boolean isResizable() {


	return resizable;


    }





    /**


     * Make this window resizable or not resizable.


     * @see #resizable


     */


    public void setResizable(boolean resizable) {


	this.resizable = resizable;


    }





    /**


     * Check whether the window displays a close button


     * in the upper right corner, in the title bar.


     * @see #closeBox


     */


    public boolean hasCloseBox() {


	return closeBox;


    }





    /**


     * Display or do not display the close box.


     * @see #closeBox


     */


    public void setCloseBox(boolean closeBox) {


	if (this.closeBox != closeBox) {


	    this.closeBox = closeBox;


	    repaint();


	}


    }





    /**


     * Check whether the window uses the resize box.


     * @see #sizeBox


     */


    public boolean hasSizeBox() {


	return sizeBox;


    }





    /**


     * Enable or disable the use of a resize box in this window.


     * @see #sizeBox


     */


    public void setSizeBox(boolean sizeBox) {


	if (sizeBox != this.sizeBox) {


	    this.sizeBox = sizeBox;


	    repaint();


	}


    }





    /**


     * Layout the widget itself.


     */


    public void layout() {


	int h = getFontMetrics(titleFont).getHeight() + 6;


	content.reshape(2, h, width-4, height-(h+2));


    }





    /**


     * Paint the outline.


     */


    public void paint(Graphics g, int x, int y, int wd, int ht) {


	FontMetrics fm = getFontMetrics(titleFont);


	int h = fm.getHeight() + 6;





	g.setColor(background);


	Bevel.fillWindowBorder(g, 0, 0, width, height, background);





	if (y < h) {


	    g.setColor(titleColor);





	    g.setFont(titleFont);


	    g.fillRect(3, 3, width-6, h-4);





	    if (title != null) {


		g.setColor(Color.white);


		Graphics  g2 = null;


		try {


		    g2 = g.create();


		    if (closeBox) {


			g2.clipRect(0, 0, width - h - 2, height);


		    } else {


			g2.clipRect(0, 0, width - 5, height);


		    }


		    g2.drawString(title, 8, fm.getAscent() + 4);		    


		} finally {


		    if (g2 != null) {


			g2.dispose();


		    }


		}


	    }





	    if (closeBox) {


		h -= 7;


		int bx = width - (h + 6);


		int by = 5;


		int crossX = 3;


		int crossY = 3;





		if (closeDown) {


		    crossX += 1;


		    crossY += 1;


		}





		g.setColor(background);


		Bevel.fillBorder(g, bx, by, h + 1, h - 1, !closeDown);





		g.setColor(Color.black);


		g.drawLine(bx + crossX, by + crossY, bx + crossX + h-8, by + crossY + h-8);


		g.drawLine(bx + crossX + 1, by + crossY, bx + crossX + h-7, by + crossY + h-8);





		g.drawLine(bx + crossX + h-8, by + crossY, bx + crossX, by + crossY + h-8);


		g.drawLine(bx + crossX + h-7, by + crossY, bx + crossX + 1, by + crossY + h-8);


	    }


	}


	if (sizeBox && (y + ht > height - 20)) {


	    int bx = width - 5;


	    int by = height - 5;


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


	    for (int i = 2 ; i < 16 ; i += 4) {


		g.drawLine(bx - i, by, bx, by - i);


	    }


	    g.setColor(Color.white);


	    for (int i = 3 ; i < 16 ; i += 4) {


		g.drawLine(bx - i, by, bx, by - i);


	    }


	}


    }





    /**


     * Check in which resize area of the Window the event occured.


     * @return LEFT, RIGHT, TOP, BOTTOM, INSIZE or NONE


     */


    protected int findResizeArea(Event evt) {


	int  resizeMargin = 6;


	int  result = NONE;


	if (evt.x < 1 || evt.x > width-2 || evt.y < 1 || evt.y > height-2) {


	    result = NONE;


	} else if (sizeBox && (evt. x > width-15) && (evt.y > height-15)) {


	    result = INSIZE;


	} else if (evt.x < resizeMargin) {


	    result = LEFT;


	} else if (evt.x > width - resizeMargin) {


	    result = RIGHT;


	} else if (evt.y < resizeMargin) {


	    result = TOP;


	} else if (evt.y > height - resizeMargin) {


	    result = BOTTOM;


	} else {


	    result = NONE;


	}


	return result;


    }





    /**


     * HandleEvent


     */


    public boolean handleEvent(Event evt) {


	if (!disabled) {


	    FontMetrics fm = getFontMetrics(titleFont);


	    int h = fm.getHeight() + 5;





	    switch (evt.id) {


		case Event.MOUSE_MOVE: {


		    if (!resizable) {


			break;


		    }


		    switch (findResizeArea(evt)) {


			case NONE:


			    resetCursor();


			    break;


			case TOP:


			    setCursor(Frame.N_RESIZE_CURSOR);


			    break;


			case BOTTOM:


			    setCursor(Frame.S_RESIZE_CURSOR);


			    break;


			case LEFT:


			    setCursor(Frame.W_RESIZE_CURSOR);


			    break;


			case RIGHT:


			    setCursor(Frame.E_RESIZE_CURSOR);


			    break;


			case INSIZE:


			    setCursor(Frame.SE_RESIZE_CURSOR);


			    break;


		    }


		    return true;


		}





		case Event.MOUSE_EXIT:


		    if (findResizeArea(evt) == NONE) {


			resetCursor();


		    }


		    break;





		case Event.MOUSE_DOWN:


		    toFront();


		    mwhere = 0;


		    mx = evt.x;


		    my = evt.y;


		    if (resizable && findResizeArea(evt) != NONE) {


			mwhere = findResizeArea(evt);


			mx = width - evt.x;


			my = height - evt.y;


		    } else if (evt.y <= h) {


			if (closeBox && (evt.x > width - h)) {


			    mwhere = INCLOSE;


			    closeDown = true;


			    repaint();


			} else if (moveable) {


			    mwhere = INDRAG;


			}


		    }


		    return false;





		case Event.MOUSE_DRAG:


		    switch (mwhere) {


			case INCLOSE:


			    if (closeDown != ((evt.y > 0) && (evt.y < h) && (evt.x < width) && (evt.x > width - h))) {


				closeDown = !closeDown;


				repaint();


			    }


			    break;





			case INDRAG:


			    move(Math.max(10 - width, Math.min(parent.width - 10, x + evt.x - mx)),


				 Math.max(-5, Math.min(parent.height - 10, y + evt.y - my)));


			    break;





			case TOP:


			    reshape(x, y + evt.y, width, Math.max(40, height - evt.y));


			    break;


			case BOTTOM:


			    reshape(x, y, width, Math.max(40, evt.y));


			    break;


			case LEFT:


			    reshape(x + evt.x, y, Math.max(50, width - evt.x), height);


			    break;


			case RIGHT:


			    reshape(x, y, Math.max(50, evt.x), height);


			    break;


			case INSIZE:


			    reshape(x, y, Math.max(50, evt.x + mx), Math.max(40, evt.y + my));


			    break;


		    }


		    return true;


		


		case Event.MOUSE_UP:


		    switch (mwhere) {


			case INCLOSE:


			    if (closeDown) {


				closeDown = false;


				repaint();


				hide();


			}


			break;


		    }


		    mwhere = 0;


		    return true;


	    }


	}


	return super.handleEvent(evt);


    }





    /**


     * Debugging.


     */


    public void paramString(StringBuffer buf) {


	super.paramString(buf);


	buf.append(",title=");


	buf.append(title);


    }


}


