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