Mercurial > projects > dwt2
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 } |