comparison org.eclipse.draw2d/src/org/eclipse/draw2d/FlowLayout.d @ 12:bc29606a740c

Added dwt-addons in original directory structure of eclipse.org
author Frank Benoit <benoit@tionex.de>
date Sat, 14 Mar 2009 18:23:29 +0100
parents
children dbfb303e8fb0
comparison
equal deleted inserted replaced
11:43904fec5dca 12:bc29606a740c
1 /*******************************************************************************
2 * Copyright (c) 2000, 2005 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.draw2d.FlowLayout;
14
15 import java.lang.all;
16
17 import org.eclipse.draw2d.geometry.Dimension;
18 import org.eclipse.draw2d.geometry.Rectangle;
19 import org.eclipse.draw2d.geometry.Transposer;
20 import org.eclipse.draw2d.AbstractHintLayout;
21 import org.eclipse.draw2d.IFigure;
22
23 /**
24 * Lays out children in rows or columns, wrapping when the current row/column is filled.
25 * The aligment and spacing of rows in the parent can be configured. The aligment and
26 * spacing of children within a row can be configured.
27 */
28 public class FlowLayout
29 : AbstractHintLayout
30 {
31
32 /** Constant to specify components to be aligned in the center */
33 public static const int ALIGN_CENTER = 0;
34 /** Constant to specify components to be aligned on the left/top */
35 public static const int ALIGN_LEFTTOP = 1;
36 /** Constant to specify components to be aligned on the right/bottom */
37 public static const int ALIGN_RIGHTBOTTOM = 2;
38
39 /** Constant to specify components should be layed out horizontally */
40 public static const bool HORIZONTAL = true;
41 /** Constant to specify components should be layed out vertically */
42 public static const bool VERTICAL = false;
43
44 /** The horizontal property. */
45 protected bool horizontal = true;
46 /**
47 * The property that determines whether leftover space at the end of a row/column should
48 * be filled by the last item in that row/column.
49 */
50 protected bool fill = false;
51
52 /** The transposer used in converting horizontal layout to vertical. */
53 protected Transposer transposer;
54 private void instanceInit(){
55 transposer = new Transposer();
56 transposer.setEnabled(!horizontal);
57 }
58
59 /** The alignment along the major axis. */
60 protected int majorAlignment = ALIGN_LEFTTOP;
61 /** The alignment along the minor axis. */
62 protected int minorAlignment = ALIGN_LEFTTOP;
63 /** The spacing along the minor axis. */
64 protected int minorSpacing = 5;
65 /** The spacing along the major axis. */
66 protected int majorSpacing = 5;
67 protected WorkingData data = null;
68
69 /**
70 * Holds the necessary information for layout calculations.
71 */
72 protected class WorkingData {
73 public int rowHeight, rowWidth, rowCount, rowX, rowY, maxWidth;
74 public Rectangle[] bounds;
75 public Rectangle area;
76 public IFigure row[];
77 }
78
79 /**
80 * Constructs a FlowLayout with horizontal orientation.
81 * @since 2.0
82 */
83 public this() {
84 instanceInit();
85 }
86
87 /**
88 * Constructs a FlowLayout whose orientation is given in the input.
89 * @param isHorizontal <code>true</code> if the layout should be horizontal
90 * @since 2.0
91 */
92 public this(bool isHorizontal) {
93 instanceInit();
94 setHorizontal(isHorizontal);
95 }
96
97 /**
98 * @see org.eclipse.draw2d.AbstractLayout#calculatePreferredSize(IFigure, int, int)
99 */
100 protected Dimension calculatePreferredSize(IFigure container, int wHint, int hHint) {
101 // Subtract out the insets from the hints
102 if (wHint > -1)
103 wHint = Math.max(0, wHint - container.getInsets().getWidth());
104 if (hHint > -1)
105 hHint = Math.max(0, hHint - container.getInsets().getHeight());
106
107 // Figure out the new hint that we are interested in based on the orientation
108 // Ignore the other hint (by setting it to -1). NOTE: The children of the
109 // parent figure will then be asked to ignore that hint as well.
110 int maxWidth;
111 if (isHorizontal()) {
112 maxWidth = wHint;
113 hHint = -1;
114 } else {
115 maxWidth = hHint;
116 wHint = -1;
117 }
118 if (maxWidth < 0) {
119 maxWidth = Integer.MAX_VALUE;
120 }
121
122 // The preferred dimension that is to be calculated and returned
123 Dimension prefSize = new Dimension();
124
125 List children = container.getChildren();
126 int width = 0;
127 int height = 0;
128 IFigure child;
129 Dimension childSize;
130
131 //Build the sizes for each row, and update prefSize accordingly
132 for (int i = 0; i < children.size(); i++) {
133 child = cast(IFigure)children.get(i);
134 childSize = transposer.t(getChildSize(child, wHint, hHint));
135 if (i is 0) {
136 width = childSize.width;
137 height = childSize.height;
138 } else if (width + childSize.width + getMinorSpacing() > maxWidth) {
139 // The current row is full, start a new row.
140 prefSize.height += height + getMajorSpacing();
141 prefSize.width = Math.max(prefSize.width, width);
142 width = childSize.width;
143 height = childSize.height;
144 } else {
145 // The current row can fit another child.
146 width += childSize.width + getMinorSpacing();
147 height = Math.max(height, childSize.height);
148 }
149 }
150
151 // Flush out the last row's data
152 prefSize.height += height;
153 prefSize.width = Math.max(prefSize.width, width);
154
155 // Transpose the dimension back, and compensate for the border.
156 prefSize = transposer.t(prefSize);
157 prefSize.width += container.getInsets().getWidth();
158 prefSize.height += container.getInsets().getHeight();
159 prefSize.union_(getBorderPreferredSize(container));
160
161 return prefSize;
162 }
163
164 /**
165 * Provides the given child's preferred size.
166 *
167 * @param child the Figure whose preferred size needs to be calculated
168 * @param wHint the width hint
169 * @param hHint the height hint
170 * @return the child's preferred size
171 */
172 protected Dimension getChildSize(IFigure child, int wHint, int hHint) {
173 return child.getPreferredSize(wHint, hHint);
174 }
175
176
177 /**
178 * Returns the alignment used for an entire row/column.
179 * <P>
180 * Possible values are :
181 * <ul>
182 * <li>{@link #ALIGN_CENTER}
183 * <li>{@link #ALIGN_LEFTTOP}
184 * <li>{@link #ALIGN_RIGHTBOTTOM}
185 * </ul>
186 *
187 * @return the major alignment
188 * @since 2.0
189 */
190 public int getMajorAlignment() {
191 return majorAlignment;
192 }
193
194 /**
195 * Returns the spacing in pixels to be used between children in the direction parallel to
196 * the layout's orientation.
197 * @return the major spacing
198 */
199 public int getMajorSpacing() {
200 return majorSpacing;
201 }
202
203 /**
204 * Returns the alignment used for children within a row/column.
205 * <P>
206 * Possible values are :
207 * <ul>
208 * <li>{@link #ALIGN_CENTER}
209 * <li>{@link #ALIGN_LEFTTOP}
210 * <li>{@link #ALIGN_RIGHTBOTTOM}
211 * </ul>
212 *
213 * @return the minor alignment
214 * @since 2.0
215 */
216 public int getMinorAlignment() {
217 return minorAlignment;
218 }
219
220 /**
221 * Returns the spacing to be used between children within a row/column.
222 * @return the minor spacing
223 */
224 public int getMinorSpacing() {
225 return minorSpacing;
226 }
227
228 /**
229 * Initializes the state of row data, which is internal to the layout process.
230 */
231 protected void initRow() {
232 data.rowX = 0;
233 data.rowHeight = 0;
234 data.rowWidth = 0;
235 data.rowCount = 0;
236 }
237
238 /**
239 * Initializes state data for laying out children, based on the Figure given as input.
240 *
241 * @param parent the parent figure
242 * @since 2.0
243 */
244 protected void initVariables(IFigure parent) {
245 data.row = new IFigure[parent.getChildren().size()];
246 data.bounds = new Rectangle[data.row.length];
247 data.maxWidth = data.area.width;
248 }
249
250 /**
251 * Returns <code>true</code> if the orientation of the layout is horizontal.
252 *
253 * @return <code>true</code> if the orientation of the layout is horizontal
254 * @since 2.0
255 */
256 public bool isHorizontal() {
257 return horizontal;
258 }
259
260 /**
261 * @see org.eclipse.draw2d.AbstractHintLayout#isSensitiveHorizontally(IFigure)
262 */
263 protected bool isSensitiveHorizontally(IFigure parent) {
264 return isHorizontal();
265 }
266
267 /**
268 * @see org.eclipse.draw2d.AbstractHintLayout#isSensitiveVertically(IFigure)
269 */
270 protected bool isSensitiveVertically(IFigure parent) {
271 return !isHorizontal();
272 }
273
274 /**
275 * @see org.eclipse.draw2d.LayoutManager#layout(IFigure)
276 */
277 public void layout(IFigure parent) {
278 data = new WorkingData();
279 Rectangle relativeArea = parent.getClientArea();
280 data.area = transposer.t(relativeArea);
281
282 Iterator iterator = parent.getChildren().iterator();
283 int dx;
284
285 //Calculate the hints to be passed to children
286 int wHint = -1;
287 int hHint = -1;
288 if (isHorizontal())
289 wHint = parent.getClientArea().width;
290 else
291 hHint = parent.getClientArea().height;
292
293 initVariables(parent);
294 initRow();
295 int i = 0;
296 while (iterator.hasNext()) {
297 IFigure f = cast(IFigure)iterator.next();
298 Dimension pref = transposer.t(getChildSize(f, wHint, hHint));
299 Rectangle r = new Rectangle(0, 0, pref.width, pref.height);
300
301 if (data.rowCount > 0) {
302 if (data.rowWidth + pref.width > data.maxWidth)
303 layoutRow(parent);
304 }
305 r.x = data.rowX;
306 r.y = data.rowY;
307 dx = r.width + getMinorSpacing();
308 data.rowX += dx;
309 data.rowWidth += dx;
310 data.rowHeight = Math.max(data.rowHeight, r.height);
311 data.row [data.rowCount] = f;
312 data.bounds[data.rowCount] = r;
313 data.rowCount++;
314 i++;
315 }
316 if (data.rowCount !is 0)
317 layoutRow(parent);
318 data = null;
319 }
320
321 /**
322 * Layouts one row of components. This is done based on the layout's orientation, minor
323 * alignment and major alignment.
324 *
325 * @param parent the parent figure
326 * @since 2.0
327 */
328 protected void layoutRow(IFigure parent) {
329 int majorAdjustment = 0;
330 int minorAdjustment = 0;
331 int correctMajorAlignment = majorAlignment;
332 int correctMinorAlignment = minorAlignment;
333
334 majorAdjustment = data.area.width - data.rowWidth + getMinorSpacing();
335
336 switch (correctMajorAlignment) {
337 case ALIGN_LEFTTOP:
338 majorAdjustment = 0;
339 break;
340 case ALIGN_CENTER:
341 majorAdjustment /= 2;
342 break;
343 case ALIGN_RIGHTBOTTOM:
344 break;
345 default:
346 }
347
348 for (int j = 0; j < data.rowCount; j++) {
349 if (fill) {
350 data.bounds[j].height = data.rowHeight;
351 } else {
352 minorAdjustment = data.rowHeight - data.bounds[j].height;
353 switch (correctMinorAlignment) {
354 case ALIGN_LEFTTOP:
355 minorAdjustment = 0;
356 break;
357 case ALIGN_CENTER:
358 minorAdjustment /= 2;
359 break;
360 case ALIGN_RIGHTBOTTOM:
361 break;
362 default:
363 }
364 data.bounds[j].y += minorAdjustment;
365 }
366 data.bounds[j].x += majorAdjustment;
367
368 setBoundsOfChild(parent, data.row[j], transposer.t(data.bounds[j]));
369 }
370 data.rowY += getMajorSpacing() + data.rowHeight;
371 initRow();
372 }
373
374 /**
375 * Sets the given bounds for the child figure input.
376 *
377 * @param parent the parent figure
378 * @param child the child figure
379 * @param bounds the size of the child to be set
380 * @since 2.0
381 */
382 protected void setBoundsOfChild(IFigure parent, IFigure child, Rectangle bounds) {
383 parent.getClientArea(Rectangle.SINGLETON);
384 bounds.translate(Rectangle.SINGLETON.x, Rectangle.SINGLETON.y);
385 child.setBounds(bounds);
386 }
387
388 /**
389 * Sets flag based on layout orientation. If in horizontal orientation, all figures will
390 * have the same height. If in vertical orientation, all figures will have the same width.
391 *
392 * @param value fill state desired
393 * @since 2.0
394 */
395 public void setStretchMinorAxis(bool value) {
396 fill = value;
397 }
398
399 /**
400 * Sets the orientation of the layout.
401 *
402 * @param flag <code>true</code> if this layout should be horizontal
403 * @since 2.0
404 */
405 public void setHorizontal(bool flag) {
406 if (horizontal is flag) return;
407 invalidate();
408 horizontal = flag;
409 transposer.setEnabled(!horizontal);
410 }
411
412 /**
413 * Sets the alignment for an entire row/column within the parent figure.
414 * <P>
415 * Possible values are :
416 * <ul>
417 * <li>{@link #ALIGN_CENTER}
418 * <li>{@link #ALIGN_LEFTTOP}
419 * <li>{@link #ALIGN_RIGHTBOTTOM}
420 * </ul>
421 *
422 * @param align the major alignment
423 * @since 2.0
424 */
425 public void setMajorAlignment(int align_) {
426 majorAlignment = align_;
427 }
428
429 /**
430 * Sets the spacing in pixels to be used between children in the direction parallel to the
431 * layout's orientation.
432 *
433 * @param n the major spacing
434 * @since 2.0
435 */
436 public void setMajorSpacing(int n) {
437 majorSpacing = n;
438 }
439
440 /**
441 * Sets the alignment to be used within a row/column.
442 * <P>
443 * Possible values are :
444 * <ul>
445 * <li>{@link #ALIGN_CENTER}
446 * <li>{@link #ALIGN_LEFTTOP}
447 * <li>{@link #ALIGN_RIGHTBOTTOM}
448 * </ul>
449 *
450 * @param align the minor alignment
451 * @since 2.0
452 */
453 public void setMinorAlignment(int align_) {
454 minorAlignment = align_;
455 }
456
457 /**
458 * Sets the spacing to be used between children within a row/column.
459 *
460 * @param n the minor spacing
461 * @since 2.0
462 */
463 public void setMinorSpacing(int n) {
464 minorSpacing = n;
465 }
466
467 }