I was modeling my splitPane off of ECHO2's. So I was going to add
support for the different split types (i.e. Split_left_right,
Split_right_left, Split_top_bottom, and Split_bottom_top).
So here is why I gave up. In IE you cannot specify both top and bottom
or right and left for absolute positionted divs. Therefore the High
never fills the entire screen top to bottom. This causes problems for
the splitPane since it should fill 100% height and width. If you try
and set height to 100% the div ends up being larger than 100% height
because you are setting top to some pixel value.
There is more explination here:
http://forum.nextapp.com/forum/index.php?showtopic=2867&hl=100%
Echo uses a nifty little approach with their splitPane where they look
at the parentDiv height/width and set the current Div. I think they use
offsetWidth and offsetHeight. Not sure off the top of my head.
Anyway this does not work with GWT because the load order is not
controlled. The parent's offsetHeight is not available until all
elements have been added to the dom, and I haven't found a way from the
google framework to have a hook listeners that will fire once dom is
fully loaded (i.e everything is added to RootPanel)
I will attach what I have so far, but it is not complete. If anyone can
get this working let me know.
Thanks, Adam
package com.hamelsoft.chunga.client;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.ComplexPanel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.Widget;
public class SplitPanel extends ComplexPanel
{
public static final int ORIENTATION_VERTICAL_TOP_BOTTOM = 0;
public static final int ORIENTATION_VERTICAL_BOTTOM_TOP = 1;
public static final int ORIENTATION_HORIZONTAL_LEFT_RIGHT = 2;
public static final int ORIENTATION_HORIZONTAL_RIGHT_LEFT = 3;
private int splitType = ORIENTATION_HORIZONTAL_LEFT_RIGHT;
private static final String parentHeightExpression =
"expression(this.parentNode.clientHeight-this.offsetTop)";
private boolean moving = false;
private int widgetCount = 0;
public static final String HANDLE_BG_COLOR = "transparent";
public static final int HANDLE_DEFAULT_WIDTH = 5;
private boolean resizable = true;
private int separatorPosition = 0;
private int dragInitMouseOffset = 0;
private SplitPane cellOne;
private SplitPane handle;
private SplitPane cellTwo;
class SplitPane extends SimplePanel {}
public SplitPanel(int splitType, int separatorPosition)
{
this.separatorPosition = separatorPosition;
this.splitType = splitType;
widgetCount = 0;
Element wrapper = DOM.createDiv();
DOM.setStyleAttribute(wrapper, "position", "absolute");
DOM.setStyleAttribute(wrapper, "overflow", "auto");
DOM.setStyleAttribute(wrapper, "left", "0");
DOM.setStyleAttribute(wrapper, "right", "0");
DOM.setStyleAttribute(wrapper, "bottom", "0");
DOM.setStyleAttribute(wrapper, "top", "0");
DOM.setStyleAttribute(wrapper, "width", "100%");
// DOM.setStyleAttribute(wrapper, "height", "100%");
setElement(wrapper);
buildSplitPaneCellOne();
buildSplitPaneDragHandle();
buildSplitPaneCellTwo();
switch(splitType)
{
case ORIENTATION_HORIZONTAL_LEFT_RIGHT :
{
DOM.setStyleAttribute(cellOne.getElement(), "top", "0px");
DOM.setStyleAttribute(cellOne.getElement(), "bottom", "0px");
DOM.setStyleAttribute(cellOne.getElement(), "left", "0px");
DOM.setStyleAttribute(cellOne.getElement(), "width",
separatorPosition+"px");
DOM.setStyleAttribute(cellTwo.getElement(), "top", "0px");
DOM.setStyleAttribute(cellTwo.getElement(), "bottom", "0px");
DOM.setStyleAttribute(cellTwo.getElement(), "right", "0px");
DOM.setStyleAttribute(cellTwo.getElement(), "width", "100%");
DOM.setStyleAttribute(handle.getElement(), "width",
getHandleSize()+"px");
DOM.setStyleAttribute(handle.getElement(), "top", "0px");
DOM.setStyleAttribute(handle.getElement(), "bottom", "0px");
if (isResizable())
DOM.setStyleAttribute(handle.getElement(), "cursor",
"w-resize");
break;
}
case ORIENTATION_HORIZONTAL_RIGHT_LEFT :
{
DOM.setStyleAttribute(cellOne.getElement(), "top", "0px");
DOM.setStyleAttribute(cellOne.getElement(), "bottom", "0px");
DOM.setStyleAttribute(cellOne.getElement(), "right", "0px");
DOM.setStyleAttribute(cellTwo.getElement(), "top", "0px");
DOM.setStyleAttribute(cellTwo.getElement(), "bottom", "0px");
DOM.setStyleAttribute(cellTwo.getElement(), "left", "0px");
DOM.setStyleAttribute(handle.getElement(), "width",
getHandleSize()+"px");
DOM.setStyleAttribute(handle.getElement(), "top", "0px");
DOM.setStyleAttribute(handle.getElement(), "bottom", "0px");
if (isResizable())
DOM.setStyleAttribute(handle.getElement(), "cursor",
"e-resize");
break;
}
case ORIENTATION_VERTICAL_TOP_BOTTOM :
{
DOM.setStyleAttribute(cellOne.getElement(), "top", "0px");
DOM.setStyleAttribute(cellOne.getElement(), "left", "0px");
DOM.setStyleAttribute(cellOne.getElement(), "right", "0px");
DOM.setStyleAttribute(cellOne.getElement(), "width", "100%");
DOM.setStyleAttribute(cellTwo.getElement(), "bottom", "0px");
DOM.setStyleAttribute(cellTwo.getElement(), "left", "0px");
DOM.setStyleAttribute(cellTwo.getElement(), "right", "0px");
DOM.setStyleAttribute(cellTwo.getElement(), "width", "100%");
DOM.setStyleAttribute(handle.getElement(), "height",
getHandleSize()+"px");
DOM.setStyleAttribute(handle.getElement(), "width", "100%");
DOM.setStyleAttribute(handle.getElement(), "left", "0px");
DOM.setStyleAttribute(handle.getElement(), "right", "0px");
if (isResizable())
DOM.setStyleAttribute(handle.getElement(), "cursor",
"n-resize");
break;
}
case ORIENTATION_VERTICAL_BOTTOM_TOP :
{
DOM.setStyleAttribute(cellOne.getElement(), "bottom", "0px");
DOM.setStyleAttribute(cellOne.getElement(), "left", "0px");
DOM.setStyleAttribute(cellOne.getElement(), "right", "0px");
DOM.setStyleAttribute(cellTwo.getElement(), "top", "0px");
DOM.setStyleAttribute(cellTwo.getElement(), "left", "0px");
DOM.setStyleAttribute(cellTwo.getElement(), "right", "0px");
DOM.setStyleAttribute(cellTwo.getElement(), "width", "100%");
DOM.setStyleAttribute(handle.getElement(), "height",
getHandleSize()+"px");
DOM.setStyleAttribute(handle.getElement(), "width", "100%");
DOM.setStyleAttribute(handle.getElement(), "left", "0px");
DOM.setStyleAttribute(handle.getElement(), "right", "0px");
if (isResizable())
DOM.setStyleAttribute(handle.getElement(), "cursor",
"s-resize");
break;
}
}
super.add(cellOne);
super.add(handle);
super.add(cellTwo);
DOM.appendChild(wrapper, cellOne.getElement());
DOM.appendChild(wrapper, cellTwo.getElement());
DOM.appendChild(wrapper, handle.getElement());
updatePositions();
sinkEvents(Event.ONMOUSEUP | Event.ONMOUSEMOVE | Event.ONMOUSEDOWN);
}
/**
* Constructs the First Cell Pane in the SplitPanel
* Changes position based on the splitType attribute
* @param size - the Size in pixels of the first pane
* @return - returns the Pane Widget
*/
private void buildSplitPaneCellOne()
{
cellOne = new SplitPane();
DOM.setStyleAttribute(cellOne.getElement(), "overflow", "auto");
DOM.setStyleAttribute(cellOne.getElement(), "position", "absolute");
DOM.setStyleAttribute(cellOne.getElement(), "backgroundColor",
"#ffffcc");
}
private void buildSplitPaneDragHandle()
{
handle = new SplitPane();
DOM.setStyleAttribute(handle.getElement(), "position", "absolute");
DOM.setStyleAttribute(handle.getElement(), "fontSize", "1px");
DOM.setStyleAttribute(handle.getElement(), "lineHeight", "0");
DOM.setStyleAttribute(handle.getElement(), "overflow", "hidden");
DOM.setStyleAttribute(handle.getElement(), "backgroundColor",
HANDLE_BG_COLOR);
}
private void buildSplitPaneCellTwo()
{
cellTwo = new SplitPane();
DOM.setStyleAttribute(cellTwo.getElement(), "position", "absolute");
DOM.setStyleAttribute(cellTwo.getElement(), "overflow", "auto");
}
public void onBrowserEvent(Event event)
{
switch (DOM.eventGetType(event))
{
case Event.ONMOUSEDOWN: {
if(DOM.compare(handle.getElement(), DOM.eventGetTarget(event)))
{
System.out.println("MOSUEDOWN CALLED");
if(isOrientationVertical())
dragInitMouseOffset = DOM.eventGetClientY(event);
else
dragInitMouseOffset = DOM.eventGetClientX(event);
moving = true;
}
break;
}
case Event.ONMOUSEUP: {
System.out.println("MOUSEUP CALLED");
moving = false;
break;
}
case Event.ONMOUSEMOVE: {
if(moving)
{
System.out.println("MOVING "+moving);
mouseMove(event);
break;
}
}
}
//Don't forget to allow the normal event handling to occur.
super.onBrowserEvent(event);
}
private void setSeparatorPosition(int newPosition)
{
int totalSize = DOM.getIntAttribute(getElement(),
(isOrientationVertical()) ? "offsetHeight" : "offsetWidth");
if (newPosition > totalSize - getHandleSize())
separatorPosition = totalSize - getHandleSize();
else
separatorPosition = newPosition;
}
private void mouseMove(Event event)
{
switch (splitType)
{
case ORIENTATION_VERTICAL_TOP_BOTTOM :
{
setSeparatorPosition(separatorPosition +
DOM.eventGetClientY(event) - dragInitMouseOffset);
break;
}
case ORIENTATION_VERTICAL_BOTTOM_TOP:
{
setSeparatorPosition(separatorPosition -
DOM.eventGetClientY(event) + dragInitMouseOffset);
break;
}
case ORIENTATION_HORIZONTAL_LEFT_RIGHT:
{
setSeparatorPosition(separatorPosition +
DOM.eventGetClientX(event) - dragInitMouseOffset);
break;
}
case ORIENTATION_HORIZONTAL_RIGHT_LEFT:
{
setSeparatorPosition(separatorPosition -
DOM.eventGetClientX(event) + dragInitMouseOffset);
break;
}
}
DOM.eventPreventDefault(event);
updatePositions();
}
private void updatePositions()
{
switch (splitType)
{
case ORIENTATION_VERTICAL_TOP_BOTTOM:
DOM.setStyleAttribute(cellOne.getElement(), "height",
(separatorPosition > 0 ? separatorPosition : 0) + "px");
DOM.setStyleAttribute(cellTwo.getElement(), "top",
(separatorPosition + getHandleSize()) + "px");
DOM.setStyleAttribute(handle.getElement(), "top",
separatorPosition + "px");
break;
case ORIENTATION_VERTICAL_BOTTOM_TOP:
DOM.setStyleAttribute(cellOne.getElement(), "height",
(separatorPosition > 0 ? separatorPosition : 0) + "px");
DOM.setStyleAttribute(cellTwo.getElement(), "bottom",
(separatorPosition + getHandleSize()) + "px");
DOM.setStyleAttribute(handle.getElement(), "bottom",
separatorPosition + "px");
break;
case ORIENTATION_HORIZONTAL_LEFT_RIGHT:
DOM.setStyleAttribute(cellOne.getElement(), "width",
(separatorPosition > 0 ? separatorPosition : 0) + "px");
DOM.setStyleAttribute(cellTwo.getElement(), "left",
(separatorPosition + getHandleSize()) + "px");
DOM.setStyleAttribute(handle.getElement(), "left",
separatorPosition + "px");
break;
case ORIENTATION_HORIZONTAL_RIGHT_LEFT:
DOM.setStyleAttribute(cellOne.getElement(), "width",
(separatorPosition > 0 ? separatorPosition : 0) + "px");
DOM.setStyleAttribute(cellTwo.getElement(), "right",
(separatorPosition + getHandleSize()) + "px");
DOM.setStyleAttribute(handle.getElement(), "right",
separatorPosition + "px");
break;
}
}
private boolean isOrientationVertical()
{
return (this.splitType == ORIENTATION_VERTICAL_TOP_BOTTOM
|| this.splitType == ORIENTATION_VERTICAL_BOTTOM_TOP);
}
/**
* Adds a widget to the splitPane. You can only add two widgets.
* The first one is added to the left of the split, then the second
* is added to the right of the splitpane
* @param w
*/
public boolean add(Widget w)
{
boolean returnVal = false;
if(widgetCount==0)
{
returnVal = cellOne.add(w);
widgetCount++;
}
else if(widgetCount==1)
{
returnVal = cellTwo.add(w);
widgetCount++;
}
return returnVal;
}
public boolean remove(Widget w)
{
if(cellOne.getWidget(0)!=null && cellOne.getWidget(0).equals(w))
return cellOne.remove(w);
if(cellTwo.getWidget(0)!=null && cellTwo.getWidget(0).equals(w))
return cellTwo.remove(w);
return false;
}
public void setHandleBGColor(String handleBGColor)
{
DOM.setStyleAttribute(handle.getElement(), "backgroundColor",
handleBGColor);
}
public void setHandleSize(int handleWidthPx) {
DOM.setStyleAttribute(handle.getElement(), "width",
handleWidthPx+"px");
}
public int getHandleSize()
{
String width = DOM.getStyleAttribute(handle.getElement(), "width");
if(width==null || width.indexOf("px")==-1) return
HANDLE_DEFAULT_WIDTH;
return Integer.parseInt(width.replaceFirst("px",""));
}
public void setHeight(String height)
{
return; //Width and height of spitPane is 100%. Parent determines
size.
}
public void setSize(String width, String height) {
return; //Width and height of spitPane is 100%. Parent determines
size.
}
public void setWidth(String width) {
return; //Width and height of spitPane is 100%. Parent determines
size.
}
public void setPixelSize(int width, int height) {
return; //Width and height of spitPane is 100%. Parent determines
size.
}
public boolean isResizable() {
return resizable;
}
public void setResizable(boolean resizable) {
this.resizable = resizable;
}
protected void onLoad() {
// TODO Auto-generated method stub
System.out.println("ON LOAD CALLED");
System.out.println(cellOne.getParent().getAbsoluteLeft());
changeHeight(getElement(), parentHeightExpression);
changeHeight(cellOne.getElement(), parentHeightExpression);
changeHeight(cellTwo.getElement(), parentHeightExpression);
}
public native void changeHeight(Element elem, String newHeight) /*-{
if(elem.style && elem.style.setExpression)
{
elem.style.setExpression("height",
"this.parentNode.clientHeight-this.offsetTop");
}
}-*/;
}