changeset 51:e300eb95bec4

RowData, RowLayout
author Frank Benoit <benoit@tionex.de>
date Fri, 11 Jan 2008 10:57:51 +0100
parents d48f7334742c
children 47febc12f0a7
files dwt/layout/RowData.d dwt/layout/RowLayout.d
diffstat 2 files changed, 603 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/layout/RowData.d	Fri Jan 11 10:57:51 2008 +0100
@@ -0,0 +1,128 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 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
+ *******************************************************************************/
+module dwt.layout.RowData;
+
+import dwt.SWT;
+import dwt.graphics.Point;
+import dwt.widgets.Control;
+
+import tango.text.Util;
+import tango.util.Convert;
+
+/**
+ * Each control controlled by a <code>RowLayout</code> can have its initial
+ * width and height specified by setting a <code>RowData</code> object
+ * into the control.
+ * <p>
+ * The following code uses a <code>RowData</code> object to change the initial
+ * size of a <code>Button</code> in a <code>Shell</code>:
+ * <pre>
+ * 		Display display = new Display();
+ * 		Shell shell = new Shell(display);
+ * 		shell.setLayout(new RowLayout());
+ * 		Button button1 = new Button(shell, SWT.PUSH);
+ * 		button1.setText("Button 1");
+ * 		button1.setLayoutData(new RowData(50, 40));
+ * </pre>
+ * </p>
+ *
+ * @see RowLayout
+ */
+public final class RowData {
+	/**
+	 * width specifies the desired width in pixels. This value
+	 * is the wHint passed into Control.computeSize(int, int, bool)
+	 * to determine the preferred size of the control.
+	 *
+	 * The default value is SWT.DEFAULT.
+	 *
+	 * @see dwt.widgets.Control#computeSize(int, int, bool)
+	 */
+	public int width = SWT.DEFAULT;
+	/**
+	 * height specifies the preferred height in pixels. This value
+	 * is the hHint passed into Control.computeSize(int, int, bool)
+	 * to determine the preferred size of the control.
+	 *
+	 * The default value is SWT.DEFAULT.
+	 *
+	 * @see dwt.widgets.Control#computeSize(int, int, bool)
+	 */
+	public int height = SWT.DEFAULT;
+
+	/**
+	 * exclude informs the layout to ignore this control when sizing
+	 * and positioning controls.  If this value is <code>true</code>,
+	 * the size and position of the control will not be managed by the
+	 * layout.  If this	value is <code>false</code>, the size and
+	 * position of the control will be computed and assigned.
+	 *
+	 * The default value is <code>false</code>.
+	 *
+	 * @since 3.1
+	 */
+	public bool exclude = false;
+
+/**
+ * Constructs a new instance of RowData using
+ * default values.
+ */
+public this () {
+}
+
+/**
+ * Constructs a new instance of RowData according to the parameters.
+ * A value of SWT.DEFAULT indicates that no minimum width or
+ * no minimum height is specified.
+ *
+ * @param width a minimum width for the control
+ * @param height a minimum height for the control
+ */
+public this (int width, int height) {
+	this.width = width;
+	this.height = height;
+}
+
+/**
+ * Constructs a new instance of RowData according to the parameter.
+ * A value of SWT.DEFAULT indicates that no minimum width or
+ * no minimum height is specified.
+ *
+ * @param point a point whose x coordinate specifies a minimum width for the control
+ * and y coordinate specifies a minimum height for the control
+ */
+public this (Point point) {
+	this (point.x, point.y);
+}
+
+char[] getName () {
+    char[] string = this.classinfo.name;
+    int index = locatePrior( string, '.');
+    if (index is string.length ) return string;
+    return string[ index + 1 .. string.length ];
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the RowData object
+ */
+public char[] toString () {
+	char[] string = getName ()~" {";
+	if (width !is SWT.DEFAULT) string ~= "width="~to!(char[])(width)~" ";
+	if (height !is SWT.DEFAULT) string ~= "height="~to!(char[])(height)~" ";
+	if (exclude) string ~= "exclude="~to!(char[])(exclude)~" ";
+	string = trim( string );
+	string ~= "}";
+	return string;
+}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/layout/RowLayout.d	Fri Jan 11 10:57:51 2008 +0100
@@ -0,0 +1,475 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 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
+ *******************************************************************************/
+module dwt.layout.RowLayout;
+
+import dwt.SWT;
+import dwt.graphics.Point;
+import dwt.graphics.Rectangle;
+import dwt.widgets.Control;
+import dwt.widgets.Layout;
+import dwt.widgets.Composite;
+import dwt.layout.RowData;
+import tango.text.Util;
+import tango.util.Convert;
+import Math = tango.math.Math;
+
+
+/**
+ * Instances of this class determine the size and position of the
+ * children of a <code>Composite</code> by placing them either in
+ * horizontal rows or vertical columns within the parent <code>Composite</code>.
+ * <p>
+ * <code>RowLayout</code> aligns all controls in one row if the
+ * <code>type</code> is set to horizontal, and one column if it is
+ * set to vertical. It has the ability to wrap, and provides configurable
+ * margins and spacing. <code>RowLayout</code> has a number of configuration
+ * fields. In addition, the height and width of each control in a
+ * <code>RowLayout</code> can be specified by setting a <code>RowData</code>
+ * object into the control using <code>setLayoutData ()</code>.
+ * </p>
+ * <p>
+ * The following example code creates a <code>RowLayout</code>, sets all
+ * of its fields to non-default values, and then sets it into a
+ * <code>Shell</code>.
+ * <pre>
+ * 		RowLayout rowLayout = new RowLayout();
+ * 		rowLayout.wrap = false;
+ * 		rowLayout.pack = false;
+ * 		rowLayout.justify = true;
+ * 		rowLayout.type = SWT.VERTICAL;
+ * 		rowLayout.marginLeft = 5;
+ * 		rowLayout.marginTop = 5;
+ * 		rowLayout.marginRight = 5;
+ * 		rowLayout.marginBottom = 5;
+ * 		rowLayout.spacing = 0;
+ * 		shell.setLayout(rowLayout);
+ * </pre>
+ * If you are using the default field values, you only need one line of code:
+ * <pre>
+ * 		shell.setLayout(new RowLayout());
+ * </pre>
+ * </p>
+ *
+ * @see RowData
+ */
+public final class RowLayout : Layout {
+
+	/**
+	 * type specifies whether the layout places controls in rows or
+	 * columns.
+	 *
+	 * The default value is HORIZONTAL.
+	 *
+	 * Possible values are: <ul>
+	 *    <li>HORIZONTAL: Position the controls horizontally from left to right</li>
+	 *    <li>VERTICAL: Position the controls vertically from top to bottom</li>
+	 * </ul>
+	 *
+	 * @since 2.0
+	 */
+	public int type = SWT.HORIZONTAL;
+
+	/**
+	 * marginWidth specifies the number of pixels of horizontal margin
+	 * that will be placed along the left and right edges of the layout.
+	 *
+	 * The default value is 0.
+	 *
+	 * @since 3.0
+	 */
+ 	public int marginWidth = 0;
+
+	/**
+	 * marginHeight specifies the number of pixels of vertical margin
+	 * that will be placed along the top and bottom edges of the layout.
+	 *
+	 * The default value is 0.
+	 *
+	 * @since 3.0
+	 */
+ 	public int marginHeight = 0;
+
+	/**
+	 * spacing specifies the number of pixels between the edge of one cell
+	 * and the edge of its neighbouring cell.
+	 *
+	 * The default value is 3.
+	 */
+	public int spacing = 3;
+
+	/**
+	 * wrap specifies whether a control will be wrapped to the next
+	 * row if there is insufficient space on the current row.
+	 *
+	 * The default value is true.
+	 */
+	public bool wrap = true;
+
+	/**
+	 * pack specifies whether all controls in the layout take
+	 * their preferred size.  If pack is false, all controls will
+	 * have the same size which is the size required to accommodate the
+	 * largest preferred height and the largest preferred width of all
+	 * the controls in the layout.
+	 *
+	 * The default value is true.
+	 */
+	public bool pack = true;
+
+	/**
+	 * fill specifies whether the controls in a row should be
+	 * all the same height for horizontal layouts, or the same
+	 * width for vertical layouts.
+	 *
+	 * The default value is false.
+	 *
+	 * @since 3.0
+	 */
+	public bool fill = false;
+
+	/**
+	 * justify specifies whether the controls in a row should be
+	 * fully justified, with any extra space placed between the controls.
+	 *
+	 * The default value is false.
+	 */
+	public bool justify = false;
+
+	/**
+	 * marginLeft specifies the number of pixels of horizontal margin
+	 * that will be placed along the left edge of the layout.
+	 *
+	 * The default value is 3.
+	 */
+	public int marginLeft = 3;
+
+	/**
+	 * marginTop specifies the number of pixels of vertical margin
+	 * that will be placed along the top edge of the layout.
+	 *
+	 * The default value is 3.
+	 */
+	public int marginTop = 3;
+
+	/**
+	 * marginRight specifies the number of pixels of horizontal margin
+	 * that will be placed along the right edge of the layout.
+	 *
+	 * The default value is 3.
+	 */
+	public int marginRight = 3;
+
+	/**
+	 * marginBottom specifies the number of pixels of vertical margin
+	 * that will be placed along the bottom edge of the layout.
+	 *
+	 * The default value is 3.
+	 */
+	public int marginBottom = 3;
+
+/**
+ * Constructs a new instance of this class.
+ */
+public this () {
+}
+
+/**
+ * Constructs a new instance of this class given the type.
+ *
+ * @param type the type of row layout
+ *
+ * @since 2.0
+ */
+public this (int type) {
+	this.type = type;
+}
+
+protected Point computeSize (Composite composite, int wHint, int hHint, bool flushCache_) {
+	Point extent;
+	if (type is SWT.HORIZONTAL) {
+		extent = layoutHorizontal (composite, false, (wHint !is SWT.DEFAULT) && wrap, wHint, flushCache_);
+	} else {
+		extent = layoutVertical (composite, false, (hHint !is SWT.DEFAULT) && wrap, hHint, flushCache_);
+	}
+	if (wHint !is SWT.DEFAULT) extent.x = wHint;
+	if (hHint !is SWT.DEFAULT) extent.y = hHint;
+	return extent;
+}
+
+Point computeSize (Control control, bool flushCache_) {
+	int wHint = SWT.DEFAULT, hHint = SWT.DEFAULT;
+	RowData data = cast(RowData) control.getLayoutData ();
+	if (data !is null) {
+		wHint = data.width;
+		hHint = data.height;
+	}
+	return control.computeSize (wHint, hHint, flushCache_);
+}
+
+protected bool flushCache (Control control) {
+	return true;
+}
+
+char[] getName () {
+    char[] string = this.classinfo.name;
+    int index = locatePrior( string, '.');
+    if (index is string.length ) return string;
+    return string[ index + 1 .. string.length ];
+}
+
+protected void layout (Composite composite, bool flushCache_) {
+	Rectangle clientArea = composite.getClientArea ();
+	if (type is SWT.HORIZONTAL) {
+		layoutHorizontal (composite, true, wrap, clientArea.width, flushCache_);
+	} else {
+		layoutVertical (composite, true, wrap, clientArea.height, flushCache_);
+	}
+}
+
+Point layoutHorizontal (Composite composite, bool move, bool wrap, int width, bool flushCache_) {
+	Control [] children = composite.getChildren ();
+	int count = 0;
+	for (int i=0; i<children.length; i++) {
+		Control control = children [i];
+		RowData data = cast(RowData) control.getLayoutData ();
+		if (data is null || !data.exclude) {
+			children [count++] = children [i];
+		}
+	}
+	if (count is 0) {
+		return new Point (marginLeft + marginWidth * 2 + marginRight, marginTop + marginHeight * 2 + marginBottom);
+	}
+	int childWidth = 0, childHeight = 0, maxHeight = 0;
+	if (!pack) {
+		for (int i=0; i<count; i++) {
+			Control child = children [i];
+			Point size = computeSize (child, flushCache_);
+			childWidth = Math.max (childWidth, size.x);
+			childHeight = Math.max (childHeight, size.y);
+		}
+		maxHeight = childHeight;
+	}
+	int clientX = 0, clientY = 0;
+	if (move) {
+		Rectangle rect = composite.getClientArea ();
+		clientX = rect.x;
+		clientY = rect.y;
+	}
+	int [] wraps = null;
+	bool wrapped = false;
+	Rectangle [] bounds = null;
+	if (move && (justify || fill)) {
+		bounds = new Rectangle [count];
+		wraps = new int [count];
+	}
+	int maxX = 0, x = marginLeft + marginWidth, y = marginTop + marginHeight;
+	for (int i=0; i<count; i++) {
+		Control child = children [i];
+		if (pack) {
+			Point size = computeSize (child, flushCache_);
+			childWidth = size.x;
+			childHeight = size.y;
+		}
+		if (wrap && (i !is 0) && (x + childWidth > width)) {
+			wrapped = true;
+			if (move && (justify || fill)) wraps [i - 1] = maxHeight;
+			x = marginLeft + marginWidth;
+			y += spacing + maxHeight;
+			if (pack) maxHeight = 0;
+		}
+		if (pack || fill) {
+			maxHeight = Math.max (maxHeight, childHeight);
+		}
+		if (move) {
+			int childX = x + clientX, childY = y + clientY;
+			if (justify || fill) {
+				bounds [i] = new Rectangle (childX, childY, childWidth, childHeight);
+			} else {
+				child.setBounds (childX, childY, childWidth, childHeight);
+			}
+		}
+		x += spacing + childWidth;
+		maxX = Math.max (maxX, x);
+	}
+	maxX = Math.max (clientX + marginLeft + marginWidth, maxX - spacing);
+	if (!wrapped) maxX += marginRight + marginWidth;
+	if (move && (justify || fill)) {
+		int space = 0, margin = 0;
+		if (!wrapped) {
+			space = Math.max (0, (width - maxX) / (count + 1));
+			margin = Math.max (0, ((width - maxX) % (count + 1)) / 2);
+		} else {
+			if (fill || justify) {
+				int last = 0;
+				if (count > 0) wraps [count - 1] = maxHeight;
+				for (int i=0; i<count; i++) {
+					if (wraps [i] !is 0) {
+						int wrapCount = i - last + 1;
+						if (justify) {
+							int wrapX = 0;
+							for (int j=last; j<=i; j++) {
+								wrapX += bounds [j].width + spacing;
+							}
+							space = Math.max (0, (width - wrapX) / (wrapCount + 1));
+							margin = Math.max (0, ((width - wrapX) % (wrapCount + 1)) / 2);
+						}
+						for (int j=last; j<=i; j++) {
+							if (justify) bounds [j].x += (space * (j - last + 1)) + margin;
+							if (fill) bounds [j].height = wraps [i];
+						}
+						last = i + 1;
+					}
+				}
+			}
+		}
+		for (int i=0; i<count; i++) {
+			if (!wrapped) {
+				if (justify) bounds [i].x += (space * (i + 1)) + margin;
+				if (fill) bounds [i].height = maxHeight;
+			}
+			children [i].setBounds (bounds [i]);
+		}
+	}
+	return new Point (maxX, y + maxHeight + marginBottom + marginHeight);
+}
+
+Point layoutVertical (Composite composite, bool move, bool wrap, int height, bool flushCache_) {
+	Control [] children = composite.getChildren ();
+	int count = 0;
+	for (int i=0; i<children.length; i++) {
+		Control control = children [i];
+		RowData data = cast(RowData) control.getLayoutData ();
+		if (data is null || !data.exclude) {
+			children [count++] = children [i];
+		}
+	}
+	if (count is 0) {
+		return new Point (marginLeft + marginWidth * 2 + marginRight, marginTop + marginHeight * 2 + marginBottom);
+	}
+	int childWidth = 0, childHeight = 0, maxWidth = 0;
+	if (!pack) {
+		for (int i=0; i<count; i++) {
+			Control child = children [i];
+			Point size = computeSize (child, flushCache_);
+			childWidth = Math.max (childWidth, size.x);
+			childHeight = Math.max (childHeight, size.y);
+		}
+		maxWidth = childWidth;
+	}
+	int clientX = 0, clientY = 0;
+	if (move) {
+		Rectangle rect = composite.getClientArea ();
+		clientX = rect.x;
+		clientY = rect.y;
+	}
+	int [] wraps = null;
+	bool wrapped = false;
+	Rectangle [] bounds = null;
+	if (move && (justify || fill)) {
+		bounds = new Rectangle [count];
+		wraps = new int [count];
+	}
+	int maxY = 0, x = marginLeft + marginWidth, y = marginTop + marginHeight;
+	for (int i=0; i<count; i++) {
+		Control child = children [i];
+		if (pack) {
+			Point size = computeSize (child, flushCache_);
+			childWidth = size.x;
+			childHeight = size.y;
+		}
+		if (wrap && (i !is 0) && (y + childHeight > height)) {
+			wrapped = true;
+			if (move && (justify || fill)) wraps [i - 1] = maxWidth;
+			x += spacing + maxWidth;
+			y = marginTop + marginHeight;
+			if (pack) maxWidth = 0;
+		}
+		if (pack || fill) {
+			maxWidth = Math.max (maxWidth, childWidth);
+		}
+		if (move) {
+			int childX = x + clientX, childY = y + clientY;
+			if (justify || fill) {
+				bounds [i] = new Rectangle (childX, childY, childWidth, childHeight);
+			} else {
+				child.setBounds (childX, childY, childWidth, childHeight);
+			}
+		}
+		y += spacing + childHeight;
+		maxY = Math.max (maxY, y);
+	}
+	maxY = Math.max (clientY + marginTop + marginHeight, maxY - spacing);
+	if (!wrapped) maxY += marginBottom + marginHeight;
+	if (move && (justify || fill)) {
+		int space = 0, margin = 0;
+		if (!wrapped) {
+			space = Math.max (0, (height - maxY) / (count + 1));
+			margin = Math.max (0, ((height - maxY) % (count + 1)) / 2);
+		} else {
+			if (fill || justify) {
+				int last = 0;
+				if (count > 0) wraps [count - 1] = maxWidth;
+				for (int i=0; i<count; i++) {
+					if (wraps [i] !is 0) {
+						int wrapCount = i - last + 1;
+						if (justify) {
+							int wrapY = 0;
+							for (int j=last; j<=i; j++) {
+								wrapY += bounds [j].height + spacing;
+							}
+							space = Math.max (0, (height - wrapY) / (wrapCount + 1));
+							margin = Math.max (0, ((height - wrapY) % (wrapCount + 1)) / 2);
+						}
+						for (int j=last; j<=i; j++) {
+							if (justify) bounds [j].y += (space * (j - last + 1)) + margin;
+							if (fill) bounds [j].width = wraps [i];
+						}
+						last = i + 1;
+					}
+				}
+			}
+		}
+		for (int i=0; i<count; i++) {
+			if (!wrapped) {
+				if (justify) bounds [i].y += (space * (i + 1)) + margin;
+				if (fill) bounds [i].width = maxWidth;
+			}
+			children [i].setBounds (bounds [i]);
+		}
+	}
+	return new Point (x + maxWidth + marginRight + marginWidth, maxY);
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the layout
+ */
+public char[] toString () {
+ 	char[] string = getName ()~" {";
+ 	string ~= "type="~((type !is SWT.HORIZONTAL) ? "SWT.VERTICAL" : "SWT.HORIZONTAL")~" ";
+ 	if (marginWidth !is 0) string ~= "marginWidth="~to!(char[])(marginWidth)~" ";
+ 	if (marginHeight !is 0) string ~= "marginHeight="~to!(char[])(marginHeight)~" ";
+ 	if (marginLeft !is 0) string ~= "marginLeft="~to!(char[])(marginLeft)~" ";
+ 	if (marginTop !is 0) string ~= "marginTop="~to!(char[])(marginTop)~" ";
+ 	if (marginRight !is 0) string ~= "marginRight="~to!(char[])(marginRight)~" ";
+ 	if (marginBottom !is 0) string ~= "marginBottom="~to!(char[])(marginBottom)~" ";
+ 	if (spacing !is 0) string ~= "spacing="~to!(char[])(spacing)~" ";
+ 	string ~= "wrap="~to!(char[])(wrap)~" ";
+	string ~= "pack="~to!(char[])(pack)~" ";
+	string ~= "fill="~to!(char[])(fill)~" ";
+	string ~= "justify="~to!(char[])(justify)~" ";
+	string = trim( string );
+	string ~= "}";
+ 	return string;
+}
+}