/*******************************************************************************
* Copyright (c) 2009 the CHISEL group and contributors.
* 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:
* Del Myers -- initial API and implementation
*******************************************************************************/
package org.eclipse.zest.custom.sequence.figures;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.draw2d.AbstractLayout;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.draw2d.geometry.Transposer;
import org.eclipse.zest.custom.sequence.figures.SashFigure.SashBarFigure;
/**
* Layout for sash forms.
* @author Del Myers
*/
public class SashLayout extends AbstractLayout {
public static final int SASH_BAR_SIZE = 5;
private boolean isHorizontal;
private int[] sashSizes;
private int padding;
private Dimension lastSize;
public SashLayout(boolean horizontal) {
this.isHorizontal = horizontal;
sashSizes = new int[0];
lastSize = new Dimension();
}
/* (non-Javadoc)
* @see org.eclipse.draw2d.AbstractLayout#getMinimumSize(org.eclipse.draw2d.IFigure, int, int)
*/
@Override
public Dimension getMinimumSize(IFigure container, int wHint, int hHint) {
Dimension preferred = getPreferredSize(container, wHint, hHint);
Dimension result = new Dimension(Math.min(preferred.width, wHint), Math.min(preferred.height, hHint));
return result;
}
/* (non-Javadoc)
* @see org.eclipse.draw2d.AbstractLayout#calculatePreferredSize(org.eclipse.draw2d.IFigure, int, int)
*/
@Override
protected Dimension calculatePreferredSize(IFigure container, int wHint,
int hHint) {
int width = 0;
int height = 0;
Transposer t = new Transposer();
t.setEnabled(isHorizontal);
List<?> children = container.getChildren();
for (Object o : children) {
Dimension size = ((IFigure)o).getPreferredSize(wHint, hHint);
t.t(size);
height += size.height;
if (size.width > width) {
width = size.width;
}
}
height += (SASH_BAR_SIZE+padding+padding) * (children.size()-1);
Dimension d = new Dimension(
Math.max(wHint, width),
Math.max(hHint, height)
);
return t.t(d);
}
/* (non-Javadoc)
* @see org.eclipse.draw2d.LayoutManager#layout(org.eclipse.draw2d.IFigure)
*/
public void layout(IFigure container) {
resetSashBars(container);
List<?> children = container.getChildren();
Transposer t = new Transposer();
t.setEnabled(isHorizontal);
Rectangle bounds = t.t(container.getClientArea());
int x = bounds.x;
int y = bounds.y;
int pad = padding+padding;
Dimension sashSize = new Dimension(bounds.width, SASH_BAR_SIZE);
for (int i = 0; i < children.size(); i++) {
IFigure child = (IFigure) children.get(i);
if (child instanceof SashBarFigure) {
Rectangle barBounds = new Rectangle(new Point(x,y), sashSize);
y+= pad + SASH_BAR_SIZE;
child.setBounds(t.t(barBounds));
} else {
int size = sashSizes[i/2];
Rectangle newBounds = new Rectangle(x, y, bounds.width, size);
y += size;
if (!(child instanceof SashFigure)) {
newBounds.shrink(padding, padding);
y+= pad;
}
child.setBounds(t.t(newBounds));
}
}
}
public void resetSashBars(IFigure sashContainer) {
List<?> children = sashContainer.getChildren();
if (children.size()/2 + 1!= sashSizes.length || !lastSize.equals(sashContainer.getSize())) {
lastSize = sashContainer.getSize().getCopy();
int[] newSizes = new int[children.size()/2 + 1];
int i = 0;
for (i = 0; i < sashSizes.length; i++) {
if (i >= newSizes.length) break;
newSizes[i] = sashSizes[i];
}
for (; i < newSizes.length; i++) {
newSizes[i] = -1;
}
sashSizes = newSizes;
//reset the constraints to fill up the container's area.
Dimension containerSize = sashContainer.getSize();
int majorSize = (isHorizontal) ? containerSize.width : containerSize.height;
int maximumArea = majorSize - (children.size()-1)*SASH_BAR_SIZE;
if (maximumArea < 0) {
maximumArea = 0;
}
int areaLeft = maximumArea;
List<Integer> uninitialized = new LinkedList<Integer>();
for (i = 0; i < sashSizes.length; i++) {
if (sashSizes[i] >= 0) {
if (sashSizes[i] > areaLeft) {
sashSizes[i] = areaLeft;
}
areaLeft -= sashSizes[i];
} else {
uninitialized.add(i);
}
}
if (uninitialized.size() > 0) {
int distributed = areaLeft/uninitialized.size();
int pad = areaLeft % uninitialized.size();
for (int u : uninitialized) {
sashSizes[u] = distributed;
}
sashSizes[uninitialized.get(0)] += pad;
} else if (areaLeft > 0) {
//add it to the end
sashSizes[sashSizes.length-1] += areaLeft;
}
}
}
public void moveSashBar(IFigure sashContainer, int index, int difference) {
resetSashBars(sashContainer);
if (index >= sashSizes.length-1) return;
if (index < 0) return;
int successor = sashSizes[index+1] - difference;
int newSize = sashSizes[index] + difference;
if (newSize < 0) {
successor = sashSizes[index+1] + sashSizes[index];
newSize = 0;
} else if (successor < 0) {
newSize = sashSizes[index] + sashSizes[index+1];
successor = 0;
}
sashSizes[index] = newSize;
sashSizes[index+1] = successor;
sashContainer.revalidate();
}
public int getSashBarCount(IFigure sashContainer) {
resetSashBars(sashContainer);
return sashSizes.length -1;
}
public int getSashBarSize(IFigure sashContainer, int index) {
if (index < 0 || index > getSashBarCount(sashContainer)) {
return -1;
}
return sashSizes[index];
}
/**
* Sets padding around the sashes.
* @param padding the amount of space surrounding the sashes.
*/
public void setPadding(int padding) {
this.padding = padding;
}
/**
* @return the padding
*/
public int getPadding() {
return padding;
}
}