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


// @(#)ScrollingContainerWidget.java, 1.31, 12/17/96





package marimba.gui;





import java.awt.*;





import marimba.persist.*;





/**


 * A container with scrollbars.


 *


 * @author	Arthur van Hoff


 * @version 	1.31, 12/17/96


 */


public class ScrollingContainerWidget extends ContainerWidget {


    public final int SCROLLSIZ = 15;





    /**


     * The possible options for the horizontal scrollbar.


     * @see #getHorzOptions


     * @see #horzmode


     */


    public static Options  horzOptions = new Options();


    static {


	horzOptions.add("never", NEVER);


	horzOptions.add("optional", OPTIONAL);


	horzOptions.add("always", ALWAYS);


    }





    /**


     * The possible options for the vertical scrollbar.


     * @see #getVertOptions


     * @see #vertmode


     */


    public static Options  vertOptions = new Options();


    static {


	vertOptions.add("never", NEVER);


	vertOptions.add("optional", OPTIONAL);


	vertOptions.add("always", ALWAYS);


    }





    /**


     * The possible options for the fillMode.


     * @see #getFillOptions


     * @see #fillMode


     */


    public static Options  fillOptions = new Options();


    static {


	fillOptions.add("none", NONE);


	fillOptions.add("scrollbars", SCROLLBAR);


    }





    /**


     * Determines whether the scrollbars should be filled.


     * @see #getFillMode


     * @see #setFillMode


     * @see #fillOptions


     */


    public int fillMode = NONE;





    /**


     * Determines whether the scrollbars should be constrained.


     * @see #isConstrained


     * @see #setConstrained


     * @see ScrollbarWidget#constrained


     */


    public boolean constrained = true;





    /**


     * The horizontal scrollbar.


     * @see #getHorz


     */


    public ScrollbarWidget horz;





    /**


     * The vertical scrollbar.


     * @see #getVert


     */


    public ScrollbarWidget vert;





    /**


     * The heigth of the header area above the container.


     * @see #getHdrHeight


     * @see #setHdrHeight


     */


    public int hdrHeight = 0;





    /**


     * The mode for the horizontal scrollbar:


     * never, optional or always.


     * @see #getHorzmode


     * @see #setHorzmode


     * @see #horzOptions


     */


    public int horzmode = ALWAYS;





    /**


     * The mode for the vertical scrollbar:


     * never, optional or always.


     * @see #getVertmode


     * @see #setVertmode


     * @see #vertOptions


     */


    public int vertmode = ALWAYS;





    /**


     * The width of the content.


     * @see #getContWidth


     * @see #setContWidth


     */


    public int contWidth = 500;





    /**


     * The height of the content.


     * @see #getContHeight


     * @see #setContHeight


     */


    public int contHeight = 500;





    /**


     * This widget can leave the bottom-right corner open.


     * That means that the vertical scrollbar becomes smaller.


     * @see #hasCorner


     * @see #setCorner


     */


    public boolean corner;








    /**


     * Constructor.


     */


    public ScrollingContainerWidget() {


	setHilite(new Color(232, 232, 232));


    }





    /**


     * Get the properties.


     */


    public void getProperties(PropertyList list) {


	super.getProperties(list);


	list.setOption("fillmode", fillOptions, fillMode, NONE);


	list.setInteger("contWidth", contWidth, 500);


	list.setInteger("contHeight", contHeight, 500);


	list.setOption("horizontal", horzOptions, horzmode, ALWAYS);


	list.setOption("vertical", vertOptions, vertmode, ALWAYS);


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


    }





    /**


     * Set the properties.


     */


    public void setProperties(PropertyList list) {


	super.setProperties(list);


	setFillMode(list.getOption("fillmode", fillOptions, NONE));


	contWidth = list.getInteger("contWidth", 500);


	contHeight = list.getInteger("contHeight", 500);


	horzmode = list.getOption("horizontal", horzOptions, ALWAYS);


	vertmode = list.getOption("vertical", vertOptions, ALWAYS);


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





	horz = vert = null;


    }





    /**


     * Disable/enable the scrollbarst, when disabling/enabling.


     */


    public void disable(boolean disabled) {


	if (this.disabled != disabled) {


	    this.disabled = disabled;


	    if (horz != null) {


		horz.disable(disabled);


	    }


	    if (vert != null) {


		vert.disable(disabled);


	    }


	    layout();


	    repaint();


	}


    }





    /**


     * Get the possible options for the horizontal scrollbar.


     * @see #horzOptions


     */


    public Options getHorzOptions() {


	return horzOptions;


    }





    /**


     * Get the possible options for the vertical scrollbar.


     * @see #vertOptions


     */


    public Options getVertOptions() {


	return vertOptions;


    }





    /**


     * Get the possible options for the fillMode.


     * @see #fillOptions


     */


