SWT BorderLayout v2

続き。リファクタリングして、spacing(AWTのBorderLayoutでいうところのhgap, vgap)を指定できるようにした。
LayoutDataとしてStringというかBorderLayout.CENTERみたいに書きたかったのでその辺は変更なし。

以下例によってソース丸ごと。次はFlowLayoutかな。

package net.dotinterface.layout;

import org.eclipse.swt.SWT;
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.Layout;

// TODO margin support
public class BorderLayout extends Layout {
	public static final String NORTH = "NORTH";

	public static final String WEST = "WEST";

	public static final String CENTER = "CENTER";

	public static final String EAST = "EAST";

	public static final String SOUTH = "SOUTH";

	public int horizontalSpacing;

	public int verticalSpacing;

	public BorderLayout() {
		this(0, 0);
	}

	public BorderLayout(int horizontalSpacing, int verticalSpacing) {
		this.horizontalSpacing = horizontalSpacing;
		this.verticalSpacing = verticalSpacing;
	}

	private static class Border {
		final String name;

		Control ctrl;

		Point size = new Point(0, 0);

		Border(String name) {
			this.name = name;
		}
	}

	private static class Borders {
		final Border north = new Border(NORTH);

		final Border west = new Border(WEST);

		final Border center = new Border(CENTER);

		final Border east = new Border(EAST);

		final Border south = new Border(SOUTH);

		final Border items = { north, west, center, east, south };
	}

	protected Point computeSize(Composite composite, int wHint, int hHint,
			boolean flushCache) {
		Borders borders = borders(composite);
		return new Point(computeMaxWidth(borders), computeMaxHeight(borders));
	}

	private Borders borders(Composite composite) {
		Borders borders = new Borders();
		Control children = composite.getChildren();
		for (int i = 0; i < children.length; i++) {
			Control c = children[i];
			Object data = c.getLayoutData();
			String bs = data instanceof String ? (String) data : CENTER;
			for (int j = 0; j < borders.items.length; j++) {
				Border b = borders.items[j];
				if (bs.equals(b.name)) {
					if (c.isVisible()) {
						b.ctrl = c;
						b.size = c.computeSize(SWT.DEFAULT, SWT.DEFAULT);
					} else {
						b.ctrl = null;
					}
					break;
				}
			}
		}
		return borders;
	}

	private int computeMaxWidth(Borders borders) {
		boolean west = borders.west.ctrl != null;
		boolean center = borders.center.ctrl != null;
		boolean east = borders.east.ctrl != null;

		int nw = borders.north.size.x;
		int ww = borders.west.size.x;
		int cw = borders.center.size.x;
		int ew = borders.east.size.x;
		int sw = borders.south.size.x;

		if (west && center) {
			cw += horizontalSpacing;
		}
		if (center && east) {
			cw += horizontalSpacing;
		}

		return Math.max(Math.max(nw, ww + cw + ew), sw);
	}

	private int computeMaxHeight(Borders borders) {
		boolean north = borders.north.ctrl != null;
		boolean west = borders.west.ctrl != null;
		boolean center = borders.center.ctrl != null;
		boolean east = borders.east.ctrl != null;
		boolean south = borders.south.ctrl != null;

		int nh = borders.north.size.y;
		int wh = borders.west.size.y;
		int ch = borders.center.size.y;
		int eh = borders.east.size.y;
		int sh = borders.south.size.y;

		if (north && west) {
			wh += verticalSpacing;
		}
		if (west && south) {
			wh += verticalSpacing;
		}

		if (north && center) {
			ch += verticalSpacing;
		}
		if (center && south) {
			ch += verticalSpacing;
		}

		if (north && east) {
			eh += verticalSpacing;
		}
		if (east && south) {
			eh += verticalSpacing;
		}

		return nh + Math.max(Math.max(wh, ch), eh) + sh;
	}

	protected void layout(Composite composite, boolean flushCache) {
		Rectangle ps = composite.getClientArea();
		int pw = ps.width, ph = ps.height;
		int cx = 0, cy = 0, cw = pw, ch = ph;

		Borders borders = borders(composite);

		Control nc = borders.north.ctrl;
		Control sc = borders.south.ctrl;
		Control wc = borders.west.ctrl;
		Control ec = borders.east.ctrl;
		Control cc = borders.center.ctrl;

		if (nc != null) { // NORTH
			int nh = borders.north.size.y;
			nc.setBounds(0, 0, cw, nh);
			if (cc != null || sc != null) {
				nh += verticalSpacing;
			}
			cy += nh;
			ch -= nh;
		}

		if (sc != null) { // SOUTH
			int sh = borders.south.size.y;
			sc.setBounds(0, ph - sh, cw, sh);
			if (cc != null) {
				sh += verticalSpacing;
			}
			ch -= sh;
		}

		if (wc != null) { // WEST
			int ww = borders.west.size.x;
			wc.setBounds(0, cy, ww, ch);
			if (cc != null || ec != null) {
				ww += horizontalSpacing;
			}
			cx += ww;
			cw -= ww;
		}

		if (ec != null) { // EAST
			int ew = borders.east.size.x;
			ec.setBounds(pw - ew, cy, ew, ch);
			if (cc != null) {
				ew += horizontalSpacing;
			}
			cw -= ew;
		}

		if (cc != null) { // CENTER
			cc.setBounds(cx, cy, cw, ch);
		}
	}
}