/*
* Copyright (c) 2011, Nikolaus Moll
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the jo-widgets.org nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL jo-widgets.org BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package org.jowidgets.spi.impl.swt.common.widgets.base;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
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.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Sash;
import org.jowidgets.common.types.Orientation;
import org.jowidgets.common.types.SplitResizePolicy;
import org.jowidgets.spi.impl.swt.common.options.SplitlayoutMode;
import org.jowidgets.spi.impl.swt.common.options.SwtOptions;
import org.jowidgets.spi.impl.swt.common.util.OrientationConvert;
import org.jowidgets.spi.widgets.setup.ISplitCompositeSetupSpi;
public class JoSashForm extends Composite {
private static final int SPLIT_MINIMUM = 0;
private double weight = -1;
private int sashSize;
private Sash sash;
private final ISashOrientationUtil sashUtil;
private Control first;
private Control second;
private Point firstMinSize;
private Point secondMinSize;
private JoSashFormLayout layout;
private final SplitResizePolicy resizePolicy;
public JoSashForm(final Composite parent, final ISplitCompositeSetupSpi setup) {
super(parent, getSashFormStyle(setup));
resizePolicy = setup.getResizePolicy();
sashUtil = getSashUtil(setup);
layout = new JoSashFormLayout(this, sashUtil);
setLayout(layout);
sash = new Sash(this, getSashStyle(setup));
sash.setToolTipText(getToolTipText());
sash.addListener(SWT.Selection, new Listener() {
@Override
public void handleEvent(final Event event) {
if (event.detail == SWT.DRAG) {
return;
}
onDragSash(event);
}
});
firstMinSize = new Point(SPLIT_MINIMUM, SPLIT_MINIMUM);
secondMinSize = new Point(SPLIT_MINIMUM, SPLIT_MINIMUM);
}
public void setWeight(final double weight) {
setWeight(weight, true);
}
void setWeight(final double weight, final boolean doLayout) {
if ((weight < 0) || (weight > 1)) {
throw new IllegalArgumentException("Illegal weight (must be between 0 and 1, is " + weight + ")");
}
this.weight = weight;
layout.resetRemeberedSize();
if (doLayout) {
layout(true);
}
}
public double getWeight() {
if (weight < -1) {
// if no weight is set return preferred weight
return getPreferredWeight();
}
return weight;
}
public void setSashSize(final int sashSize) {
if (this.sashSize == sashSize) {
return;
}
this.sashSize = sashSize;
layout(true);
}
public int getSashSize() {
return sashSize;
}
/**
* User has dragged sash
*
* @param event
*/
private void onDragSash(final Event event) {
final Rectangle area = getClientArea();
final int totalSize = sashUtil.getSize(area);
final int targetPos = sashUtil.getEventPos(event);
final int firstSize = Math.max(targetPos, sashUtil.getSize(firstMinSize));
final int secondSize = totalSize - sashSize - firstSize;
event.doit = ((targetPos >= sashUtil.getSize(firstMinSize))
&& (targetPos + sashSize <= totalSize - sashUtil.getSize(secondMinSize)));
if ((firstSize != sashUtil.getSize(first.getBounds())) && (event.doit) && (event.detail != SWT.DRAG)) {
weight = (double) firstSize / (totalSize - sashSize);
setChildrenBounds(area, firstSize, secondSize);
}
}
void setChildrenBounds(final Rectangle area, final int firstSize, final int secondSize) {
final Rectangle firstBounds = sashUtil.createBounds(area, sashUtil.getPosition(area), firstSize);
final Rectangle sashBounds = sashUtil.createBounds(area, sashUtil.getPosition(firstBounds) + firstSize, sashSize);
final Rectangle secondBounds = sashUtil.createBounds(area, sashUtil.getPosition(sashBounds) + sashSize, secondSize);
first.setBounds(firstBounds);
if (!sash.getBounds().equals(sashBounds)) {
sash.setBounds(sashBounds);
}
if (!second.getBounds().equals(secondBounds)) {
second.setBounds(secondBounds);
}
}
private Control getChild(int childIndex) {
final Control[] children = getChildren();
int index = 0;
while (index < children.length) {
// ignore the sash
if (children[index] == this.sash) {
childIndex++;
}
else if (index == childIndex) {
return children[index];
}
index++;
}
return null;
}
public Control getFirst() {
if (first == null) {
first = getChild(0);
}
return first;
}
public Control getSecond() {
if (second == null) {
second = getChild(1);
}
return second;
}
public Sash getSash() {
return sash;
}
public SplitResizePolicy getResizePolicy() {
return resizePolicy;
}
public void setMinSizes(final Point firstMinSize, final Point secondMinSize) {
this.firstMinSize = firstMinSize;
this.secondMinSize = secondMinSize;
layout(true);
}
public Point getFirstMinSize() {
return firstMinSize;
}
public Point getSecondMinSize() {
return secondMinSize;
}
@Override
public void setBackground(final Color color) {
super.setBackground(color);
sash.setBackground(color);
}
@Override
public void setForeground(final Color color) {
super.setForeground(color);
sash.setForeground(color);
}
private double getPreferredWeight() {
if (first == null) {
return 0;
}
if (second == null) {
return 1;
}
final int firstSize = sashUtil.getSize(first.computeSize(SWT.DEFAULT, SWT.DEFAULT));
final int secondSize = sashUtil.getSize(first.computeSize(SWT.DEFAULT, SWT.DEFAULT));
final int totalSize = firstSize + secondSize;
return (double) firstSize / totalSize;
}
private static int getSashFormStyle(final ISplitCompositeSetupSpi setup) {
final Orientation orientation = setup.getOrientation();
final int style = OrientationConvert.convert(orientation);
final int mask = SWT.BORDER | SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT;
return style & mask;
}
private static int getSashStyle(final ISplitCompositeSetupSpi setup) {
final Orientation orientation = setup.getOrientation();
final int style;
if (Orientation.HORIZONTAL == orientation) {
style = SWT.VERTICAL;
}
else if (Orientation.VERTICAL == orientation) {
style = SWT.HORIZONTAL;
}
else {
throw new IllegalStateException("Wrong Orientation is set");
}
if (SwtOptions.getSplitLayoutMode().equals(SplitlayoutMode.ON_MOUSE_MOVE)) {
return style | SWT.SMOOTH;
}
else {
return style;
}
}
private static ISashOrientationUtil getSashUtil(final ISplitCompositeSetupSpi setup) {
if (setup.getOrientation() == Orientation.HORIZONTAL) {
return SashOrientationUtil.HORIZONTAL;
}
else if (setup.getOrientation() == Orientation.VERTICAL) {
return SashOrientationUtil.VERTICAL;
}
else {
throw new IllegalStateException("Wrong Orientation is set");
}
}
}