comparison org.eclipse.draw2d/src/org/eclipse/draw2d/ToolbarLayout.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, 2007 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.ToolbarLayout;
14
15 import java.lang.all;
16
17 import org.eclipse.draw2d.geometry.Dimension;
18 import org.eclipse.draw2d.geometry.Insets;
19 import org.eclipse.draw2d.geometry.Rectangle;
20 import org.eclipse.draw2d.geometry.Transposer;
21 import org.eclipse.draw2d.AbstractHintLayout;
22 import org.eclipse.draw2d.IFigure;
23
24 /**
25 * Arranges figures in a single row or column. Orientation can be set to produce either
26 * a row or column layout. This layout tries to fit all children within the parent's
27 * client area. To do this, it compresses the children by some amount, but will not
28 * compress them smaller than their minimum size. If a child's preferred size is smaller
29 * than the row's or column's minor dimension, the layout can be configured to stretch the
30 * child.
31 */
32 public class ToolbarLayout
33 : AbstractHintLayout
34 {
35
36 /** Space in pixels between Figures **/
37 protected int spacing;
38 /** Sets whether children should "stretch" with their container **/
39 protected bool matchWidth;
40 /** Orientation of layout **/
41 protected bool horizontal = false;
42 /** Alignment of layout **/
43 protected int minorAlignment;
44
45 /** Constant for center alignment **/
46 public static const int ALIGN_CENTER = 0;
47 /** Constant for top-left alignment **/
48 public static const int ALIGN_TOPLEFT = 1;
49 /** Constant for bottom-right alignment **/
50 public static const int ALIGN_BOTTOMRIGHT = 2;
51
52 /** Constant for horizontal alignment **/
53 public static const bool HORIZONTAL = true;
54 /** Constant for vertical alignment **/
55 public static const bool VERTICAL = false;
56
57 /** Transposer object used in layout calculations **/
58 protected Transposer transposer;
59 private void instanceInit() {
60 transposer = new Transposer();
61 transposer.setEnabled(horizontal);
62 }
63
64 /**
65 * Constructs a vertically oriented ToolbarLayout with child spacing of 0 pixels,
66 * matchWidth <code>true</code>, and {@link #ALIGN_TOPLEFT} alignment.
67 *
68 * @since 2.0
69 */
70 public this() {
71 instanceInit();
72 spacing = 0;
73 matchWidth = true;
74 minorAlignment = ALIGN_TOPLEFT;
75 horizontal = false;
76 }
77
78 /**
79 * Constructs a ToolbarLayout with a specified orientation. Default values are: child
80 * spacing 0 pixels, matchWidth <code>false</code>, and {@link #ALIGN_TOPLEFT}
81 * alignment.
82 *
83 * @param isHorizontal whether the children are oriented horizontally
84 * @since 2.0
85 */
86 public this(bool isHorizontal) {
87 instanceInit();
88 horizontal = isHorizontal;
89 transposer.setEnabled(horizontal);
90 spacing = 0;
91 matchWidth = false;
92 minorAlignment = ALIGN_TOPLEFT;
93 }
94
95 private Dimension calculateChildrenSize(List children, int wHint, int hHint,
96 bool preferred) {
97 Dimension childSize;
98 IFigure child;
99 int height = 0, width = 0;
100 for (int i = 0; i < children.size(); i++) {
101 child = cast(IFigure)children.get(i);
102 childSize = transposer.t(preferred ? getChildPreferredSize(child, wHint, hHint)
103 : getChildMinimumSize(child, wHint, hHint));
104 height += childSize.height;
105 width = Math.max(width, childSize.width);
106 }
107 return new Dimension(width, height);
108 }
109
110 /**
111 * Calculates the minimum size of the container based on the given hints. If this is a
112 * vertically-oriented Toolbar Layout, then only the widthHint is respected (which means
113 * that the children can be as tall as they desire). In this case, the minimum width
114 * is that of the widest child, and the minimum height is the sum of the minimum
115 * heights of all children, plus the spacing between them. The border and insets of the
116 * container figure are also accounted for.
117 *
118 * @param container the figure whose minimum size has to be calculated
119 * @param wHint the width hint (the desired width of the container)
120 * @param hHint the height hint (the desired height of the container)
121 * @return the minimum size of the container
122 * @see #getMinimumSize(IFigure, int, int)
123 * @since 2.1
124 */
125 protected Dimension calculateMinimumSize(IFigure container, int wHint, int hHint) {
126 Insets insets = container.getInsets();
127 if (isHorizontal()) {
128 wHint = -1;
129 if (hHint >= 0)
130 hHint = Math.max(0, hHint - insets.getHeight());
131 } else {
132 hHint = -1;
133 if (wHint >= 0)
134 wHint = Math.max(0, wHint - insets.getWidth());
135 }
136
137 List children = container.getChildren();
138 Dimension minSize = calculateChildrenSize(children, wHint, hHint, false);
139 // Do a second pass, if necessary
140 if (wHint >= 0 && minSize.width > wHint) {
141 minSize = calculateChildrenSize(children, minSize.width, hHint, false);
142 } else if (hHint >= 0 && minSize.width > hHint) {
143 minSize = calculateChildrenSize(children, wHint, minSize.width, false);
144 }
145
146 minSize.height += Math.max(0, children.size() - 1) * spacing;
147 return transposer.t(minSize)
148 .expand(insets.getWidth(), insets.getHeight())
149 .union_(getBorderPreferredSize(container));
150 }
151
152 /**
153 * Calculates the preferred size of the container based on the given hints. If this is a
154 * vertically-oriented Toolbar Layout, then only the widthHint is respected (which means
155 * that the children can be as tall as they desire). In this case, the preferred width
156 * is that of the widest child, and the preferred height is the sum of the preferred
157 * heights of all children, plus the spacing between them. The border and insets of the
158 * container figure are also accounted for.
159 *
160 * @param container the figure whose preferred size has to be calculated
161 * @param wHint the width hint (the desired width of the container)
162 * @param hHint the height hint (the desired height of the container)
163 * @return the preferred size of the container
164 * @see #getPreferredSize(IFigure, int, int)
165 * @since 2.0
166 */
167 protected Dimension calculatePreferredSize(IFigure container, int wHint, int hHint) {
168 Insets insets = container.getInsets();
169 if (isHorizontal()) {
170 wHint = -1;
171 if (hHint >= 0)
172 hHint = Math.max(0, hHint - insets.getHeight());
173 } else {
174 hHint = -1;
175 if (wHint >= 0)
176 wHint = Math.max(0, wHint - insets.getWidth());
177 }
178
179 List children = container.getChildren();
180 Dimension prefSize = calculateChildrenSize(children, wHint, hHint, true);
181 // Do a second pass, if necessary
182 if (wHint >= 0 && prefSize.width > wHint) {
183 prefSize = calculateChildrenSize(children, prefSize.width, hHint, true);
184 } else if (hHint >= 0 && prefSize.width > hHint) {
185 prefSize = calculateChildrenSize(children, wHint, prefSize.width, true);
186 }
187
188 prefSize.height += Math.max(0, children.size() - 1) * spacing;
189 return transposer.t(prefSize)
190 .expand(insets.getWidth(), insets.getHeight())
191 .union_(getBorderPreferredSize(container));
192 }
193
194 /**
195 * @param child the figure whose minimum size is to be determined
196 * @param wHint the width hint
197 * @param hHint the height hint
198 * @return the given figure's minimum size
199 * @since 3.3
200 */
201 protected Dimension getChildMinimumSize(IFigure child, int wHint, int hHint) {
202 return child.getMinimumSize(wHint, hHint);
203 }
204
205 /**
206 * @param child the figure whose preferred size is to be determined
207 * @param wHint the width hint
208 * @param hHint the height hint
209 * @return given figure's preferred size
210 * @since 3.3
211 */
212 protected Dimension getChildPreferredSize(IFigure child, int wHint, int hHint) {
213 return child.getPreferredSize(wHint, hHint);
214 }
215
216 /**
217 * Returns the minor aligment of the layout. Minor minor axis is the axis perpindicular
218 * to the overall orientation set in the contructor.
219 * @return the minor aligment
220 */
221 public int getMinorAlignment() {
222 return minorAlignment;
223 }
224
225 /**
226 * @return the spacing between children
227 */
228 public int getSpacing() {
229 return spacing;
230 }
231
232 /**
233 * Returns <code>true</code> if stretch minor axis has been enabled. The default value is
234 * false.
235 * @return <code>true</code> if stretch minor axis is enabled
236 */
237 public bool getStretchMinorAxis() {
238 return matchWidth;
239 }
240
241 /**
242 * @return whether the orientation of the layout is horizontal
243 * @since 2.0
244 */
245 public bool isHorizontal() {
246 return horizontal;
247 }
248
249 /**
250 * @see org.eclipse.draw2d.AbstractHintLayout#isSensitiveHorizontally(IFigure)
251 */
252 protected bool isSensitiveHorizontally(IFigure parent) {
253 return !isHorizontal();
254 }
255
256 /**
257 * @see org.eclipse.draw2d.AbstractHintLayout#isSensitiveVertically(IFigure)
258 */
259 protected bool isSensitiveVertically(IFigure parent) {
260 return isHorizontal();
261 }
262
263 /**
264 * @see org.eclipse.draw2d.LayoutManager#layout(IFigure)
265 */
266 public void layout(IFigure parent) {
267 List children = parent.getChildren();
268 int numChildren = children.size();
269 Rectangle clientArea = transposer.t(parent.getClientArea());
270 int x = clientArea.x;
271 int y = clientArea.y;
272 int availableHeight = clientArea.height;
273
274 Dimension prefSizes [] = new Dimension[numChildren];
275 Dimension minSizes [] = new Dimension[numChildren];
276
277 // Calculate the width and height hints. If it's a vertical ToolBarLayout,
278 // then ignore the height hint (set it to -1); otherwise, ignore the
279 // width hint. These hints will be passed to the children of the parent
280 // figure when getting their preferred size.
281 int wHint = -1;
282 int hHint = -1;
283 if (isHorizontal()) {
284 hHint = parent.getClientArea(Rectangle.SINGLETON).height;
285 } else {
286 wHint = parent.getClientArea(Rectangle.SINGLETON).width;
287 }
288
289 /*
290 * Calculate sum of preferred heights of all children(totalHeight).
291 * Calculate sum of minimum heights of all children(minHeight).
292 * Cache Preferred Sizes and Minimum Sizes of all children.
293 *
294 * totalHeight is the sum of the preferred heights of all children
295 * totalMinHeight is the sum of the minimum heights of all children
296 * prefMinSumHeight is the sum of the difference between all children's
297 * preferred heights and minimum heights. (This is used as a ratio to
298 * calculate how much each child will shrink).
299 */
300 IFigure child;
301 int totalHeight = 0;
302 int totalMinHeight = 0;
303 int prefMinSumHeight = 0;
304
305 for (int i = 0; i < numChildren; i++) {
306 child = cast(IFigure)children.get(i);
307
308 prefSizes[i] = transposer.t(getChildPreferredSize(child, wHint, hHint));
309 minSizes[i] = transposer.t(getChildMinimumSize(child, wHint, hHint));
310
311 totalHeight += prefSizes[i].height;
312 totalMinHeight += minSizes[i].height;
313 }
314 totalHeight += (numChildren - 1) * spacing;
315 totalMinHeight += (numChildren - 1) * spacing;
316 prefMinSumHeight = totalHeight - totalMinHeight;
317 /*
318 * The total amount that the children must be shrunk is the
319 * sum of the preferred Heights of the children minus
320 * Max(the available area and the sum of the minimum heights of the children).
321 *
322 * amntShrinkHeight is the combined amount that the children must shrink
323 * amntShrinkCurrentHeight is the amount each child will shrink respectively
324 */
325 int amntShrinkHeight = totalHeight - Math.max(availableHeight, totalMinHeight);
326
327 if (amntShrinkHeight < 0) {
328 amntShrinkHeight = 0;
329 }
330
331 for (int i = 0; i < numChildren; i++) {
332 int amntShrinkCurrentHeight = 0;
333 int prefHeight = prefSizes[i].height;
334 int minHeight = minSizes[i].height;
335 int prefWidth = prefSizes[i].width;
336 int minWidth = minSizes[i].width;
337 Rectangle newBounds = new Rectangle(x, y, prefWidth, prefHeight);
338
339 child = cast(IFigure)children.get(i);
340 if (prefMinSumHeight !is 0)
341 amntShrinkCurrentHeight =
342 (prefHeight - minHeight) * amntShrinkHeight / (prefMinSumHeight);
343
344 int width = Math.min(prefWidth, transposer.t(child.getMaximumSize()).width);
345 if (matchWidth)
346 width = transposer.t(child.getMaximumSize()).width;
347 width = Math.max(minWidth, Math.min(clientArea.width, width));
348 newBounds.width = width;
349
350 int adjust = clientArea.width - width;
351 switch (minorAlignment) {
352 case ALIGN_TOPLEFT:
353 adjust = 0;
354 break;
355 case ALIGN_CENTER:
356 adjust /= 2;
357 break;
358 case ALIGN_BOTTOMRIGHT:
359 break;
360 default:
361 }
362 newBounds.x += adjust;
363 newBounds.height -= amntShrinkCurrentHeight;
364 child.setBounds(transposer.t(newBounds));
365
366 amntShrinkHeight -= amntShrinkCurrentHeight;
367 prefMinSumHeight -= (prefHeight - minHeight);
368 y += newBounds.height + spacing;
369 }
370 }
371
372 /**
373 * Sets the alignment of the children contained in the layout. Possible values are
374 * {@link #ALIGN_CENTER}, {@link #ALIGN_BOTTOMRIGHT} and {@link #ALIGN_TOPLEFT}.
375 *
376 * @param align the minor alignment
377 * @since 2.0
378 */
379 public void setMinorAlignment(int align_) {
380 minorAlignment = align_;
381 }
382
383 /**
384 * Sets the amount of space between children.
385 *
386 * @param space the amount of space between children
387 * @since 2.0
388 */
389 public void setSpacing(int space) {
390 spacing = space;
391 }
392
393 /**
394 * Sets children's width (if vertically oriented) or height (if horizontally oriented) to
395 * stretch with their container.
396 *
397 * @deprecated use {@link #setStretchMinorAxis(bool)}
398 * @param match whether to stretch children
399 * @since 2.0
400 */
401 public void setMatchWidth(bool match) {
402 matchWidth = match;
403 }
404
405 /**
406 * Causes children that are smaller in the dimension of the minor axis to be stretched to
407 * fill the minor axis. The minor axis is the opposite of the orientation.
408 * @param stretch whether to stretch children
409 * @since 2.0
410 */
411 public void setStretchMinorAxis(bool stretch) {
412 matchWidth = stretch;
413 }
414
415 /**
416 * Sets the orientation of the children in the ToolbarLayout.
417 *
418 * @param flag whether the orientation should be vertical
419 * @since 2.0
420 */
421 public void setVertical(bool flag) {
422 if (horizontal !is flag) return;
423 invalidate();
424 horizontal = !flag;
425 transposer.setEnabled(horizontal);
426 }
427
428 }