root/dwt/layout/RowLayout.d

Revision 246:fd9c62a2998e, 18.0 kB (checked in by Frank Benoit <benoit@tionex.de>, 6 months ago)

Updater SWT 3.4M7 to 3.4

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