    public Options getFillOptions() {


	return fillOptions;


    }





    /**


     * Check if the scrollbars are filled.


     * @see #fillMode


     */


    public int getFillMode() {


	return fillMode;


    }





    /**


     * Let the scrollbars fill or not.


     * @see #fillMode


     */


    public void setFillMode(int fillMode) {


	if (fillMode==NONE || fillMode==SCROLLBAR) {


	    this.fillMode = fillMode;


	    if (horz != null) {


		horz.setFilled(fillMode==SCROLLBAR);


	    }


	    if (vert != null) {


		vert.setFilled(fillMode==SCROLLBAR);


	    }


	}


    }





    /**


     * Check if the scrollbars are constrained.


     * @see #constrained


     */


    public boolean isConstrained() {


	return constrained;


    }





    /**


     * Let the scrollbars be constrained or not.


     * @see #constrained


     */


    public void setConstrained(boolean constrained) {


	this.constrained = constrained;


	if (horz != null) {


	    horz.setConstrained(constrained);


	}


	if (vert != null) {


	    vert.setConstrained(constrained);


	}


    }





    /**


     * Get the horizontal scrollbar.


     * @see #horz


     */


    public ScrollbarWidget getHorz() {


	return horz;


    }





    /**


     * Get the vertical scrollbar.


     * @see #vert


     */


    public ScrollbarWidget getVert() {


	return vert;


    }





    /**


     * Get the height of the header area above the container.


     * @see #hdrHeight


     */


    public int getHdrHeight() {


	return hdrHeight;


    }





    /**


     * Set the height of the header area above the container.


     * @see #hdrHeight


     */


    public void setHdrHeight(int hdrHeight) {


	if (this.hdrHeight != hdrHeight) {


	    this.hdrHeight = hdrHeight;


	    layout();


	    repaint();


	}


    }





    /**


     * Get the mode for the horizontal scrollbar.


     * @see #horzmode


     */


    public int getHorzmode() {


	return horzmode;


    }





    /**


     * Set the mode for the horizontal scrollbar.


     * @see #horzmode


     */


    public void setHorzmode(int horzmode) {


	if (horzmode==NEVER || horzmode==OPTIONAL || horzmode==ALWAYS) {


	    this.horzmode = horzmode;


	    layout();


	    repaint();


	}


    }





    /**


     * Get the mode for the vertical scrollbar.


     * @see #vertmode


     */


    public int getVertmode() {


	return vertmode;


    }





    /**


     * Set the mode for the vertical scrollbar.


     * @see #vertmode


     */


    public void setVertmode(int vertmode) {


	if (vertmode==NEVER || vertmode==OPTIONAL || vertmode==ALWAYS) {


	    this.vertmode = vertmode;


	    layout();


	    repaint();


	}


    }





    /**


     * Get the width of the content.


     * @see #contWidth


     */


    public int getContWidth() {


	return contWidth;


    }





    /**


     * Set the width of the content.


     * @see #contWidth


     */


    public void setContWidth(int contWidth) {


	if (this.contWidth != contWidth) {


	    this.contWidth = contWidth;


	    layout();


	    repaint();


	}


    }





    /**


     * Get the height of the content.


     * @see #contHeight


     */


    public int getContHeight() {


	return contHeight;


    }





    /**


     * Set the height of the content.


     * @see #contHeight


     */


    public void setContHeight(int contHeight) {


	if (this.contHeight != contHeight) {


	    this.contHeight = contHeight;


	    layout();


	    repaint();


	}


    }





    /**


     * Check if this widget leaves the bottom-right corner open.


     * @see #corner


     */


    public boolean hasCorner() {


	return corner;


    }





    /**


     * Let this widget have a corner or not.


     * @see #corner


     */


    public void setCorner(boolean corner) {


	if (this.corner != corner) {


	    this.corner = corner;


	    layout();


	    repaint();


	}


    }





    /**


     * Allocate content container.


     */


    public Widget newContent() {


	GroupWidget content = new GroupWidget();


	content.lineMode = LOWERED;


	return content;


    }





    /**


     * Scroll the content to a given position, limited by


     * contHeight and contWidth. This will change the


     * translation of the content.


     */


    public void scrollContent(int tx, int ty) {


	int  xScroll, yScroll;





	if (contHeight < content.height && contWidth < content.width) {


	    xScroll = yScroll = 0;


	} else if (contHeight < content.height) {


	    xScroll = Math.min(0, Math.max(tx, 20 - contWidth));


	    yScroll = 0;


	} else if (contWidth < content.width) {


	    xScroll = 0;


	    yScroll = Math.min(0, Math.max(ty, 20 - contHeight));


	} else {


	    xScroll = Math.min(0, Math.max(tx, 20 - contWidth));


	    yScroll = Math.min(0, Math.max(ty, 20 - contHeight));


	}





	content.scroll(xScroll, yScroll);


	if (horz != null) {


	    horz.setValue(-content.tx);


	}


	if (vert != null) {


	    vert.setValue(-content.ty);


	}


    }





