blob: 670ca3391fb82355e7ab01621fee7e296434abf1 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.gef.ui.parts;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.ControlPaintHandler;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Sash;
import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.rap.swt.SWT;
class Splitter extends Composite {
public static final int DEFAULT_SASH_WIDTH = 5;
private static final int DRAG_MINIMUM = 62;
private static final String MAINTAIN_SIZE = "maintain size"; //$NON-NLS-1$
private int fixedSize = 150;
private int orientation = SWT.VERTICAL;
private Sash[] sashes = new Sash[0];
private Control[] controls = new Control[0];
private Control maxControl = null;
private Listener sashListener;
private int sashWidth = DEFAULT_SASH_WIDTH;
/**
* PropertyChangeSupport
*/
protected PropertyChangeSupport listeners = new PropertyChangeSupport(this);
public void addFixedSizeChangeListener(PropertyChangeListener listener) {
listeners.addPropertyChangeListener(listener);
}
protected void firePropertyChange(int oldValue, int newValue) {
listeners.firePropertyChange(MAINTAIN_SIZE, oldValue, newValue);
}
public void removeFixedSizeChangeListener(PropertyChangeListener listener) {
listeners.removePropertyChangeListener(listener);
}
public int getFixedSize() {
return fixedSize;
}
public void setFixedSize(int newSize) {
if (newSize == fixedSize) {
return;
}
firePropertyChange(fixedSize, fixedSize = newSize);
}
class SashPainter implements Listener {
public void handleEvent(Event e) {
paint((Sash) e.widget, e.gc);
}
}
public Splitter(Composite parent, int style) {
super(parent, checkStyle(style));
if ((style & SWT.HORIZONTAL) != 0)
orientation = SWT.HORIZONTAL;
this.addListener(SWT.Resize, new Listener() {
public void handleEvent(Event e) {
layout(true);
}
});
sashListener = new Listener() {
public void handleEvent(Event e) {
onDragSash(e);
}
};
}
private static int checkStyle(int style) {
int mask = SWT.BORDER;
return style & mask;
}
public Point computeSize(int wHint, int hHint, boolean changed) {
Control[] controls = getControls(true);
if (controls.length == 0)
return new Point(wHint, hHint);
int width = 0;
int height = 0;
boolean vertical = (getStyle() & SWT.VERTICAL) != 0;
if (vertical) {
width = wHint;
height += (controls.length - 1) * getSashWidth();
} else {
height = hHint;
width += controls.length * getSashWidth();
}
for (int i = 0; i < controls.length; i++) {
if (vertical) {
Point size = controls[i].computeSize(wHint, SWT.DEFAULT);
height += size.y;
} else {
Point size = controls[i].computeSize(SWT.DEFAULT, hHint);
if (controls[i].getData(MAINTAIN_SIZE) != null) {
size.x = fixedSize;
}
width += size.x;
}
}
// if (wHint != SWT.DEFAULT) width = wHint;
// if (hHint != SWT.DEFAULT) height = hHint;
return new Point(width, height);
}
/**
* Answer SWT.HORIZONTAL if the controls in the SashForm are laid out side
* by side. Answer SWT.VERTICAL if the controls in the SashForm are laid out
* top to bottom.
*/
public int getOrientation() {
return orientation;
}
public int getSashWidth() {
return sashWidth;
}
/**
* Answer the control that currently is maximized in the SashForm. This
* value may be null.
*/
public Control getMaximizedControl() {
return this.maxControl;
}
private Control[] getControls(boolean onlyVisible) {
Control[] children = getChildren();
Control[] controls = new Control[0];
for (int i = 0; i < children.length; i++) {
if (children[i] instanceof Sash)
continue;
if (onlyVisible && !children[i].getVisible())
continue;
Control[] newControls = new Control[controls.length + 1];
System.arraycopy(controls, 0, newControls, 0, controls.length);
newControls[controls.length] = children[i];
controls = newControls;
}
return controls;
}
public void layout(boolean changed) {
Rectangle area = getClientArea();
if (area.width == 0 || area.height == 0)
return;
Control[] newControls = getControls(true);
if (controls.length == 0 && newControls.length == 0)
return;
controls = newControls;
if (maxControl != null && !maxControl.isDisposed()) {
for (int i = 0; i < controls.length; i++) {
if (controls[i] != maxControl) {
controls[i].setBounds(-200, -200, 0, 0);
} else {
controls[i].setBounds(area);
}
}
return;
}
// keep just the right number of sashes
if (sashes.length < controls.length - 1) {
Sash[] newSashes = new Sash[controls.length - 1];
System.arraycopy(sashes, 0, newSashes, 0, sashes.length);
int sashOrientation = (orientation == SWT.HORIZONTAL) ? SWT.VERTICAL
: SWT.HORIZONTAL;
for (int i = sashes.length; i < newSashes.length; i++) {
newSashes[i] = new Sash(this, sashOrientation);
newSashes[i].setBackground(ColorConstants.button);
ControlPaintHandler helper = new ControlPaintHandler(
newSashes[i]);
helper.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent e) {
paint((Sash) e.widget, e.gc);
}
});
newSashes[i].addListener(SWT.Selection, sashListener);
}
sashes = newSashes;
}
if (sashes.length > controls.length - 1) {
if (controls.length == 0) {
for (int i = 0; i < sashes.length; i++) {
sashes[i].dispose();
}
sashes = new Sash[0];
} else {
Sash[] newSashes = new Sash[controls.length - 1];
System.arraycopy(sashes, 0, newSashes, 0, newSashes.length);
for (int i = controls.length - 1; i < sashes.length; i++) {
sashes[i].dispose();
}
sashes = newSashes;
}
}
if (controls.length == 0)
return;
// @TODO
// This only works if the orientation is horizontal, there are two
// children and one
// of them has been set to maintain its size.
int x = area.x;
int width;
for (int i = 0; i < controls.length; i++) {
Control control = controls[i];
if (control.getData(MAINTAIN_SIZE) != null) {
width = fixedSize;
if (width > area.width) {
width = area.width - getSashWidth();
}
control.setBounds(x, area.y, width, area.height);
x += width + getSashWidth();
} else {
width = Math.max(area.width - fixedSize - getSashWidth(), 0);
control.setBounds(x, area.y, width, area.height);
x += (width + getSashWidth());
}
}
if (sashes.length > 0)
sashes[0].setBounds(
controls[0].getBounds().x + controls[0].getBounds().width,
area.y, getSashWidth(), area.height);
}
public void maintainSize(Control c) {
Control[] controls = getControls(false);
for (int i = 0; i < controls.length; i++) {
Control ctrl = controls[i];
if (ctrl == c) {
ctrl.setData(MAINTAIN_SIZE, new Boolean(true));
break;
}
}
}
void paint(Sash sash, GC gc) {
if (getSashWidth() == 0)
return;
Point size = sash.getSize();
if (getOrientation() == SWT.HORIZONTAL) {
gc.setForeground(ColorConstants.buttonDarker);
gc.drawLine(getSashWidth() - 1, 0, getSashWidth() - 1, size.y);
gc.setForeground(ColorConstants.buttonLightest);
gc.drawLine(0, 0, 0, size.y);
} else {
gc.setForeground(ColorConstants.buttonDarker);
gc.drawLine(0, 0, size.x, 0);
gc.drawLine(0, getSashWidth() - 1, size.x, getSashWidth() - 1);
gc.setForeground(ColorConstants.buttonLightest);
gc.drawLine(0, 1, size.x, 1);
}
}
private void onDragSash(Event event) {
if (event.detail == SWT.DRAG) {
// constrain feedback
Rectangle area = getClientArea();
if (orientation == SWT.HORIZONTAL) {
if (controls[0].getData(MAINTAIN_SIZE) != null) {
event.x = Math.max(event.x, DRAG_MINIMUM);
} else {
event.x = Math.min(event.x, area.width - DRAG_MINIMUM
- getSashWidth());
}
} else {
event.y = Math.min(event.y, area.height - DRAG_MINIMUM
- getSashWidth());
}
return;
}
Sash sash = (Sash) event.widget;
int sashIndex = -1;
for (int i = 0; i < sashes.length; i++) {
if (sashes[i] == sash) {
sashIndex = i;
break;
}
}
if (sashIndex == -1)
return;
Control c1 = controls[sashIndex];
Control c2 = controls[sashIndex + 1];
Rectangle b1 = c1.getBounds();
Rectangle b2 = c2.getBounds();
controls = getControls(false);
Rectangle sashBounds = sash.getBounds();
if (orientation == SWT.HORIZONTAL) {
int shift = event.x - sashBounds.x;
b1.width += shift;
b2.x += shift;
b2.width -= shift;
} else {
int shift = event.y - sashBounds.y;
b1.height += shift;
b2.y += shift;
b2.height -= shift;
}
c1.setBounds(b1);
sash.setBounds(event.x, event.y, event.width, event.height);
c2.setBounds(b2);
// @TODO
// This will only work when you have two controls, one of whom is set to
// maintain size
if (c1.getData(MAINTAIN_SIZE) != null) {
setFixedSize(c1.getBounds().width);
} else {
setFixedSize(c2.getBounds().width);
}
}
/**
* If orientation is SWT.HORIZONTAL, lay the controls in the SashForm out
* side by side. If orientation is SWT.VERTICAL, lay the controls in the
* SashForm out top to bottom.
*/
public void setOrientation(int orientation) {
if (this.orientation == orientation)
return;
if (orientation != SWT.HORIZONTAL && orientation != SWT.VERTICAL) {
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
}
this.orientation = orientation;
int sashOrientation = (orientation == SWT.HORIZONTAL) ? SWT.VERTICAL
: SWT.HORIZONTAL;
for (int i = 0; i < sashes.length; i++) {
sashes[i].dispose();
sashes[i] = new Sash(this, sashOrientation);
sashes[i].setBackground(ColorConstants.buttonLightest);
sashes[i].addListener(SWT.Selection, sashListener);
}
layout();
}
public void setSashWidth(int width) {
sashWidth = width;
}
public void setLayout(Layout layout) {
// SashForm does not use Layout
}
/**
* Specify the control that should take up the entire client area of the
* SashForm. If one control has been maximized, and this method is called
* with a different control, the previous control will be minimized and the
* new control will be maximized.. if the value of control is null, the
* SashForm will minimize all controls and return to the default layout
* where all controls are laid out separated by sashes.
*/
public void setMaximizedControl(Control control) {
if (control == null) {
if (maxControl != null) {
this.maxControl = null;
layout();
for (int i = 0; i < sashes.length; i++) {
sashes[i].setVisible(true);
}
}
return;
}
for (int i = 0; i < sashes.length; i++) {
sashes[i].setVisible(false);
}
maxControl = control;
layout();
}
}