# HG changeset patch
# User Frank Benoit
# Date 1200044652 -3600
# Node ID d48f7334742c9b94668199a41b6fb52a2e6af4a8
# Parent a67796650ad4fb0ffe028514db42ca3e2507079e
FormLayout, FormData, FormAttachment
diff -r a67796650ad4 -r d48f7334742c dwt/layout/FormAttachment.d
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/layout/FormAttachment.d Fri Jan 11 10:44:12 2008 +0100
@@ -0,0 +1,304 @@
+/*******************************************************************************
+ * 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.FormAttachment;
+
+import dwt.SWT;
+import dwt.widgets.Control;
+import dwt.layout.FormLayout;
+import dwt.layout.FormData;
+
+import tango.text.convert.Format;
+
+/**
+ * Instances of this class are used to define the edges of a control
+ * within a FormLayout
.
+ *
+ * FormAttachments
are set into the top, bottom, left,
+ * and right fields of the FormData
for a control.
+ * For example:
+ *
+ * FormData data = new FormData();
+ * data.top = new FormAttachment(0,5);
+ * data.bottom = new FormAttachment(100,-5);
+ * data.left = new FormAttachment(0,5);
+ * data.right = new FormAttachment(100,-5);
+ * button.setLayoutData(data);
+ *
+ *
+ *
+ * A FormAttachment
defines where to attach the side of
+ * a control by using the equation, y = ax + b. The "a" term represents
+ * a fraction of the parent composite's width (from the left) or height
+ * (from the top). It can be defined using a numerator and denominator,
+ * or just a percentage value. If a percentage is used, the denominator
+ * is set to 100. The "b" term in the equation represents an offset, in
+ * pixels, from the attachment position. For example:
+ *
+ * FormAttachment attach = new FormAttachment (20, -5);
+ *
+ * specifies that the side to which the FormAttachment
+ * object belongs will lie at 20% of the parent composite, minus 5 pixels.
+ *
+ *
+ * Control sides can also be attached to another control.
+ * For example:
+ *
+ * FormAttachment attach = new FormAttachment (button, 10);
+ *
+ * specifies that the side to which the FormAttachment
+ * object belongs will lie in the same position as the adjacent side of
+ * the button
control, plus 10 pixels. The control side can
+ * also be attached to the opposite side of the specified control.
+ * For example:
+ *
+ * FormData data = new FormData ();
+ * data.left = new FormAttachment (button, 0, SWT.LEFT);
+ *
+ * specifies that the left side of the control will lie in the same position
+ * as the left side of the button
control. The control can also
+ * be attached in a position that will center the control on the specified
+ * control. For example:
+ *
+ * data.left = new FormAttachment (button, 0, SWT.CENTER);
+ *
+ * specifies that the left side of the control will be positioned so that it is
+ * centered between the left and right sides of the button
control.
+ * If the alignment is not specified, the default is to attach to the adjacent side.
+ *
+ *
+ * @see FormLayout
+ * @see FormData
+ *
+ * @since 2.0
+ */
+public final class FormAttachment {
+ /**
+ * numerator specifies the numerator of the "a" term in the
+ * equation, y = ax + b, which defines the attachment.
+ */
+ public int numerator;
+
+ /**
+ * denominator specifies the denominator of the "a" term in the
+ * equation, y = ax + b, which defines the attachment.
+ *
+ * The default value is 100.
+ */
+ public int denominator = 100;
+
+ /**
+ * offset specifies the offset, in pixels, of the control side
+ * from the attachment position.
+ * If the offset is positive, then the control side is offset
+ * to the right of or below the attachment position. If it is
+ * negative, then the control side is offset to the left of or
+ * above the attachment position.
+ *
+ * This is equivalent to the "b" term in the equation y = ax + b.
+ * The default value is 0.
+ */
+ public int offset;
+
+ /**
+ * control specifies the control to which the control side is
+ * attached.
+ */
+ public Control control;
+
+ /**
+ * alignment specifies the alignment of the control side that is
+ * attached to a control.
+ *
+ * For top and bottom attachments, TOP, BOTTOM and CENTER are used. For left
+ * and right attachments, LEFT, RIGHT and CENTER are used. If any other case
+ * occurs, the default will be used instead.
+ *
+ *
+ *
Possible values are:
+ * - TOP: Attach the side to the top side of the specified control.
+ * - BOTTOM : Attach the side to the bottom side of the specified control.
+ * - LEFT: Attach the side to the left side of the specified control.
+ * - RIGHT: Attach the side to the right side of the specified control.
+ * - CENTER: Attach the side at a position which will center the control on the specified control.
+ * - DEFAULT: Attach the side to the adjacent side of the specified control.
+ *
+ */
+ public int alignment;
+
+/**
+ * Constructs a new instance of this class.
+ * Since no numerator, denominator or offset is specified,
+ * the attachment is treated as a percentage of the form.
+ * The numerator is zero, the denominator is 100 and the
+ * offset is zero.
+ *
+ * @since 3.2
+ */
+public this () {
+}
+
+/**
+ * Constructs a new instance of this class given a numerator
+ * Since no denominator or offset is specified, the default
+ * is to treat the numerator as a percentage of the form, with a
+ * denominator of 100. The offset is zero.
+ *
+ * @param numerator the percentage of the position
+ *
+ * @since 3.0
+ */
+public this (int numerator) {
+ this (numerator, 100, 0);
+}
+
+/**
+ * Constructs a new instance of this class given a numerator
+ * and an offset. Since no denominator is specified, the default
+ * is to treat the numerator as a percentage of the form, with a
+ * denominator of 100.
+ *
+ * @param numerator the percentage of the position
+ * @param offset the offset of the side from the position
+ */
+public this (int numerator, int offset) {
+ this (numerator, 100, offset);
+}
+
+/**
+ * Constructs a new instance of this class given a numerator
+ * and denominator and an offset. The position of the side is
+ * given by the fraction of the form defined by the numerator
+ * and denominator.
+ *
+ * @param numerator the numerator of the position
+ * @param denominator the denominator of the position
+ * @param offset the offset of the side from the position
+ */
+public this (int numerator, int denominator, int offset) {
+ if (denominator == 0) SWT.error (SWT.ERROR_CANNOT_BE_ZERO);
+ this.numerator = numerator;
+ this.denominator = denominator;
+ this.offset = offset;
+}
+
+/**
+ * Constructs a new instance of this class given a control.
+ * Since no alignment is specified, the default alignment is
+ * to attach the side to the adjacent side of the specified
+ * control. Since no offset is specified, an offset of 0 is
+ * used.
+ *
+ * @param control the control the side is attached to
+ */
+public this (Control control) {
+ this (control, 0, SWT.DEFAULT);
+}
+
+/**
+ * Constructs a new instance of this class given a control
+ * and an offset. Since no alignment is specified, the default
+ * alignment is to attach the side to the adjacent side of the
+ * specified control.
+ *
+ * @param control the control the side is attached to
+ * @param offset the offset of the side from the control
+ */
+public this (Control control, int offset) {
+ this (control, offset, SWT.DEFAULT);
+}
+
+/**
+ * Constructs a new instance of this class given a control,
+ * an offset and an alignment.
+ *
+ * @param control the control the side is attached to
+ * @param offset the offset of the side from the control
+ * @param alignment the alignment of the side to the control it is attached to
+ */
+public this (Control control, int offset, int alignment) {
+ this.control = control;
+ this.offset = offset;
+ this.alignment = alignment;
+}
+
+FormAttachment divide (int value) {
+ return new FormAttachment (numerator, denominator * value, offset / value);
+}
+
+int gcd (int m, int n) {
+ int temp;
+ m = Math.abs (m);
+ n = Math.abs (n);
+ if (m < n) {
+ temp = m;
+ m = n;
+ n = temp;
+ }
+ while (n != 0){
+ temp = m;
+ m = n;
+ n = temp % n;
+ }
+ return m;
+}
+
+FormAttachment minus (FormAttachment attachment) {
+ FormAttachment solution = new FormAttachment ();
+ solution.numerator = numerator * attachment.denominator - denominator * attachment.numerator;
+ solution.denominator = denominator * attachment.denominator;
+ int gcd = gcd (solution.denominator, solution.numerator);
+ solution.numerator = solution.numerator / gcd;
+ solution.denominator = solution.denominator / gcd;
+ solution.offset = offset - attachment.offset;
+ return solution;
+}
+
+FormAttachment minus (int value) {
+ return new FormAttachment (numerator, denominator, offset - value);
+}
+
+FormAttachment plus (FormAttachment attachment) {
+ FormAttachment solution = new FormAttachment ();
+ solution.numerator = numerator * attachment.denominator + denominator * attachment.numerator;
+ solution.denominator = denominator * attachment.denominator;
+ int gcd = gcd (solution.denominator, solution.numerator);
+ solution.numerator = solution.numerator / gcd;
+ solution.denominator = solution.denominator / gcd;
+ solution.offset = offset + attachment.offset;
+ return solution;
+}
+
+FormAttachment plus (int value) {
+ return new FormAttachment (numerator, denominator, offset + value);
+}
+
+int solveX (int value) {
+ if (denominator == 0) SWT.error (SWT.ERROR_CANNOT_BE_ZERO);
+ return ((numerator * value) / denominator) + offset;
+}
+
+int solveY (int value) {
+ if (numerator == 0) SWT.error (SWT.ERROR_CANNOT_BE_ZERO);
+ return (value - offset) * denominator / numerator;
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the FormAttachment
+ */
+public char[] toString () {
+ char[] string = control != null ? control.toString () : Format( "{}/{}", numerator, denominator );
+ return Format("{{y = ({})x + {}}", string, ( offset >= 0 ? Format(")x + {}", offset ) : Format( ")x - {}", -offset)));
+}
+
+}
diff -r a67796650ad4 -r d48f7334742c dwt/layout/FormData.d
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/layout/FormData.d Fri Jan 11 10:44:12 2008 +0100
@@ -0,0 +1,348 @@
+/*******************************************************************************
+ * 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.FormData;
+
+
+import dwt.SWT;
+import dwt.graphics.Point;
+import dwt.widgets.Control;
+import dwt.layout.FormAttachment;
+import tango.text.Util;
+
+import tango.text.Util;
+import tango.util.Convert;
+
+/**
+ * Instances of this class are used to define the attachments
+ * of a control in a FormLayout
.
+ *
+ * To set a FormData
object into a control, you use the
+ * setLayoutData ()
method. To define attachments for the
+ * FormData
, set the fields directly, like this:
+ *
+ * FormData data = new FormData();
+ * data.left = new FormAttachment(0,5);
+ * data.right = new FormAttachment(100,-5);
+ * button.setLayoutData(formData);
+ *
+ *
+ *
+ * FormData
contains the FormAttachments
for
+ * each edge of the control that the FormLayout
uses to
+ * determine the size and position of the control. FormData
+ * objects also allow you to set the width and height of controls within
+ * a FormLayout
.
+ *
+ *
+ * @see FormLayout
+ * @see FormAttachment
+ *
+ * @since 2.0
+ */
+public final class FormData {
+ /**
+ * width specifies the preferred 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 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 Control#computeSize(int, int, bool)
+ */
+ public int height = SWT.DEFAULT;
+ /**
+ * left specifies the attachment of the left side of
+ * the control.
+ */
+ public FormAttachment left;
+ /**
+ * right specifies the attachment of the right side of
+ * the control.
+ */
+ public FormAttachment right;
+ /**
+ * top specifies the attachment of the top of the control.
+ */
+ public FormAttachment top;
+ /**
+ * bottom specifies the attachment of the bottom of the
+ * control.
+ */
+ public FormAttachment bottom;
+
+ int cacheWidth = -1, cacheHeight = -1;
+ int defaultWhint, defaultHhint, defaultWidth = -1, defaultHeight = -1;
+ int currentWhint, currentHhint, currentWidth = -1, currentHeight = -1;
+ FormAttachment cacheLeft, cacheRight, cacheTop, cacheBottom;
+ bool isVisited, needed;
+
+/**
+ * Constructs a new instance of FormData using
+ * default values.
+ */
+public this () {
+}
+
+/**
+ * Constructs a new instance of FormData 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;
+}
+
+void computeSize (Control control, int wHint, int hHint, bool flushCache_) {
+ if (cacheWidth !is -1 && cacheHeight !is -1) return;
+ if (wHint is this.width && hHint is this.height) {
+ if (defaultWidth is -1 || defaultHeight is -1 || wHint !is defaultWhint || hHint !is defaultHhint) {
+ Point size = control.computeSize (wHint, hHint, flushCache_);
+ defaultWhint = wHint;
+ defaultHhint = hHint;
+ defaultWidth = size.x;
+ defaultHeight = size.y;
+ }
+ cacheWidth = defaultWidth;
+ cacheHeight = defaultHeight;
+ return;
+ }
+ if (currentWidth is -1 || currentHeight is -1 || wHint !is currentWhint || hHint !is currentHhint) {
+ Point size = control.computeSize (wHint, hHint, flushCache_);
+ currentWhint = wHint;
+ currentHhint = hHint;
+ currentWidth = size.x;
+ currentHeight = size.y;
+ }
+ cacheWidth = currentWidth;
+ cacheHeight = currentHeight;
+}
+
+void flushCache () {
+ cacheWidth = cacheHeight = -1;
+ defaultHeight = defaultWidth = -1;
+ currentHeight = currentWidth = -1;
+}
+
+int getWidth (Control control, bool flushCache) {
+ needed = true;
+ computeSize (control, width, height, flushCache);
+ return cacheWidth;
+}
+
+int getHeight (Control control, bool flushCache) {
+ computeSize (control, width, height, flushCache);
+ return cacheHeight;
+}
+
+FormAttachment getBottomAttachment (Control control, int spacing, bool flushCache) {
+ if (cacheBottom !is null) return cacheBottom;
+ if (isVisited) return cacheBottom = new FormAttachment (0, getHeight (control, flushCache));
+ if (bottom is null) {
+ if (top is null) return cacheBottom = new FormAttachment (0, getHeight (control, flushCache));
+ return cacheBottom = getTopAttachment (control, spacing, flushCache).plus (getHeight (control, flushCache));
+ }
+ Control bottomControl = bottom.control;
+ if (bottomControl !is null) {
+ if (bottomControl.isDisposed ()) {
+ bottom.control = bottomControl = null;
+ } else {
+ if (bottomControl.getParent () !is control.getParent ()) {
+ bottomControl = null;
+ }
+ }
+ }
+ if (bottomControl is null) return cacheBottom = bottom;
+ isVisited = true;
+ FormData bottomData = cast(FormData) bottomControl.getLayoutData ();
+ FormAttachment bottomAttachment = bottomData.getBottomAttachment (bottomControl, spacing, flushCache);
+ switch (bottom.alignment) {
+ case SWT.BOTTOM:
+ cacheBottom = bottomAttachment.plus (bottom.offset);
+ break;
+ case SWT.CENTER: {
+ FormAttachment topAttachment = bottomData.getTopAttachment (bottomControl, spacing, flushCache);
+ FormAttachment bottomHeight = bottomAttachment.minus (topAttachment);
+ cacheBottom = bottomAttachment.minus (bottomHeight.minus (getHeight (control, flushCache)).divide (2));
+ break;
+ }
+ default: {
+ FormAttachment topAttachment = bottomData.getTopAttachment (bottomControl, spacing, flushCache);
+ cacheBottom = topAttachment.plus (bottom.offset - spacing);
+ break;
+ }
+ }
+ isVisited = false;
+ return cacheBottom;
+}
+
+FormAttachment getLeftAttachment (Control control, int spacing, bool flushCache) {
+ if (cacheLeft !is null) return cacheLeft;
+ if (isVisited) return cacheLeft = new FormAttachment (0, 0);
+ if (left is null) {
+ if (right is null) return cacheLeft = new FormAttachment (0, 0);
+ return cacheLeft = getRightAttachment (control, spacing, flushCache).minus (getWidth (control, flushCache));
+ }
+ Control leftControl = left.control;
+ if (leftControl !is null) {
+ if (leftControl.isDisposed ()) {
+ left.control = leftControl = null;
+ } else {
+ if (leftControl.getParent () !is control.getParent ()) {
+ leftControl = null;
+ }
+ }
+ }
+ if (leftControl is null) return cacheLeft = left;
+ isVisited = true;
+ FormData leftData = cast(FormData) leftControl.getLayoutData ();
+ FormAttachment leftAttachment = leftData.getLeftAttachment (leftControl, spacing, flushCache);
+ switch (left.alignment) {
+ case SWT.LEFT:
+ cacheLeft = leftAttachment.plus (left.offset);
+ break;
+ case SWT.CENTER: {
+ FormAttachment rightAttachment = leftData.getRightAttachment (leftControl, spacing, flushCache);
+ FormAttachment leftWidth = rightAttachment.minus (leftAttachment);
+ cacheLeft = leftAttachment.plus (leftWidth.minus (getWidth (control, flushCache)).divide (2));
+ break;
+ }
+ default: {
+ FormAttachment rightAttachment = leftData.getRightAttachment (leftControl, spacing, flushCache);
+ cacheLeft = rightAttachment.plus (left.offset + spacing);
+ }
+ }
+ isVisited = false;
+ return cacheLeft;
+}
+
+char[] getName () {
+ char[] string = this.classinfo.name;
+ int index = locatePrior( string, '.');
+ if (index is string.length ) return string;
+ return string[ index + 1 .. string.length ];
+}
+
+FormAttachment getRightAttachment (Control control, int spacing, bool flushCache) {
+ if (cacheRight !is null) return cacheRight;
+ if (isVisited) return cacheRight = new FormAttachment (0, getWidth (control, flushCache));
+ if (right is null) {
+ if (left is null) return cacheRight = new FormAttachment (0, getWidth (control, flushCache));
+ return cacheRight = getLeftAttachment (control, spacing, flushCache).plus (getWidth (control, flushCache));
+ }
+ Control rightControl = right.control;
+ if (rightControl !is null) {
+ if (rightControl.isDisposed ()) {
+ right.control = rightControl = null;
+ } else {
+ if (rightControl.getParent () !is control.getParent ()) {
+ rightControl = null;
+ }
+ }
+ }
+ if (rightControl is null) return cacheRight = right;
+ isVisited = true;
+ FormData rightData = cast(FormData) rightControl.getLayoutData ();
+ FormAttachment rightAttachment = rightData.getRightAttachment (rightControl, spacing, flushCache);
+ switch (right.alignment) {
+ case SWT.RIGHT:
+ cacheRight = rightAttachment.plus (right.offset);
+ break;
+ case SWT.CENTER: {
+ FormAttachment leftAttachment = rightData.getLeftAttachment (rightControl, spacing, flushCache);
+ FormAttachment rightWidth = rightAttachment.minus (leftAttachment);
+ cacheRight = rightAttachment.minus (rightWidth.minus (getWidth (control, flushCache)).divide (2));
+ break;
+ }
+ default: {
+ FormAttachment leftAttachment = rightData.getLeftAttachment (rightControl, spacing, flushCache);
+ cacheRight = leftAttachment.plus (right.offset - spacing);
+ break;
+ }
+ }
+ isVisited = false;
+ return cacheRight;
+}
+
+FormAttachment getTopAttachment (Control control, int spacing, bool flushCache) {
+ if (cacheTop !is null) return cacheTop;
+ if (isVisited) return cacheTop = new FormAttachment (0, 0);
+ if (top is null) {
+ if (bottom is null) return cacheTop = new FormAttachment (0, 0);
+ return cacheTop = getBottomAttachment (control, spacing, flushCache).minus (getHeight (control, flushCache));
+ }
+ Control topControl = top.control;
+ if (topControl !is null) {
+ if (topControl.isDisposed ()) {
+ top.control = topControl = null;
+ } else {
+ if (topControl.getParent () !is control.getParent ()) {
+ topControl = null;
+ }
+ }
+ }
+ if (topControl is null) return cacheTop = top;
+ isVisited = true;
+ FormData topData = cast(FormData) topControl.getLayoutData ();
+ FormAttachment topAttachment = topData.getTopAttachment (topControl, spacing, flushCache);
+ switch (top.alignment) {
+ case SWT.TOP:
+ cacheTop = topAttachment.plus (top.offset);
+ break;
+ case SWT.CENTER: {
+ FormAttachment bottomAttachment = topData.getBottomAttachment (topControl, spacing, flushCache);
+ FormAttachment topHeight = bottomAttachment.minus (topAttachment);
+ cacheTop = topAttachment.plus (topHeight.minus (getHeight (control, flushCache)).divide (2));
+ break;
+ }
+ default: {
+ FormAttachment bottomAttachment = topData.getBottomAttachment (topControl, spacing, flushCache);
+ cacheTop = bottomAttachment.plus (top.offset + spacing);
+ break;
+ }
+ }
+ isVisited = false;
+ return cacheTop;
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the FormData 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 (left !is null) string ~= "left="~to!(char[])(left)~" ";
+ if (right !is null) string ~= "right="~to!(char[])(right)~" ";
+ if (top !is null) string ~= "top="~to!(char[])(top)~" ";
+ if (bottom !is null) string ~= "bottom="~to!(char[])(bottom)~" ";
+ string = trim( string );
+ string ~= "}";
+ return string;
+}
+
+}
diff -r a67796650ad4 -r d48f7334742c dwt/layout/FormLayout.d
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/layout/FormLayout.d Fri Jan 11 10:44:12 2008 +0100
@@ -0,0 +1,393 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 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.FormLayout;
+
+import dwt.layout.FormAttachment;
+import dwt.layout.FormData;
+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.widgets.Scrollable;
+
+import tango.text.Util;
+import tango.util.Convert;
+import Math = tango.math.Math;
+
+/**
+ * Instances of this class control the position and size of the
+ * children of a composite control by using FormAttachments
+ * to optionally configure the left, top, right and bottom edges of
+ * each child.
+ *
+ * The following example code creates a FormLayout
and then sets
+ * it into a Shell
:
+ *
+ * Display display = new Display ();
+ * Shell shell = new Shell(display);
+ * FormLayout layout = new FormLayout();
+ * layout.marginWidth = 3;
+ * layout.marginHeight = 3;
+ * shell.setLayout(layout);
+ *
+ *
+ *
+ * To use a FormLayout
, create a FormData
with
+ * FormAttachment
for each child of Composite
.
+ * The following example code attaches button1
to the top
+ * and left edge of the composite and button2
to the right
+ * edge of button1
and the top and right edges of the
+ * composite:
+ *
+ * FormData data1 = new FormData();
+ * data1.left = new FormAttachment(0, 0);
+ * data1.top = new FormAttachment(0, 0);
+ * button1.setLayoutData(data1);
+ * FormData data2 = new FormData();
+ * data2.left = new FormAttachment(button1);
+ * data2.top = new FormAttachment(0, 0);
+ * data2.right = new FormAttachment(100, 0);
+ * button2.setLayoutData(data2);
+ *
+ *
+ *
+ * Each side of a child control can be attached to a position in the parent
+ * composite, or to other controls within the Composite
by
+ * creating instances of FormAttachment
and setting them into
+ * the top, bottom, left, and right fields of the child's FormData
.
+ *
+ *
+ * If a side is not given an attachment, it is defined as not being attached
+ * to anything, causing the child to remain at its preferred size. If a child
+ * is given no attachment on either the left or the right or top or bottom, it is
+ * automatically attached to the left and top of the composite respectively.
+ * The following code positions button1
and button2
+ * but relies on default attachments:
+ *
+ * FormData data2 = new FormData();
+ * data2.left = new FormAttachment(button1);
+ * data2.right = new FormAttachment(100, 0);
+ * button2.setLayoutData(data2);
+ *
+ *
+ *
+ * IMPORTANT: Do not define circular attachments. For example, do not attach
+ * the right edge of button1
to the left edge of button2
+ * and then attach the left edge of button2
to the right edge of
+ * button1
. This will over constrain the layout, causing undefined
+ * behavior. The algorithm will terminate, but the results are undefined.
+ *
+ *
+ * @see FormData
+ * @see FormAttachment
+ *
+ * @since 2.0
+ *
+ */
+public final class FormLayout : Layout {
+
+ /**
+ * 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.
+ */
+ 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.
+ */
+ public int marginHeight = 0;
+
+
+ /**
+ * marginLeft specifies the number of pixels of horizontal margin
+ * that will be placed along the left edge of the layout.
+ *
+ * The default value is 0.
+ *
+ * @since 3.1
+ */
+ public int marginLeft = 0;
+
+ /**
+ * marginTop specifies the number of pixels of vertical margin
+ * that will be placed along the top edge of the layout.
+ *
+ * The default value is 0.
+ *
+ * @since 3.1
+ */
+ public int marginTop = 0;
+
+ /**
+ * marginRight specifies the number of pixels of horizontal margin
+ * that will be placed along the right edge of the layout.
+ *
+ * The default value is 0.
+ *
+ * @since 3.1
+ */
+ public int marginRight = 0;
+
+ /**
+ * marginBottom specifies the number of pixels of vertical margin
+ * that will be placed along the bottom edge of the layout.
+ *
+ * The default value is 0.
+ *
+ * @since 3.1
+ */
+ public int marginBottom = 0;
+
+ /**
+ * spacing specifies the number of pixels between the edge of one control
+ * and the edge of its neighbouring control.
+ *
+ * The default value is 0.
+ *
+ * @since 3.0
+ */
+ public int spacing = 0;
+
+/**
+ * Constructs a new instance of this class.
+ */
+public this () {
+}
+
+/*
+ * Computes the preferred height of the form with
+ * respect to the preferred height of the control.
+ *
+ * Given that the equations for top (T) and bottom (B)
+ * of the control in terms of the height of the form (X)
+ * are:
+ * T = AX + B
+ * B = CX + D
+ *
+ * The equation for the height of the control (H)
+ * is bottom (B) minus top (T) or (H = B - T) or:
+ *
+ * H = (CX + D) - (AX + B)
+ *
+ * Solving for (X), the height of the form, we get:
+ *
+ * X = (H + B - D) / (C - A)
+ *
+ * When (A = C), (C - A = 0) and the equation has no
+ * solution for X. This is a special case meaning that
+ * the control does not constrain the height of the
+ * form. In this case, we need to arbitrarily define
+ * the height of the form (X):
+ *
+ * Case 1: A = C, A = 0, C = 0
+ *
+ * Let X = D, the distance from the top of the form
+ * to the bottom edge of the control. In this case,
+ * the control was attached to the top of the form
+ * and the form needs to be large enough to show the
+ * bottom edge of the control.
+ *
+ * Case 2: A = C, A = 1, C = 1
+ *
+ * Let X = -B, the distance from the bottom of the
+ * form to the top edge of the control. In this case,
+ * the control was attached to the bottom of the form
+ * and the only way that the control would be visible
+ * is if the offset is negative. If the offset is
+ * positive, there is no possible height for the form
+ * that will show the control as it will always be
+ * below the bottom edge of the form.
+ *
+ * Case 3: A = C, A !is 0, C !is 0 and A !is 1, C !is 0
+ *
+ * Let X = D / (1 - C), the distance from the top of the
+ * form to the bottom edge of the control. In this case,
+ * since C is not 0 or 1, it must be a fraction, U / V.
+ * The offset D is the distance from CX to the bottom edge
+ * of the control. This represents a fraction of the form
+ * (1 - C)X. Since the height of a fraction of the form is
+ * known, the height of the entire form can be found by setting
+ * (1 - C)X = D. We solve this equation for X in terms of U
+ * and V, giving us X = (U * D) / (U - V). Similarly, if the
+ * offset D is negative, the control is positioned above CX.
+ * The offset -B is the distance from the top edge of the control
+ * to CX. We can find the height of the entire form by setting
+ * CX = -B. Solving in terms of U and V gives us X = (-B * V) / U.
+ */
+int computeHeight (Control control, FormData data, bool flushCache) {
+ FormAttachment top = data.getTopAttachment (control, spacing, flushCache);
+ FormAttachment bottom = data.getBottomAttachment (control, spacing, flushCache);
+ FormAttachment height = bottom.minus (top);
+ if (height.numerator is 0) {
+ if (bottom.numerator is 0) return bottom.offset;
+ if (bottom.numerator is bottom.denominator) return -top.offset;
+ if (bottom.offset <= 0) {
+ return -top.offset * top.denominator / bottom.numerator;
+ }
+ int divider = bottom.denominator - bottom.numerator;
+ return bottom.denominator * bottom.offset / divider;
+ }
+ return height.solveY (data.getHeight (control, flushCache));
+}
+
+protected Point computeSize (Composite composite, int wHint, int hHint, bool flushCache) {
+ Point size = layout (composite, false, 0, 0, wHint, hHint, flushCache);
+ if (wHint !is SWT.DEFAULT) size.x = wHint;
+ if (hHint !is SWT.DEFAULT) size.y = hHint;
+ return size;
+}
+
+protected bool flushCache (Control control) {
+ Object data = control.getLayoutData ();
+ if (data !is null) (cast(FormData) data).flushCache ();
+ 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 ];
+}
+
+/*
+ * Computes the preferred height of the form with
+ * respect to the preferred height of the control.
+ */
+int computeWidth (Control control, FormData data, bool flushCache) {
+ FormAttachment left = data.getLeftAttachment (control, spacing, flushCache);
+ FormAttachment right = data.getRightAttachment (control, spacing, flushCache);
+ FormAttachment width = right.minus (left);
+ if (width.numerator is 0) {
+ if (right.numerator is 0) return right.offset;
+ if (right.numerator is right.denominator) return -left.offset;
+ if (right.offset <= 0) {
+ return -left.offset * left.denominator / left.numerator;
+ }
+ int divider = right.denominator - right.numerator;
+ return right.denominator * right.offset / divider;
+ }
+ return width.solveY (data.getWidth (control, flushCache));
+}
+
+protected void layout (Composite composite, bool flushCache) {
+ Rectangle rect = composite.getClientArea ();
+ int x = rect.x + marginLeft + marginWidth;
+ int y = rect.y + marginTop + marginHeight;
+ int width = Math.max (0, rect.width - marginLeft - 2 * marginWidth - marginRight);
+ int height = Math.max (0, rect.height - marginTop - 2 * marginHeight - marginBottom);
+ layout (composite, true, x, y, width, height, flushCache);
+}
+
+Point layout (Composite composite, bool move, int x, int y, int width, int height, bool flushCache) {
+ Control [] children = composite.getChildren ();
+ for (int i=0; i