    /**


     * Scroll the content so that the given rectangle


     * is visible.


     */


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


	x = Math.max(0, Math.min(x, contWidth));


	y = Math.max(0, Math.min(y, contHeight));





	int tx = content.tx;


	int ty = content.ty;





	if (x + w + tx > content.width) {


	    tx = content.width - (x + w);


	}


	if (x < -tx) {


	    tx = 5 - x;


	}





	if (y + h + ty > content.height) {


	    ty = content.height - (y + h);


	}


	if (y < -ty) {


	    ty = 5 - y;


	}


	scrollContent(tx, ty);


    }





    /**


     * Set the size of the content


     */


    public void setContentSize(int contWidth, int contHeight) {


	if ((contWidth != this.contWidth) || (contHeight != this.contHeight)) {


	    this.contWidth = contWidth;


	    this.contHeight = contHeight;


	    scrollContent(content.tx, content.ty);


	    invalidate();


	    repaint();


	}


    }





    /**


     * Set scrollbar mode.


     */


    public void setScrollbarModes(int horzmode, int vertmode) {


	if ((this.horzmode != horzmode) || (this.vertmode != vertmode)) {


	    this.horzmode = horzmode;


	    this.vertmode = vertmode;


	    invalidate();


	    repaint();


	}


    }





    /**


     * Create a new scrollbar with all the necessary properties.


     */


    public ScrollbarWidget newScrollbar(int orientation) {


	ScrollbarWidget  result = new ScrollbarWidget(orientation);


	result.setConstrained(constrained);


	result.setFilled(fillMode==SCROLLBAR);


	result.setBackground(background);


	result.setHilite(hilite);


	result.setForeground(foreground);


	result.disable(disabled);


	return result;


    }





    /**


     * Layout the container.


     */


    public void layout() {


	boolean scrollHorz = horzmode == ALWAYS;


	boolean scrollVert = vertmode == ALWAYS;





	int w = scrollVert ? width - SCROLLSIZ : width;


	int h = (scrollHorz ? height - SCROLLSIZ : height) - hdrHeight;





	if (horzmode == OPTIONAL && contWidth > w) {


	    h = height - SCROLLSIZ - hdrHeight;


	    scrollHorz = true;


	}


	if (vertmode == OPTIONAL && contHeight > h) {


	    w = width - SCROLLSIZ;


	    scrollVert = true;


	}





	content.reshape(0, hdrHeight, w, h);


	int  oldTx = content.tx;


	int  oldTy = content.ty;


	scrollContent(content.tx, content.ty);


	boolean  horzChange = scrollHorz && oldTx == content.tx;


	boolean  vertChange = scrollVert && oldTy == content.ty;





	// deal with the HORIZONTAL scrollbar


	if (horzChange) {


	    if (horz == null) {


		add(horz = newScrollbar(HORIZONTAL));


	    }


	    int  horzWidth = width;


	    if ((corner && vertChange) || (scrollVert && (w >= h))) {


		horzWidth -= SCROLLSIZ;


	    }


	    horz.reshape(0, height - SCROLLSIZ, horzWidth, SCROLLSIZ);


	    horz.setParam(-content.tx, 0, contWidth, 10, w);


	} else if (horz != null) {


	    remove(horz);


	    horz = null;


	}





	// deal with the VERTICAL scrollbar


	if (vertChange) {


	    if (vert == null) {


		add(vert = newScrollbar(VERTICAL));


	    }


	    int  vertHeight = height - hdrHeight;


	    if ((corner && horzChange) || (scrollHorz && (w < h))) {


		vertHeight -= SCROLLSIZ;


	    }


	    vert.reshape(w, hdrHeight, SCROLLSIZ, vertHeight);


	    vert.setParam(-content.ty, 0, contHeight, 10, h);


	} else if (vert != null) {


	    remove(vert);


	    vert = null;


	}


    }





    /**


     * Handle scroll events.


     */


    public boolean handleEvent(Event evt) {


	switch (evt.id) {


	  case Event.SCROLL_LINE_UP:


	  case Event.SCROLL_LINE_DOWN:


	  case Event.SCROLL_PAGE_UP:


	  case Event.SCROLL_PAGE_DOWN:


	  case Event.SCROLL_ABSOLUTE:


	    if (evt.target == horz) {


		scrollContent(-horz.value, content.ty);


	    } else if (evt.target == vert) {


		scrollContent(content.tx, -vert.value);


	    }


	    break;


	}


	return super.handleEvent(evt);


    }


}


