/******************************************************************************* * Copyright (c) 2000, 2005 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 * Exadel, Inc. * Red Hat, Inc. *******************************************************************************/ package org.jboss.tools.common.gef.xpl; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import org.eclipse.swt.*; import org.eclipse.swt.widgets.*; import org.eclipse.swt.graphics.*; import org.eclipse.draw2d.ColorConstants; public class GEFSplitter extends Composite { private static final int SASH_WIDTH = 5; private static final int FIXED_DRAG_MINIMUM = 62; private static final int OTHER_DRAG_MINIMUM = 0; private static final String MAINTAIN_SIZE = "maintain size"; //$NON-NLS-1$ private int fixedSize = 150; private int fixedDragMinimum; private int otherDragMinimum; private int orientation = SWT.HORIZONTAL; private Sash[] sashes = new Sash[0]; private Control[] controls = new Control[0]; private Control maxControl = null; private Listener sashListener; private boolean first = true; 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 GEFSplitter(Composite parent, int style) { this(parent, style, FIXED_DRAG_MINIMUM, OTHER_DRAG_MINIMUM); } public GEFSplitter(Composite parent, int style, int fixedDragMinimum) { this(parent, style, fixedDragMinimum, OTHER_DRAG_MINIMUM); } public GEFSplitter(Composite parent, int style, int fixedDragMinimum, int otherDragMinimum) { super(parent, checkStyle(style)); this.fixedDragMinimum = fixedDragMinimum; this.otherDragMinimum = otherDragMinimum; if ((style & SWT.VERTICAL) != 0) { orientation = SWT.VERTICAL; } 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) * SASH_WIDTH; } else { height = hHint; width += controls.length * SASH_WIDTH; } 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; } } return new Point(width, height); } public int getOrientation() { return orientation; } 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; } 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); newSashes[i].addListener(SWT.Paint, new SashPainter()); 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; if (orientation == SWT.HORIZONTAL) { 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 - SASH_WIDTH; } } else { width = Math.max(area.width - fixedSize - SASH_WIDTH, 0); } control.setBounds(x, area.y, width, area.height); x += (width + SASH_WIDTH); } sashes[0].setBounds(controls[0].getBounds().x + controls[0].getBounds().width, area.y, SASH_WIDTH, area.height); } else { int y = area.y; int height; for (int i = 0; i < controls.length; i++) { Control control = controls[i]; if (control.getData(MAINTAIN_SIZE) != null) { height = fixedSize; if (height > area.height) { height = area.height - SASH_WIDTH; } } else { height = Math.max(area.height - fixedSize - SASH_WIDTH, 0); } control.setBounds(area.x, y, area.width, height); y += (height + SASH_WIDTH); } sashes[0].setBounds(area.x, controls[0].getBounds().y + controls[0].getBounds().height, area.width, SASH_WIDTH); } } 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, Boolean.TRUE); } } } void paint(Sash sash, GC gc) { if (first) { first = false; getParent().layout(); } Point size = sash.getSize(); if (getOrientation() == SWT.HORIZONTAL) { gc.setForeground(ColorConstants.buttonDarker); gc.drawLine(SASH_WIDTH - 1, 0, SASH_WIDTH - 1, size.y); gc.setForeground(ColorConstants.buttonLightest); gc.drawLine(0, 0, 0, size.y); } else { gc.setForeground(ColorConstants.buttonDarker); gc.drawLine(0, SASH_WIDTH - 1, size.x, SASH_WIDTH - 1); gc.setForeground(ColorConstants.buttonLightest); gc.drawLine(0, 0, size.x, 0); } } private void onDragSash(Event event) { if (event.detail == SWT.DRAG) { Rectangle area = getClientArea(); if (orientation == SWT.HORIZONTAL) { if (controls[0].getData(MAINTAIN_SIZE) != null) { event.x = Math.max(Math.min(area.width - otherDragMinimum - SASH_WIDTH, event.x), fixedDragMinimum); } else { event.x = Math.min(Math.max(otherDragMinimum, event.x), area.width - fixedDragMinimum - SASH_WIDTH); } } else { if (controls[0].getData(MAINTAIN_SIZE) != null) { event.x = Math.max(Math.min(area.height - otherDragMinimum - SASH_WIDTH, event.y), fixedDragMinimum); } else { event.x = Math.min(Math.max(otherDragMinimum, event.y), area.height - fixedDragMinimum - SASH_WIDTH); } } 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(); Rectangle sashBounds = sash.getBounds(); if (orientation == SWT.HORIZONTAL) { int shift = event.x - sashBounds.x; if (shift == 0) { return; } b1.width += shift; b2.x += shift; b2.width -= shift; } else { int shift = event.y - sashBounds.y; if (shift == 0) { return; } 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); if (orientation == SWT.HORIZONTAL) { if (c1.getData(MAINTAIN_SIZE) != null) { setFixedSize(c1.getBounds().width); } else { setFixedSize(c2.getBounds().width); } } else { if (c1.getData(MAINTAIN_SIZE) != null) { setFixedSize(c1.getBounds().height); } else { setFixedSize(c2.getBounds().height); } } } 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 setLayout (Layout layout) { } 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(); } }