Mercurial > projects > dwt2
annotate org.eclipse.swt.gtk.linux.x86/src/org/eclipse/swt/layout/FormLayout.d @ 125:c43718956f21 default tip
Updated the snippets status.
author | Jacob Carlborg <doob@me.com> |
---|---|
date | Thu, 11 Aug 2011 19:55:14 +0200 |
parents | 536e43f63c81 |
children |
rev | line source |
---|---|
25 | 1 /******************************************************************************* |
2 * Copyright (c) 2000, 2008 IBM Corporation and others. | |
3 * All rights reserved. This program and the accompanying materials | |
4 * are made available under the terms of the Eclipse Public License v1.0 | |
5 * which accompanies this distribution, and is available at | |
6 * http://www.eclipse.org/legal/epl-v10.html | |
7 * | |
8 * Contributors: | |
9 * IBM Corporation - initial API and implementation | |
10 * Port to the D programming language: | |
11 * Frank Benoit <benoit@tionex.de> | |
12 *******************************************************************************/ | |
13 module org.eclipse.swt.layout.FormLayout; | |
14 | |
15 import org.eclipse.swt.layout.FormAttachment; | |
16 import org.eclipse.swt.layout.FormData; | |
17 import org.eclipse.swt.SWT; | |
18 import org.eclipse.swt.graphics.Point; | |
19 import org.eclipse.swt.graphics.Rectangle; | |
20 import org.eclipse.swt.widgets.Control; | |
21 import org.eclipse.swt.widgets.Layout; | |
22 import org.eclipse.swt.widgets.Composite; | |
23 import org.eclipse.swt.widgets.Scrollable; | |
24 | |
48 | 25 import java.lang.all; |
25 | 26 |
27 /** | |
28 * Instances of this class control the position and size of the | |
29 * children of a composite control by using <code>FormAttachments</code> | |
30 * to optionally configure the left, top, right and bottom edges of | |
31 * each child. | |
32 * <p> | |
33 * The following example code creates a <code>FormLayout</code> and then sets | |
34 * it into a <code>Shell</code>: | |
35 * <pre> | |
36 * Display display = new Display (); | |
37 * Shell shell = new Shell(display); | |
38 * FormLayout layout = new FormLayout(); | |
39 * layout.marginWidth = 3; | |
40 * layout.marginHeight = 3; | |
41 * shell.setLayout(layout); | |
42 * </pre> | |
43 * </p> | |
44 * <p> | |
45 * To use a <code>FormLayout</code>, create a <code>FormData</code> with | |
46 * <code>FormAttachment</code> for each child of <code>Composite</code>. | |
47 * The following example code attaches <code>button1</code> to the top | |
48 * and left edge of the composite and <code>button2</code> to the right | |
49 * edge of <code>button1</code> and the top and right edges of the | |
50 * composite: | |
51 * <pre> | |
52 * FormData data1 = new FormData(); | |
53 * data1.left = new FormAttachment(0, 0); | |
54 * data1.top = new FormAttachment(0, 0); | |
55 * button1.setLayoutData(data1); | |
56 * FormData data2 = new FormData(); | |
57 * data2.left = new FormAttachment(button1); | |
58 * data2.top = new FormAttachment(0, 0); | |
59 * data2.right = new FormAttachment(100, 0); | |
60 * button2.setLayoutData(data2); | |
61 * </pre> | |
62 * </p> | |
63 * <p> | |
64 * Each side of a child control can be attached to a position in the parent | |
65 * composite, or to other controls within the <code>Composite</code> by | |
66 * creating instances of <code>FormAttachment</code> and setting them into | |
67 * the top, bottom, left, and right fields of the child's <code>FormData</code>. | |
68 * </p> | |
69 * <p> | |
70 * If a side is not given an attachment, it is defined as not being attached | |
71 * to anything, causing the child to remain at its preferred size. If a child | |
72 * is given no attachment on either the left or the right or top or bottom, it is | |
73 * automatically attached to the left and top of the composite respectively. | |
74 * The following code positions <code>button1</code> and <code>button2</code> | |
75 * but relies on default attachments: | |
76 * <pre> | |
77 * FormData data2 = new FormData(); | |
78 * data2.left = new FormAttachment(button1); | |
79 * data2.right = new FormAttachment(100, 0); | |
80 * button2.setLayoutData(data2); | |
81 * </pre> | |
82 * </p> | |
83 * <p> | |
84 * IMPORTANT: Do not define circular attachments. For example, do not attach | |
85 * the right edge of <code>button1</code> to the left edge of <code>button2</code> | |
86 * and then attach the left edge of <code>button2</code> to the right edge of | |
87 * <code>button1</code>. This will over constrain the layout, causing undefined | |
88 * behavior. The algorithm will terminate, but the results are undefined. | |
89 * </p> | |
90 * | |
91 * @see FormData | |
92 * @see FormAttachment | |
93 * @see <a href="http://www.eclipse.org/swt/snippets/#formlayout">FormLayout snippets</a> | |
94 * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: LayoutExample</a> | |
95 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> | |
96 * | |
97 * @since 2.0 | |
98 */ | |
99 public final class FormLayout : Layout { | |
100 | |
101 /** | |
102 * marginWidth specifies the number of pixels of horizontal margin | |
103 * that will be placed along the left and right edges of the layout. | |
104 * | |
105 * The default value is 0. | |
106 */ | |
107 public int marginWidth = 0; | |
108 | |
109 /** | |
110 * marginHeight specifies the number of pixels of vertical margin | |
111 * that will be placed along the top and bottom edges of the layout. | |
112 * | |
113 * The default value is 0. | |
114 */ | |
115 public int marginHeight = 0; | |
116 | |
117 | |
118 /** | |
119 * marginLeft specifies the number of pixels of horizontal margin | |
120 * that will be placed along the left edge of the layout. | |
121 * | |
122 * The default value is 0. | |
123 * | |
124 * @since 3.1 | |
125 */ | |
126 public int marginLeft = 0; | |
127 | |
128 /** | |
129 * marginTop specifies the number of pixels of vertical margin | |
130 * that will be placed along the top edge of the layout. | |
131 * | |
132 * The default value is 0. | |
133 * | |
134 * @since 3.1 | |
135 */ | |
136 public int marginTop = 0; | |
137 | |
138 /** | |
139 * marginRight specifies the number of pixels of horizontal margin | |
140 * that will be placed along the right edge of the layout. | |
141 * | |
142 * The default value is 0. | |
143 * | |
144 * @since 3.1 | |
145 */ | |
146 public int marginRight = 0; | |
147 | |
148 /** | |
149 * marginBottom specifies the number of pixels of vertical margin | |
150 * that will be placed along the bottom edge of the layout. | |
151 * | |
152 * The default value is 0. | |
153 * | |
154 * @since 3.1 | |
155 */ | |
156 public int marginBottom = 0; | |
157 | |
158 /** | |
159 * spacing specifies the number of pixels between the edge of one control | |
160 * and the edge of its neighbouring control. | |
161 * | |
162 * The default value is 0. | |
163 * | |
164 * @since 3.0 | |
165 */ | |
166 public int spacing = 0; | |
167 | |
168 /** | |
169 * Constructs a new instance of this class. | |
170 */ | |
171 public this () { | |
172 } | |
173 | |
174 /* | |
175 * Computes the preferred height of the form with | |
176 * respect to the preferred height of the control. | |
177 * | |
178 * Given that the equations for top (T) and bottom (B) | |
179 * of the control in terms of the height of the form (X) | |
180 * are: | |
181 * T = AX + B | |
182 * B = CX + D | |
183 * | |
184 * The equation for the height of the control (H) | |
185 * is bottom (B) minus top (T) or (H = B - T) or: | |
186 * | |
187 * H = (CX + D) - (AX + B) | |
188 * | |
189 * Solving for (X), the height of the form, we get: | |
190 * | |
191 * X = (H + B - D) / (C - A) | |
192 * | |
193 * When (A = C), (C - A = 0) and the equation has no | |
194 * solution for X. This is a special case meaning that | |
195 * the control does not constrain the height of the | |
196 * form. In this case, we need to arbitrarily define | |
197 * the height of the form (X): | |
198 * | |
199 * Case 1: A = C, A = 0, C = 0 | |
200 * | |
201 * Let X = D, the distance from the top of the form | |
202 * to the bottom edge of the control. In this case, | |
203 * the control was attached to the top of the form | |
204 * and the form needs to be large enough to show the | |
205 * bottom edge of the control. | |
206 * | |
207 * Case 2: A = C, A = 1, C = 1 | |
208 * | |
209 * Let X = -B, the distance from the bottom of the | |
210 * form to the top edge of the control. In this case, | |
211 * the control was attached to the bottom of the form | |
212 * and the only way that the control would be visible | |
213 * is if the offset is negative. If the offset is | |
214 * positive, there is no possible height for the form | |
215 * that will show the control as it will always be | |
216 * below the bottom edge of the form. | |
217 * | |
218 * Case 3: A = C, A !is 0, C !is 0 and A !is 1, C !is 0 | |
219 * | |
220 * Let X = D / (1 - C), the distance from the top of the | |
221 * form to the bottom edge of the control. In this case, | |
222 * since C is not 0 or 1, it must be a fraction, U / V. | |
223 * The offset D is the distance from CX to the bottom edge | |
224 * of the control. This represents a fraction of the form | |
225 * (1 - C)X. Since the height of a fraction of the form is | |
226 * known, the height of the entire form can be found by setting | |
227 * (1 - C)X = D. We solve this equation for X in terms of U | |
228 * and V, giving us X = (U * D) / (U - V). Similarly, if the | |
229 * offset D is negative, the control is positioned above CX. | |
230 * The offset -B is the distance from the top edge of the control | |
231 * to CX. We can find the height of the entire form by setting | |
232 * CX = -B. Solving in terms of U and V gives us X = (-B * V) / U. | |
233 */ | |
234 int computeHeight (Control control, FormData data, bool flushCache) { | |
235 FormAttachment top = data.getTopAttachment (control, spacing, flushCache); | |
236 FormAttachment bottom = data.getBottomAttachment (control, spacing, flushCache); | |
237 FormAttachment height = bottom.minus (top); | |
238 if (height.numerator is 0) { | |
239 if (bottom.numerator is 0) return bottom.offset; | |
240 if (bottom.numerator is bottom.denominator) return -top.offset; | |
241 if (bottom.offset <= 0) { | |
242 return -top.offset * top.denominator / bottom.numerator; | |
243 } | |
244 int divider = bottom.denominator - bottom.numerator; | |
245 return bottom.denominator * bottom.offset / divider; | |
246 } | |
247 return height.solveY (data.getHeight (control, flushCache)); | |
248 } | |
249 | |
250 override protected Point computeSize (Composite composite, int wHint, int hHint, bool flushCache) { | |
251 Point size = layout (composite, false, 0, 0, wHint, hHint, flushCache); | |
252 if (wHint !is SWT.DEFAULT) size.x = wHint; | |
253 if (hHint !is SWT.DEFAULT) size.y = hHint; | |
254 return size; | |
255 } | |
256 | |
257 override protected bool flushCache (Control control) { | |
258 Object data = control.getLayoutData (); | |
259 if (data !is null) (cast(FormData) data).flushCache (); | |
260 return true; | |
261 } | |
262 | |
263 String getName () { | |
264 String string = this.classinfo.name; | |
265 int index = string.lastIndexOf('.'); | |
266 if (index is -1 ) return string; | |
267 return string[ index + 1 .. string.length ]; | |
268 } | |
269 | |
270 /* | |
271 * Computes the preferred height of the form with | |
272 * respect to the preferred height of the control. | |
273 */ | |
274 int computeWidth (Control control, FormData data, bool flushCache) { | |
275 FormAttachment left = data.getLeftAttachment (control, spacing, flushCache); | |
276 FormAttachment right = data.getRightAttachment (control, spacing, flushCache); | |
277 FormAttachment width = right.minus (left); | |
278 if (width.numerator is 0) { | |
279 if (right.numerator is 0) return right.offset; | |
280 if (right.numerator is right.denominator) return -left.offset; | |
281 if (right.offset <= 0) { | |
282 return -left.offset * left.denominator / left.numerator; | |
283 } | |
284 int divider = right.denominator - right.numerator; | |
285 return right.denominator * right.offset / divider; | |
286 } | |
287 return width.solveY (data.getWidth (control, flushCache)); | |
288 } | |
289 | |
290 override protected void layout (Composite composite, bool flushCache) { | |
291 Rectangle rect = composite.getClientArea (); | |
292 int x = rect.x + marginLeft + marginWidth; | |
293 int y = rect.y + marginTop + marginHeight; | |
294 int width = Math.max (0, rect.width - marginLeft - 2 * marginWidth - marginRight); | |
295 int height = Math.max (0, rect.height - marginTop - 2 * marginHeight - marginBottom); | |
296 layout (composite, true, x, y, width, height, flushCache); | |
297 } | |
298 | |
299 Point layout (Composite composite, bool move, int x, int y, int width, int height, bool flushCache) { | |
300 Control [] children = composite.getChildren (); | |
301 for (int i=0; i<children.length; i++) { | |
302 Control child = children [i]; | |
303 FormData data = cast(FormData) child.getLayoutData (); | |
304 if (data is null) child.setLayoutData (data = new FormData ()); | |
305 if (flushCache) data.flushCache (); | |
306 data.cacheLeft = data.cacheRight = data.cacheTop = data.cacheBottom = null; | |
307 } | |
308 bool [] flush = null; | |
309 Rectangle [] bounds = null; | |
310 int w = 0, h = 0; | |
311 for (int i=0; i<children.length; i++) { | |
312 Control child = children [i]; | |
313 FormData data = cast(FormData) child.getLayoutData (); | |
314 if (width !is SWT.DEFAULT) { | |
315 data.needed = false; | |
316 FormAttachment left = data.getLeftAttachment (child, spacing, flushCache); | |
317 FormAttachment right = data.getRightAttachment (child, spacing, flushCache); | |
318 int x1 = left.solveX (width), x2 = right.solveX (width); | |
319 if (data.height is SWT.DEFAULT && !data.needed) { | |
320 int trim = 0; | |
321 //TEMPORARY CODE | |
322 if ( auto sa = cast(Scrollable)child) { | |
323 Rectangle rect = sa.computeTrim (0, 0, 0, 0); | |
324 trim = rect.width; | |
325 } else { | |
326 trim = child.getBorderWidth () * 2; | |
327 } | |
328 data.cacheWidth = data.cacheHeight = -1; | |
329 int currentWidth = Math.max (0, x2 - x1 - trim); | |
330 data.computeSize (child, currentWidth, data.height, flushCache); | |
331 if (flush is null) flush = new bool [children.length]; | |
332 flush [i] = true; | |
333 } | |
334 w = Math.max (x2, w); | |
335 if (move) { | |
336 if (bounds is null) bounds = new Rectangle [children.length]; | |
337 bounds [i] = new Rectangle (0, 0, 0, 0); | |
338 bounds [i].x = x + x1; | |
339 bounds [i].width = x2 - x1; | |
340 } | |
341 } else { | |
342 w = Math.max (computeWidth (child, data, flushCache), w); | |
343 } | |
344 } | |
345 for (int i=0; i<children.length; i++) { | |
346 Control child = children [i]; | |
347 FormData data = cast(FormData) child.getLayoutData (); | |
348 if (height !is SWT.DEFAULT) { | |
349 int y1 = data.getTopAttachment (child, spacing, flushCache).solveX (height); | |
350 int y2 = data.getBottomAttachment (child, spacing, flushCache).solveX (height); | |
351 h = Math.max (y2, h); | |
352 if (move) { | |
353 bounds [i].y = y + y1; | |
354 bounds [i].height = y2 - y1; | |
355 } | |
356 } else { | |
357 h = Math.max (computeHeight (child, data, flushCache), h); | |
358 } | |
359 } | |
360 for (int i=0; i<children.length; i++) { | |
361 Control child = children [i]; | |
362 FormData data = cast(FormData) child.getLayoutData (); | |
363 if (flush !is null && flush [i]) data.cacheWidth = data.cacheHeight = -1; | |
364 data.cacheLeft = data.cacheRight = data.cacheTop = data.cacheBottom = null; | |
365 } | |
366 if (move) { | |
367 for (int i=0; i<children.length; i++) { | |
368 children [i].setBounds (bounds [i]); | |
369 } | |
370 } | |
371 w += marginLeft + marginWidth * 2 + marginRight; | |
372 h += marginTop + marginHeight * 2 + marginBottom; | |
373 return new Point (w, h); | |
374 } | |
375 | |
376 /** | |
377 * Returns a string containing a concise, human-readable | |
378 * description of the receiver. | |
379 * | |
380 * @return a string representation of the layout | |
381 */ | |
382 override public String toString () { | |
383 String string = getName ()~" {"; | |
120
536e43f63c81
Comprehensive update for Win32/Linux32 dmd-2.053/dmd-1.068+Tango-r5661
Denis Shelomovskij <verylonglogin.reg@gmail.com>
parents:
51
diff
changeset
|
384 if (marginWidth !is 0) string ~= "marginWidth="~String_valueOf(marginWidth)~" "; |
536e43f63c81
Comprehensive update for Win32/Linux32 dmd-2.053/dmd-1.068+Tango-r5661
Denis Shelomovskij <verylonglogin.reg@gmail.com>
parents:
51
diff
changeset
|
385 if (marginHeight !is 0) string ~= "marginHeight="~String_valueOf(marginHeight)~" "; |
536e43f63c81
Comprehensive update for Win32/Linux32 dmd-2.053/dmd-1.068+Tango-r5661
Denis Shelomovskij <verylonglogin.reg@gmail.com>
parents:
51
diff
changeset
|
386 if (marginLeft !is 0) string ~= "marginLeft="~String_valueOf(marginLeft)~" "; |
536e43f63c81
Comprehensive update for Win32/Linux32 dmd-2.053/dmd-1.068+Tango-r5661
Denis Shelomovskij <verylonglogin.reg@gmail.com>
parents:
51
diff
changeset
|
387 if (marginRight !is 0) string ~= "marginRight="~String_valueOf(marginRight)~" "; |
536e43f63c81
Comprehensive update for Win32/Linux32 dmd-2.053/dmd-1.068+Tango-r5661
Denis Shelomovskij <verylonglogin.reg@gmail.com>
parents:
51
diff
changeset
|
388 if (marginTop !is 0) string ~= "marginTop="~String_valueOf(marginTop)~" "; |
536e43f63c81
Comprehensive update for Win32/Linux32 dmd-2.053/dmd-1.068+Tango-r5661
Denis Shelomovskij <verylonglogin.reg@gmail.com>
parents:
51
diff
changeset
|
389 if (marginBottom !is 0) string ~= "marginBottom="~String_valueOf(marginBottom)~" "; |
536e43f63c81
Comprehensive update for Win32/Linux32 dmd-2.053/dmd-1.068+Tango-r5661
Denis Shelomovskij <verylonglogin.reg@gmail.com>
parents:
51
diff
changeset
|
390 if (spacing !is 0) string ~= "spacing="~String_valueOf(spacing)~" "; |
25 | 391 string = string.trim(); |
392 string ~= "}"; | |
393 return string; | |
394 } | |
395 } |