Mercurial > projects > dwt-linux
comparison dwt/layout/RowLayout.d @ 51:e300eb95bec4
RowData, RowLayout
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Fri, 11 Jan 2008 10:57:51 +0100 |
parents | |
children | 8cec8f536af3 |
comparison
equal
deleted
inserted
replaced
50:d48f7334742c | 51:e300eb95bec4 |
---|---|
1 /******************************************************************************* | |
2 * Copyright (c) 2000, 2006 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 *******************************************************************************/ | |
11 module dwt.layout.RowLayout; | |
12 | |
13 import dwt.SWT; | |
14 import dwt.graphics.Point; | |
15 import dwt.graphics.Rectangle; | |
16 import dwt.widgets.Control; | |
17 import dwt.widgets.Layout; | |
18 import dwt.widgets.Composite; | |
19 import dwt.layout.RowData; | |
20 import tango.text.Util; | |
21 import tango.util.Convert; | |
22 import Math = tango.math.Math; | |
23 | |
24 | |
25 /** | |
26 * Instances of this class determine the size and position of the | |
27 * children of a <code>Composite</code> by placing them either in | |
28 * horizontal rows or vertical columns within the parent <code>Composite</code>. | |
29 * <p> | |
30 * <code>RowLayout</code> aligns all controls in one row if the | |
31 * <code>type</code> is set to horizontal, and one column if it is | |
32 * set to vertical. It has the ability to wrap, and provides configurable | |
33 * margins and spacing. <code>RowLayout</code> has a number of configuration | |
34 * fields. In addition, the height and width of each control in a | |
35 * <code>RowLayout</code> can be specified by setting a <code>RowData</code> | |
36 * object into the control using <code>setLayoutData ()</code>. | |
37 * </p> | |
38 * <p> | |
39 * The following example code creates a <code>RowLayout</code>, sets all | |
40 * of its fields to non-default values, and then sets it into a | |
41 * <code>Shell</code>. | |
42 * <pre> | |
43 * RowLayout rowLayout = new RowLayout(); | |
44 * rowLayout.wrap = false; | |
45 * rowLayout.pack = false; | |
46 * rowLayout.justify = true; | |
47 * rowLayout.type = SWT.VERTICAL; | |
48 * rowLayout.marginLeft = 5; | |
49 * rowLayout.marginTop = 5; | |
50 * rowLayout.marginRight = 5; | |
51 * rowLayout.marginBottom = 5; | |
52 * rowLayout.spacing = 0; | |
53 * shell.setLayout(rowLayout); | |
54 * </pre> | |
55 * If you are using the default field values, you only need one line of code: | |
56 * <pre> | |
57 * shell.setLayout(new RowLayout()); | |
58 * </pre> | |
59 * </p> | |
60 * | |
61 * @see RowData | |
62 */ | |
63 public final class RowLayout : Layout { | |
64 | |
65 /** | |
66 * type specifies whether the layout places controls in rows or | |
67 * columns. | |
68 * | |
69 * The default value is HORIZONTAL. | |
70 * | |
71 * Possible values are: <ul> | |
72 * <li>HORIZONTAL: Position the controls horizontally from left to right</li> | |
73 * <li>VERTICAL: Position the controls vertically from top to bottom</li> | |
74 * </ul> | |
75 * | |
76 * @since 2.0 | |
77 */ | |
78 public int type = SWT.HORIZONTAL; | |
79 | |
80 /** | |
81 * marginWidth specifies the number of pixels of horizontal margin | |
82 * that will be placed along the left and right edges of the layout. | |
83 * | |
84 * The default value is 0. | |
85 * | |
86 * @since 3.0 | |
87 */ | |
88 public int marginWidth = 0; | |
89 | |
90 /** | |
91 * marginHeight specifies the number of pixels of vertical margin | |
92 * that will be placed along the top and bottom edges of the layout. | |
93 * | |
94 * The default value is 0. | |
95 * | |
96 * @since 3.0 | |
97 */ | |
98 public int marginHeight = 0; | |
99 | |
100 /** | |
101 * spacing specifies the number of pixels between the edge of one cell | |
102 * and the edge of its neighbouring cell. | |
103 * | |
104 * The default value is 3. | |
105 */ | |
106 public int spacing = 3; | |
107 | |
108 /** | |
109 * wrap specifies whether a control will be wrapped to the next | |
110 * row if there is insufficient space on the current row. | |
111 * | |
112 * The default value is true. | |
113 */ | |
114 public bool wrap = true; | |
115 | |
116 /** | |
117 * pack specifies whether all controls in the layout take | |
118 * their preferred size. If pack is false, all controls will | |
119 * have the same size which is the size required to accommodate the | |
120 * largest preferred height and the largest preferred width of all | |
121 * the controls in the layout. | |
122 * | |
123 * The default value is true. | |
124 */ | |
125 public bool pack = true; | |
126 | |
127 /** | |
128 * fill specifies whether the controls in a row should be | |
129 * all the same height for horizontal layouts, or the same | |
130 * width for vertical layouts. | |
131 * | |
132 * The default value is false. | |
133 * | |
134 * @since 3.0 | |
135 */ | |
136 public bool fill = false; | |
137 | |
138 /** | |
139 * justify specifies whether the controls in a row should be | |
140 * fully justified, with any extra space placed between the controls. | |
141 * | |
142 * The default value is false. | |
143 */ | |
144 public bool justify = false; | |
145 | |
146 /** | |
147 * marginLeft specifies the number of pixels of horizontal margin | |
148 * that will be placed along the left edge of the layout. | |
149 * | |
150 * The default value is 3. | |
151 */ | |
152 public int marginLeft = 3; | |
153 | |
154 /** | |
155 * marginTop specifies the number of pixels of vertical margin | |
156 * that will be placed along the top edge of the layout. | |
157 * | |
158 * The default value is 3. | |
159 */ | |
160 public int marginTop = 3; | |
161 | |
162 /** | |
163 * marginRight specifies the number of pixels of horizontal margin | |
164 * that will be placed along the right edge of the layout. | |
165 * | |
166 * The default value is 3. | |
167 */ | |
168 public int marginRight = 3; | |
169 | |
170 /** | |
171 * marginBottom specifies the number of pixels of vertical margin | |
172 * that will be placed along the bottom edge of the layout. | |
173 * | |
174 * The default value is 3. | |
175 */ | |
176 public int marginBottom = 3; | |
177 | |
178 /** | |
179 * Constructs a new instance of this class. | |
180 */ | |
181 public this () { | |
182 } | |
183 | |
184 /** | |
185 * Constructs a new instance of this class given the type. | |
186 * | |
187 * @param type the type of row layout | |
188 * | |
189 * @since 2.0 | |
190 */ | |
191 public this (int type) { | |
192 this.type = type; | |
193 } | |
194 | |
195 protected Point computeSize (Composite composite, int wHint, int hHint, bool flushCache_) { | |
196 Point extent; | |
197 if (type is SWT.HORIZONTAL) { | |
198 extent = layoutHorizontal (composite, false, (wHint !is SWT.DEFAULT) && wrap, wHint, flushCache_); | |
199 } else { | |
200 extent = layoutVertical (composite, false, (hHint !is SWT.DEFAULT) && wrap, hHint, flushCache_); | |
201 } | |
202 if (wHint !is SWT.DEFAULT) extent.x = wHint; | |
203 if (hHint !is SWT.DEFAULT) extent.y = hHint; | |
204 return extent; | |
205 } | |
206 | |
207 Point computeSize (Control control, bool flushCache_) { | |
208 int wHint = SWT.DEFAULT, hHint = SWT.DEFAULT; | |
209 RowData data = cast(RowData) control.getLayoutData (); | |
210 if (data !is null) { | |
211 wHint = data.width; | |
212 hHint = data.height; | |
213 } | |
214 return control.computeSize (wHint, hHint, flushCache_); | |
215 } | |
216 | |
217 protected bool flushCache (Control control) { | |
218 return true; | |
219 } | |
220 | |
221 char[] getName () { | |
222 char[] string = this.classinfo.name; | |
223 int index = locatePrior( string, '.'); | |
224 if (index is string.length ) return string; | |
225 return string[ index + 1 .. string.length ]; | |
226 } | |
227 | |
228 protected void layout (Composite composite, bool flushCache_) { | |
229 Rectangle clientArea = composite.getClientArea (); | |
230 if (type is SWT.HORIZONTAL) { | |
231 layoutHorizontal (composite, true, wrap, clientArea.width, flushCache_); | |
232 } else { | |
233 layoutVertical (composite, true, wrap, clientArea.height, flushCache_); | |
234 } | |
235 } | |
236 | |
237 Point layoutHorizontal (Composite composite, bool move, bool wrap, int width, bool flushCache_) { | |
238 Control [] children = composite.getChildren (); | |
239 int count = 0; | |
240 for (int i=0; i<children.length; i++) { | |
241 Control control = children [i]; | |
242 RowData data = cast(RowData) control.getLayoutData (); | |
243 if (data is null || !data.exclude) { | |
244 children [count++] = children [i]; | |
245 } | |
246 } | |
247 if (count is 0) { | |
248 return new Point (marginLeft + marginWidth * 2 + marginRight, marginTop + marginHeight * 2 + marginBottom); | |
249 } | |
250 int childWidth = 0, childHeight = 0, maxHeight = 0; | |
251 if (!pack) { | |
252 for (int i=0; i<count; i++) { | |
253 Control child = children [i]; | |
254 Point size = computeSize (child, flushCache_); | |
255 childWidth = Math.max (childWidth, size.x); | |
256 childHeight = Math.max (childHeight, size.y); | |
257 } | |
258 maxHeight = childHeight; | |
259 } | |
260 int clientX = 0, clientY = 0; | |
261 if (move) { | |
262 Rectangle rect = composite.getClientArea (); | |
263 clientX = rect.x; | |
264 clientY = rect.y; | |
265 } | |
266 int [] wraps = null; | |
267 bool wrapped = false; | |
268 Rectangle [] bounds = null; | |
269 if (move && (justify || fill)) { | |
270 bounds = new Rectangle [count]; | |
271 wraps = new int [count]; | |
272 } | |
273 int maxX = 0, x = marginLeft + marginWidth, y = marginTop + marginHeight; | |
274 for (int i=0; i<count; i++) { | |
275 Control child = children [i]; | |
276 if (pack) { | |
277 Point size = computeSize (child, flushCache_); | |
278 childWidth = size.x; | |
279 childHeight = size.y; | |
280 } | |
281 if (wrap && (i !is 0) && (x + childWidth > width)) { | |
282 wrapped = true; | |
283 if (move && (justify || fill)) wraps [i - 1] = maxHeight; | |
284 x = marginLeft + marginWidth; | |
285 y += spacing + maxHeight; | |
286 if (pack) maxHeight = 0; | |
287 } | |
288 if (pack || fill) { | |
289 maxHeight = Math.max (maxHeight, childHeight); | |
290 } | |
291 if (move) { | |
292 int childX = x + clientX, childY = y + clientY; | |
293 if (justify || fill) { | |
294 bounds [i] = new Rectangle (childX, childY, childWidth, childHeight); | |
295 } else { | |
296 child.setBounds (childX, childY, childWidth, childHeight); | |
297 } | |
298 } | |
299 x += spacing + childWidth; | |
300 maxX = Math.max (maxX, x); | |
301 } | |
302 maxX = Math.max (clientX + marginLeft + marginWidth, maxX - spacing); | |
303 if (!wrapped) maxX += marginRight + marginWidth; | |
304 if (move && (justify || fill)) { | |
305 int space = 0, margin = 0; | |
306 if (!wrapped) { | |
307 space = Math.max (0, (width - maxX) / (count + 1)); | |
308 margin = Math.max (0, ((width - maxX) % (count + 1)) / 2); | |
309 } else { | |
310 if (fill || justify) { | |
311 int last = 0; | |
312 if (count > 0) wraps [count - 1] = maxHeight; | |
313 for (int i=0; i<count; i++) { | |
314 if (wraps [i] !is 0) { | |
315 int wrapCount = i - last + 1; | |
316 if (justify) { | |
317 int wrapX = 0; | |
318 for (int j=last; j<=i; j++) { | |
319 wrapX += bounds [j].width + spacing; | |
320 } | |
321 space = Math.max (0, (width - wrapX) / (wrapCount + 1)); | |
322 margin = Math.max (0, ((width - wrapX) % (wrapCount + 1)) / 2); | |
323 } | |
324 for (int j=last; j<=i; j++) { | |
325 if (justify) bounds [j].x += (space * (j - last + 1)) + margin; | |
326 if (fill) bounds [j].height = wraps [i]; | |
327 } | |
328 last = i + 1; | |
329 } | |
330 } | |
331 } | |
332 } | |
333 for (int i=0; i<count; i++) { | |
334 if (!wrapped) { | |
335 if (justify) bounds [i].x += (space * (i + 1)) + margin; | |
336 if (fill) bounds [i].height = maxHeight; | |
337 } | |
338 children [i].setBounds (bounds [i]); | |
339 } | |
340 } | |
341 return new Point (maxX, y + maxHeight + marginBottom + marginHeight); | |
342 } | |
343 | |
344 Point layoutVertical (Composite composite, bool move, bool wrap, int height, bool flushCache_) { | |
345 Control [] children = composite.getChildren (); | |
346 int count = 0; | |
347 for (int i=0; i<children.length; i++) { | |
348 Control control = children [i]; | |
349 RowData data = cast(RowData) control.getLayoutData (); | |
350 if (data is null || !data.exclude) { | |
351 children [count++] = children [i]; | |
352 } | |
353 } | |
354 if (count is 0) { | |
355 return new Point (marginLeft + marginWidth * 2 + marginRight, marginTop + marginHeight * 2 + marginBottom); | |
356 } | |
357 int childWidth = 0, childHeight = 0, maxWidth = 0; | |
358 if (!pack) { | |
359 for (int i=0; i<count; i++) { | |
360 Control child = children [i]; | |
361 Point size = computeSize (child, flushCache_); | |
362 childWidth = Math.max (childWidth, size.x); | |
363 childHeight = Math.max (childHeight, size.y); | |
364 } | |
365 maxWidth = childWidth; | |
366 } | |
367 int clientX = 0, clientY = 0; | |
368 if (move) { | |
369 Rectangle rect = composite.getClientArea (); | |
370 clientX = rect.x; | |
371 clientY = rect.y; | |
372 } | |
373 int [] wraps = null; | |
374 bool wrapped = false; | |
375 Rectangle [] bounds = null; | |
376 if (move && (justify || fill)) { | |
377 bounds = new Rectangle [count]; | |
378 wraps = new int [count]; | |
379 } | |
380 int maxY = 0, x = marginLeft + marginWidth, y = marginTop + marginHeight; | |
381 for (int i=0; i<count; i++) { | |
382 Control child = children [i]; | |
383 if (pack) { | |
384 Point size = computeSize (child, flushCache_); | |
385 childWidth = size.x; | |
386 childHeight = size.y; | |
387 } | |
388 if (wrap && (i !is 0) && (y + childHeight > height)) { | |
389 wrapped = true; | |
390 if (move && (justify || fill)) wraps [i - 1] = maxWidth; | |
391 x += spacing + maxWidth; | |
392 y = marginTop + marginHeight; | |
393 if (pack) maxWidth = 0; | |
394 } | |
395 if (pack || fill) { | |
396 maxWidth = Math.max (maxWidth, childWidth); | |
397 } | |
398 if (move) { | |
399 int childX = x + clientX, childY = y + clientY; | |
400 if (justify || fill) { | |
401 bounds [i] = new Rectangle (childX, childY, childWidth, childHeight); | |
402 } else { | |
403 child.setBounds (childX, childY, childWidth, childHeight); | |
404 } | |
405 } | |
406 y += spacing + childHeight; | |
407 maxY = Math.max (maxY, y); | |
408 } | |
409 maxY = Math.max (clientY + marginTop + marginHeight, maxY - spacing); | |
410 if (!wrapped) maxY += marginBottom + marginHeight; | |
411 if (move && (justify || fill)) { | |
412 int space = 0, margin = 0; | |
413 if (!wrapped) { | |
414 space = Math.max (0, (height - maxY) / (count + 1)); | |
415 margin = Math.max (0, ((height - maxY) % (count + 1)) / 2); | |
416 } else { | |
417 if (fill || justify) { | |
418 int last = 0; | |
419 if (count > 0) wraps [count - 1] = maxWidth; | |
420 for (int i=0; i<count; i++) { | |
421 if (wraps [i] !is 0) { | |
422 int wrapCount = i - last + 1; | |
423 if (justify) { | |
424 int wrapY = 0; | |
425 for (int j=last; j<=i; j++) { | |
426 wrapY += bounds [j].height + spacing; | |
427 } | |
428 space = Math.max (0, (height - wrapY) / (wrapCount + 1)); | |
429 margin = Math.max (0, ((height - wrapY) % (wrapCount + 1)) / 2); | |
430 } | |
431 for (int j=last; j<=i; j++) { | |
432 if (justify) bounds [j].y += (space * (j - last + 1)) + margin; | |
433 if (fill) bounds [j].width = wraps [i]; | |
434 } | |
435 last = i + 1; | |
436 } | |
437 } | |
438 } | |
439 } | |
440 for (int i=0; i<count; i++) { | |
441 if (!wrapped) { | |
442 if (justify) bounds [i].y += (space * (i + 1)) + margin; | |
443 if (fill) bounds [i].width = maxWidth; | |
444 } | |
445 children [i].setBounds (bounds [i]); | |
446 } | |
447 } | |
448 return new Point (x + maxWidth + marginRight + marginWidth, maxY); | |
449 } | |
450 | |
451 /** | |
452 * Returns a string containing a concise, human-readable | |
453 * description of the receiver. | |
454 * | |
455 * @return a string representation of the layout | |
456 */ | |
457 public char[] toString () { | |
458 char[] string = getName ()~" {"; | |
459 string ~= "type="~((type !is SWT.HORIZONTAL) ? "SWT.VERTICAL" : "SWT.HORIZONTAL")~" "; | |
460 if (marginWidth !is 0) string ~= "marginWidth="~to!(char[])(marginWidth)~" "; | |
461 if (marginHeight !is 0) string ~= "marginHeight="~to!(char[])(marginHeight)~" "; | |
462 if (marginLeft !is 0) string ~= "marginLeft="~to!(char[])(marginLeft)~" "; | |
463 if (marginTop !is 0) string ~= "marginTop="~to!(char[])(marginTop)~" "; | |
464 if (marginRight !is 0) string ~= "marginRight="~to!(char[])(marginRight)~" "; | |
465 if (marginBottom !is 0) string ~= "marginBottom="~to!(char[])(marginBottom)~" "; | |
466 if (spacing !is 0) string ~= "spacing="~to!(char[])(spacing)~" "; | |
467 string ~= "wrap="~to!(char[])(wrap)~" "; | |
468 string ~= "pack="~to!(char[])(pack)~" "; | |
469 string ~= "fill="~to!(char[])(fill)~" "; | |
470 string ~= "justify="~to!(char[])(justify)~" "; | |
471 string = trim( string ); | |
472 string ~= "}"; | |
473 return string; | |
474 } | |
475 } |