Mercurial > projects > dwt-addons
annotate dwtx/ui/forms/widgets/TableWrapLayout.d @ 128:8df1d4193877
Fix: runtime error in ui.forms. Arrays had an intermediate copy, so values were not stored correctly.
Add: collection impls.
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sun, 17 Aug 2008 02:05:20 +0200 |
parents | 04b47443bb01 |
children |
rev | line source |
---|---|
75 | 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 dwtx.ui.forms.widgets.TableWrapLayout; | |
14 | |
15 import dwtx.ui.forms.widgets.TableWrapData; | |
16 import dwtx.ui.forms.widgets.ILayoutExtension; | |
17 import dwtx.ui.forms.widgets.LayoutCache; | |
18 import dwtx.ui.forms.widgets.SizeCache; | |
19 | |
20 import dwt.DWT; | |
21 import dwt.graphics.Point; | |
22 import dwt.graphics.Rectangle; | |
23 import dwt.widgets.Composite; | |
24 import dwt.widgets.Control; | |
25 import dwt.widgets.Layout; | |
26 | |
27 import dwt.dwthelper.utils; | |
104
04b47443bb01
Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections.
Frank Benoit <benoit@tionex.de>
parents:
85
diff
changeset
|
28 import dwtx.dwtxhelper.Collection; |
75 | 29 |
30 /** | |
31 * This implementation of the layout algorithm attempts to position controls in | |
32 * the composite using a two-pass autolayout HTML table altorithm recommeded by | |
33 * HTML 4.01 W3C specification (see | |
34 * http://www.w3.org/TR/html4/appendix/notes.html#h-B.5.2.2). The main | |
35 * differences with GridLayout is that it has two passes and that width and | |
36 * height are not calculated in the same pass. | |
37 * <p> | |
38 * The advantage of the algorithm over GridLayout is that it is capable of | |
39 * flowing text controls capable of line wrap. These controls do not have | |
40 * natural 'preferred size'. Instead, they are capable of providing the required | |
41 * height if the width is set. Consequently, this algorithm first calculates the | |
42 * widths that will be assigned to columns, and then passes those widths to the | |
43 * controls to calculate the height. When a composite with this layout is a | |
44 * child of the scrolling composite, they should interact in such a way that | |
45 * reduction in the scrolling composite width results in the reflow and increase | |
46 * of the overall height. | |
47 * <p> | |
48 * If none of the columns contain expandable and wrappable controls, the | |
49 * end-result will be similar to the one provided by GridLayout. The difference | |
50 * will show up for layouts that contain controls whose minimum and maximum | |
51 * widths are not the same. | |
52 * | |
53 * @see TableWrapData | |
54 * @since 3.0 | |
55 */ | |
56 public final class TableWrapLayout : Layout, ILayoutExtension { | |
57 | |
58 public alias Layout.computeSize computeSize; | |
59 /** | |
60 * Number of columns to use when positioning children (default is 1). | |
61 */ | |
62 public int numColumns = 1; | |
63 | |
64 /** | |
65 * Left margin variable (default is 5). | |
66 */ | |
67 public int leftMargin = 5; | |
68 | |
69 /** | |
70 * Right margin variable (default is 5). | |
71 */ | |
72 public int rightMargin = 5; | |
73 | |
74 /** | |
75 * Top margin variable (default is 5). | |
76 */ | |
77 public int topMargin = 5; | |
78 | |
79 /** | |
80 * Botom margin variable (default is 5). | |
81 */ | |
82 public int bottomMargin = 5; | |
83 | |
84 /** | |
85 * Horizontal spacing (default is 5). | |
86 */ | |
87 public int horizontalSpacing = 5; | |
88 | |
89 /** | |
90 * Vertical spacing (default is 5). | |
91 */ | |
92 public int verticalSpacing = 5; | |
93 | |
94 /** | |
95 * If set to <code>true</code>, all the columns will have the same width. | |
96 * Otherwise, column widths will be computed based on controls in them and | |
97 * their layout data (default is <code>false</code>). | |
98 */ | |
99 public bool makeColumnsEqualWidth = false; | |
100 | |
101 private bool initialLayout = true; | |
102 | |
104
04b47443bb01
Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections.
Frank Benoit <benoit@tionex.de>
parents:
85
diff
changeset
|
103 private Vector grid = null; |
75 | 104 |
104
04b47443bb01
Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections.
Frank Benoit <benoit@tionex.de>
parents:
85
diff
changeset
|
105 private Hashtable rowspans; |
75 | 106 |
107 private int[] minColumnWidths, maxColumnWidths; | |
108 | |
109 private int widestColumnWidth; | |
110 | |
111 private int[] growingColumns; | |
112 | |
113 private int[] growingRows; | |
114 | |
115 private LayoutCache cache; | |
116 | |
117 private class RowSpan { | |
118 Control child; | |
119 | |
120 int row; | |
121 | |
122 int column; | |
123 | |
124 int height; | |
125 | |
126 int totalHeight; | |
127 | |
128 public this(Control child, int column, int row) { | |
129 this.child = child; | |
130 this.column = column; | |
131 this.row = row; | |
132 } | |
133 | |
134 /* | |
135 * Updates this row span's height with the given one if it is within | |
136 * this span. | |
137 */ | |
138 public void update(int currentRow, int rowHeight) { | |
139 TableWrapData td = cast(TableWrapData) child.getLayoutData(); | |
140 // is currentRow within this span? | |
141 if (currentRow >= row && currentRow < row + td.rowspan) { | |
142 totalHeight += rowHeight; | |
143 if (currentRow > row) | |
144 totalHeight += verticalSpacing; | |
145 } | |
146 } | |
147 | |
148 public int getRequiredHeightIncrease() { | |
149 if (totalHeight < height) | |
150 return height - totalHeight; | |
151 return 0; | |
152 } | |
153 } | |
154 | |
155 this(){ | |
156 cache = new LayoutCache(); | |
157 } | |
158 | |
159 /** | |
160 * Implements ILayoutExtension. Should not be called directly. | |
161 * | |
162 * @see ILayoutExtension | |
163 */ | |
164 public int computeMinimumWidth(Composite parent, bool changed) { | |
165 | |
166 Control[] children = parent.getChildren(); | |
167 if (changed) { | |
168 cache.flush(); | |
169 } | |
170 | |
171 cache.setControls(children); | |
172 | |
173 changed = true; | |
174 initializeIfNeeded(parent, changed); | |
175 if (initialLayout) { | |
176 changed = true; | |
177 initialLayout = false; | |
178 } | |
179 if (grid is null || changed) { | |
180 changed = true; | |
104
04b47443bb01
Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections.
Frank Benoit <benoit@tionex.de>
parents:
85
diff
changeset
|
181 grid = new Vector(); |
75 | 182 createGrid(parent); |
183 } | |
184 if (minColumnWidths is null) | |
185 minColumnWidths = new int[numColumns]; | |
186 for (int i = 0; i < numColumns; i++) { | |
187 minColumnWidths[i] = 0; | |
188 } | |
189 return internalGetMinimumWidth(parent, changed); | |
190 } | |
191 | |
192 /** | |
193 * Implements ILayoutExtension. Should not be called directly. | |
194 * | |
195 * @see ILayoutExtension | |
196 */ | |
197 public int computeMaximumWidth(Composite parent, bool changed) { | |
198 Control[] children = parent.getChildren(); | |
199 if (changed) { | |
200 cache.flush(); | |
201 } | |
202 | |
203 cache.setControls(children); | |
204 | |
205 changed = true; | |
206 initializeIfNeeded(parent, changed); | |
207 if (initialLayout) { | |
208 changed = true; | |
209 initialLayout = false; | |
210 } | |
211 if (grid is null || changed) { | |
212 changed = true; | |
104
04b47443bb01
Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections.
Frank Benoit <benoit@tionex.de>
parents:
85
diff
changeset
|
213 grid = new Vector(); |
75 | 214 createGrid(parent); |
215 } | |
216 if (maxColumnWidths is null) | |
217 maxColumnWidths = new int[numColumns]; | |
218 for (int i = 0; i < numColumns; i++) { | |
219 maxColumnWidths[i] = 0; | |
220 } | |
221 return internalGetMaximumWidth(parent, changed); | |
222 } | |
223 | |
224 /** | |
225 * @see Layout#layout(Composite, bool) | |
226 */ | |
227 protected void layout(Composite parent, bool changed) { | |
228 | |
229 Rectangle clientArea = parent.getClientArea(); | |
230 Control[] children = parent.getChildren(); | |
231 if (changed) { | |
232 cache.flush(); | |
233 } | |
234 | |
235 if (children.length is 0) | |
236 return; | |
237 | |
238 cache.setControls(children); | |
239 | |
240 int parentWidth = clientArea.width; | |
241 changed = true; | |
242 initializeIfNeeded(parent, changed); | |
243 if (initialLayout) { | |
244 changed = true; | |
245 initialLayout = false; | |
246 } | |
247 if (grid is null || changed) { | |
248 changed = true; | |
104
04b47443bb01
Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections.
Frank Benoit <benoit@tionex.de>
parents:
85
diff
changeset
|
249 grid = new Vector(); |
75 | 250 createGrid(parent); |
251 } | |
252 resetColumnWidths(); | |
253 int minWidth = internalGetMinimumWidth(parent, changed); | |
254 int maxWidth = internalGetMaximumWidth(parent, changed); | |
255 int tableWidth = parentWidth; | |
256 int[] columnWidths; | |
257 if (parentWidth <= minWidth) { | |
258 tableWidth = minWidth; | |
259 if (makeColumnsEqualWidth) { | |
260 columnWidths = new int[numColumns]; | |
261 for (int i = 0; i < numColumns; i++) { | |
262 columnWidths[i] = widestColumnWidth; | |
263 } | |
264 } else | |
265 columnWidths = minColumnWidths; | |
266 } else if (parentWidth > maxWidth) { | |
267 if (growingColumns.length is 0) { | |
268 tableWidth = maxWidth; | |
269 columnWidths = maxColumnWidths; | |
270 } else { | |
271 columnWidths = new int[numColumns]; | |
272 int colSpace = tableWidth - leftMargin - rightMargin; | |
273 colSpace -= (numColumns - 1) * horizontalSpacing; | |
274 int extra = parentWidth - maxWidth; | |
275 int colExtra = extra / growingColumns.length; | |
276 for (int i = 0; i < numColumns; i++) { | |
277 columnWidths[i] = maxColumnWidths[i]; | |
278 if (isGrowingColumn(i)) { | |
279 columnWidths[i] += colExtra; | |
280 } | |
281 } | |
282 } | |
283 } else { | |
284 columnWidths = new int[numColumns]; | |
285 if (makeColumnsEqualWidth) { | |
286 int colSpace = tableWidth - leftMargin - rightMargin; | |
287 colSpace -= (numColumns - 1) * horizontalSpacing; | |
288 int col = colSpace / numColumns; | |
289 for (int i = 0; i < numColumns; i++) { | |
290 columnWidths[i] = col; | |
291 } | |
292 } else { | |
293 columnWidths = assignExtraSpace(tableWidth, maxWidth, minWidth); | |
294 } | |
295 } | |
296 int y = topMargin+clientArea.y; | |
297 int[] rowHeights = computeRowHeights(children, columnWidths, changed); | |
298 for (int i = 0; i < grid.size(); i++) { | |
299 int rowHeight = rowHeights[i]; | |
300 int x = leftMargin+clientArea.x; | |
104
04b47443bb01
Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections.
Frank Benoit <benoit@tionex.de>
parents:
85
diff
changeset
|
301 TableWrapData[] row = arrayFromObject!(TableWrapData)( grid.elementAt(i)); |
75 | 302 for (int j = 0; j < numColumns; j++) { |
303 TableWrapData td = row[j]; | |
304 if (td.isItemData) { | |
305 Control child = children[td.childIndex]; | |
306 placeControl(child, td, x, y, rowHeights, i); | |
307 } | |
308 x += columnWidths[j]; | |
309 if (j < numColumns - 1) | |
310 x += horizontalSpacing; | |
311 } | |
312 y += rowHeight + verticalSpacing; | |
313 } | |
314 } | |
315 | |
316 int[] computeRowHeights(Control[] children, int[] columnWidths, | |
317 bool changed) { | |
318 int[] rowHeights = new int[grid.size()]; | |
319 for (int i = 0; i < grid.size(); i++) { | |
104
04b47443bb01
Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections.
Frank Benoit <benoit@tionex.de>
parents:
85
diff
changeset
|
320 TableWrapData[] row = arrayFromObject!(TableWrapData)( grid.elementAt(i)); |
75 | 321 rowHeights[i] = 0; |
322 for (int j = 0; j < numColumns; j++) { | |
323 TableWrapData td = row[j]; | |
324 if (td.isItemData is false) { | |
325 continue; | |
326 } | |
327 Control child = children[td.childIndex]; | |
328 int span = td.colspan; | |
329 int cwidth = 0; | |
330 for (int k = j; k < j + span; k++) { | |
331 cwidth += columnWidths[k]; | |
332 if (k < j + span - 1) | |
333 cwidth += horizontalSpacing; | |
334 } | |
335 Point size = computeSize(td.childIndex, cwidth, td.indent, td.maxWidth, td.maxHeight); | |
336 td.compWidth = cwidth; | |
337 if (td.heightHint !is DWT.DEFAULT) { | |
338 size = new Point(size.x, td.heightHint); | |
339 } | |
340 td.compSize = size; | |
104
04b47443bb01
Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections.
Frank Benoit <benoit@tionex.de>
parents:
85
diff
changeset
|
341 RowSpan rowspan = cast(RowSpan) rowspans.get(child); |
75 | 342 if (rowspan is null) { |
343 rowHeights[i] = Math.max(rowHeights[i], size.y); | |
344 } else | |
345 rowspan.height = size.y; | |
346 } | |
347 updateRowSpans(i, rowHeights[i]); | |
348 } | |
104
04b47443bb01
Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections.
Frank Benoit <benoit@tionex.de>
parents:
85
diff
changeset
|
349 for (Enumeration enm = rowspans.elements(); enm.hasMoreElements();) { |
04b47443bb01
Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections.
Frank Benoit <benoit@tionex.de>
parents:
85
diff
changeset
|
350 RowSpan rowspan = cast(RowSpan) enm.nextElement(); |
75 | 351 int increase = rowspan.getRequiredHeightIncrease(); |
352 if (increase is 0) | |
353 continue; | |
354 TableWrapData td = cast(TableWrapData) rowspan.child.getLayoutData(); | |
355 int ngrowing = 0; | |
356 int[] affectedRows = new int[grid.size()]; | |
357 for (int i = 0; i < growingRows.length; i++) { | |
358 int growingRow = growingRows[i]; | |
359 if (growingRow >= rowspan.row | |
360 && growingRow < rowspan.row + td.rowspan) { | |
361 affectedRows[ngrowing++] = growingRow; | |
362 } | |
363 } | |
364 if (ngrowing is 0) { | |
365 ngrowing = 1; | |
366 affectedRows[0] = rowspan.row + td.rowspan - 1; | |
367 } | |
368 increase += increase % ngrowing; | |
369 int perRowIncrease = increase / ngrowing; | |
370 for (int i = 0; i < ngrowing; i++) { | |
371 int growingRow = affectedRows[i]; | |
372 rowHeights[growingRow] += perRowIncrease; | |
373 } | |
374 } | |
375 return rowHeights; | |
376 } | |
377 | |
378 bool isGrowingColumn(int col) { | |
379 if (growingColumns is null) | |
380 return false; | |
381 for (int i = 0; i < growingColumns.length; i++) { | |
382 if (col is growingColumns[i]) | |
383 return true; | |
384 } | |
385 return false; | |
386 } | |
387 | |
388 int[] assignExtraSpace(int tableWidth, int maxWidth, int minWidth) { | |
389 int fixedPart = leftMargin + rightMargin + (numColumns - 1) | |
390 * horizontalSpacing; | |
391 int D = maxWidth - minWidth; | |
392 int W = tableWidth - fixedPart - minWidth; | |
393 int widths[] = new int[numColumns]; | |
394 int rem = 0; | |
395 for (int i = 0; i < numColumns; i++) { | |
396 int cmin = minColumnWidths[i]; | |
397 int cmax = maxColumnWidths[i]; | |
398 int d = cmax - cmin; | |
399 int extra = D !is 0 ? (d * W) / D : 0; | |
400 if (i < numColumns - 1) { | |
401 widths[i] = cmin + extra; | |
402 rem += widths[i]; | |
403 } else { | |
404 widths[i] = tableWidth - fixedPart - rem; | |
405 } | |
406 } | |
407 return widths; | |
408 } | |
409 | |
410 Point computeSize(int childIndex, int width, int indent, int maxWidth, int maxHeight) { | |
411 int widthArg = width - indent; | |
412 SizeCache controlCache = cache.getCache(childIndex); | |
413 if (!isWrap(controlCache.getControl())) | |
414 widthArg = DWT.DEFAULT; | |
415 Point size = controlCache.computeSize(widthArg, DWT.DEFAULT); | |
416 if (maxWidth !is DWT.DEFAULT) | |
417 size.x = Math.min(size.x, maxWidth); | |
418 if (maxHeight !is DWT.DEFAULT) | |
419 size.y = Math.min(size.y, maxHeight); | |
420 size.x += indent; | |
421 return size; | |
422 } | |
423 | |
424 void placeControl(Control control, TableWrapData td, int x, int y, | |
425 int[] rowHeights, int row) { | |
426 int xloc = x + td.indent; | |
427 int yloc = y; | |
428 int height = td.compSize.y; | |
429 int colWidth = td.compWidth - td.indent; | |
430 int width = td.compSize.x-td.indent; | |
431 width = Math.min(width, colWidth); | |
432 int slotHeight = rowHeights[row]; | |
104
04b47443bb01
Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections.
Frank Benoit <benoit@tionex.de>
parents:
85
diff
changeset
|
433 RowSpan rowspan = cast(RowSpan) rowspans.get(control); |
75 | 434 if (rowspan !is null) { |
435 slotHeight = 0; | |
436 for (int i = row; i < row + td.rowspan; i++) { | |
437 if (i > row) | |
438 slotHeight += verticalSpacing; | |
439 slotHeight += rowHeights[i]; | |
440 } | |
441 } | |
442 // align horizontally | |
443 if (td.align_ is TableWrapData.CENTER) { | |
444 xloc = x + colWidth / 2 - width / 2; | |
445 } else if (td.align_ is TableWrapData.RIGHT) { | |
446 xloc = x + colWidth - width; | |
447 } else if (td.align_ is TableWrapData.FILL) { | |
448 width = colWidth; | |
449 } | |
450 // align vertically | |
451 if (td.valign is TableWrapData.MIDDLE) { | |
452 yloc = y + slotHeight / 2 - height / 2; | |
453 } else if (td.valign is TableWrapData.BOTTOM) { | |
454 yloc = y + slotHeight - height; | |
455 } else if (td.valign is TableWrapData.FILL) { | |
456 height = slotHeight; | |
457 } | |
458 control.setBounds(xloc, yloc, width, height); | |
459 } | |
460 | |
461 void createGrid(Composite composite) { | |
462 int row, column, rowFill, columnFill; | |
463 Control[] children; | |
464 TableWrapData spacerSpec; | |
104
04b47443bb01
Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections.
Frank Benoit <benoit@tionex.de>
parents:
85
diff
changeset
|
465 Vector growingCols = new Vector(); |
04b47443bb01
Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections.
Frank Benoit <benoit@tionex.de>
parents:
85
diff
changeset
|
466 Vector growingRows = new Vector(); |
04b47443bb01
Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections.
Frank Benoit <benoit@tionex.de>
parents:
85
diff
changeset
|
467 rowspans = new Hashtable(); |
75 | 468 // |
469 children = composite.getChildren(); | |
470 if (children.length is 0) | |
471 return; | |
472 // | |
104
04b47443bb01
Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections.
Frank Benoit <benoit@tionex.de>
parents:
85
diff
changeset
|
473 grid.addElement( new ArrayWrapperObject(createEmptyRow())); |
75 | 474 row = 0; |
475 column = 0; | |
476 // Loop through the children and place their associated layout specs in | |
477 // the | |
478 // grid. Placement occurs left to right, top to bottom (i.e., by row). | |
479 for (int i = 0; i < children.length; i++) { | |
480 // Find the first available spot in the grid. | |
481 Control child = children[i]; | |
482 TableWrapData spec = cast(TableWrapData) child.getLayoutData(); | |
104
04b47443bb01
Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections.
Frank Benoit <benoit@tionex.de>
parents:
85
diff
changeset
|
483 while (arrayFromObject!(TableWrapData)( grid.elementAt(row))[column] !is null) { |
75 | 484 column = column + 1; |
485 if (column >= numColumns) { | |
486 row = row + 1; | |
487 column = 0; | |
488 if (row >= grid.size()) { | |
104
04b47443bb01
Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections.
Frank Benoit <benoit@tionex.de>
parents:
85
diff
changeset
|
489 grid.addElement(new ArrayWrapperObject(createEmptyRow())); |
75 | 490 } |
491 } | |
492 } | |
493 // See if the place will support the widget's horizontal span. If | |
494 // not, go to the | |
495 // next row. | |
496 if (column + spec.colspan - 1 >= numColumns) { | |
104
04b47443bb01
Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections.
Frank Benoit <benoit@tionex.de>
parents:
85
diff
changeset
|
497 grid.addElement(new ArrayWrapperObject(createEmptyRow())); |
75 | 498 row = row + 1; |
499 column = 0; | |
500 } | |
501 // The vertical span for the item will be at least 1. If it is > 1, | |
502 // add other rows to the grid. | |
503 if (spec.rowspan > 1) { | |
104
04b47443bb01
Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections.
Frank Benoit <benoit@tionex.de>
parents:
85
diff
changeset
|
504 rowspans.put(child, new RowSpan(child, column, row)); |
75 | 505 } |
506 for (int j = 2; j <= spec.rowspan; j++) { | |
507 if (row + j > grid.size()) { | |
104
04b47443bb01
Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections.
Frank Benoit <benoit@tionex.de>
parents:
85
diff
changeset
|
508 grid.addElement(new ArrayWrapperObject(createEmptyRow())); |
75 | 509 } |
510 } | |
511 // Store the layout spec. Also cache the childIndex. NOTE: That we | |
512 // assume the children of a | |
513 // composite are maintained in the order in which they are created | |
514 // and added to the composite. | |
128
8df1d4193877
Fix: runtime error in ui.forms. Arrays had an intermediate copy, so values were not stored correctly.
Frank Benoit <benoit@tionex.de>
parents:
104
diff
changeset
|
515 (cast(ArrayWrapperObject) grid.elementAt(row)).array[column] = spec; |
75 | 516 spec.childIndex = i; |
517 if (spec.grabHorizontal) { | |
518 updateGrowingColumns(growingCols, spec, column); | |
519 } | |
520 if (spec.grabVertical) { | |
521 updateGrowingRows(growingRows, spec, row); | |
522 } | |
523 // Put spacers in the grid to account for the item's vertical and | |
524 // horizontal | |
525 // span. | |
526 rowFill = spec.rowspan - 1; | |
527 columnFill = spec.colspan - 1; | |
528 for (int r = 1; r <= rowFill; r++) { | |
529 for (int c = 0; c < spec.colspan; c++) { | |
530 spacerSpec = new TableWrapData(); | |
531 spacerSpec.isItemData = false; | |
128
8df1d4193877
Fix: runtime error in ui.forms. Arrays had an intermediate copy, so values were not stored correctly.
Frank Benoit <benoit@tionex.de>
parents:
104
diff
changeset
|
532 (cast(ArrayWrapperObject) grid.elementAt(row + r)).array[column + c] = spacerSpec; |
75 | 533 } |
534 } | |
535 for (int c = 1; c <= columnFill; c++) { | |
536 for (int r = 0; r < spec.rowspan; r++) { | |
537 spacerSpec = new TableWrapData(); | |
538 spacerSpec.isItemData = false; | |
128
8df1d4193877
Fix: runtime error in ui.forms. Arrays had an intermediate copy, so values were not stored correctly.
Frank Benoit <benoit@tionex.de>
parents:
104
diff
changeset
|
539 (cast(ArrayWrapperObject) grid.elementAt(row + r)).array[column + c] = spacerSpec; |
75 | 540 } |
541 } | |
542 column = column + spec.colspan - 1; | |
543 } | |
544 // Fill out empty grid cells with spacers. | |
545 for (int k = column + 1; k < numColumns; k++) { | |
546 spacerSpec = new TableWrapData(); | |
547 spacerSpec.isItemData = false; | |
128
8df1d4193877
Fix: runtime error in ui.forms. Arrays had an intermediate copy, so values were not stored correctly.
Frank Benoit <benoit@tionex.de>
parents:
104
diff
changeset
|
548 (cast(ArrayWrapperObject) grid.elementAt(row)).array[k] = spacerSpec; |
75 | 549 } |
550 for (int k = row + 1; k < grid.size(); k++) { | |
551 spacerSpec = new TableWrapData(); | |
552 spacerSpec.isItemData = false; | |
128
8df1d4193877
Fix: runtime error in ui.forms. Arrays had an intermediate copy, so values were not stored correctly.
Frank Benoit <benoit@tionex.de>
parents:
104
diff
changeset
|
553 (cast(ArrayWrapperObject) grid.elementAt(k)).array[column] = spacerSpec; |
75 | 554 } |
555 growingColumns = new int[growingCols.size()]; | |
556 for (int i = 0; i < growingCols.size(); i++) { | |
557 growingColumns[i] = (cast(Integer) growingCols.get(i)).intValue(); | |
558 } | |
559 this.growingRows = new int[growingRows.size()]; | |
560 for (int i = 0; i < growingRows.size(); i++) { | |
561 this.growingRows[i] = (cast(Integer) growingRows.get(i)).intValue(); | |
562 } | |
563 } | |
564 | |
104
04b47443bb01
Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections.
Frank Benoit <benoit@tionex.de>
parents:
85
diff
changeset
|
565 private void updateGrowingColumns(Vector growingColumns, |
75 | 566 TableWrapData spec, int column) { |
567 int affectedColumn = column + spec.colspan - 1; | |
568 for (int i = 0; i < growingColumns.size(); i++) { | |
569 Integer col = cast(Integer) growingColumns.get(i); | |
570 if (col.intValue() is affectedColumn) | |
571 return; | |
572 } | |
104
04b47443bb01
Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections.
Frank Benoit <benoit@tionex.de>
parents:
85
diff
changeset
|
573 growingColumns.add(new Integer(affectedColumn)); |
75 | 574 } |
575 | |
104
04b47443bb01
Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections.
Frank Benoit <benoit@tionex.de>
parents:
85
diff
changeset
|
576 private void updateGrowingRows(Vector growingRows, TableWrapData spec, |
75 | 577 int row) { |
578 int affectedRow = row + spec.rowspan - 1; | |
579 for (int i = 0; i < growingRows.size(); i++) { | |
580 Integer irow = cast(Integer) growingRows.get(i); | |
581 if (irow.intValue() is affectedRow) | |
582 return; | |
583 } | |
104
04b47443bb01
Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections.
Frank Benoit <benoit@tionex.de>
parents:
85
diff
changeset
|
584 growingRows.add(new Integer(affectedRow)); |
75 | 585 } |
586 | |
587 private TableWrapData[] createEmptyRow() { | |
588 TableWrapData[] row = new TableWrapData[numColumns]; | |
589 for (int i = 0; i < numColumns; i++) | |
590 row[i] = null; | |
591 return row; | |
592 } | |
593 | |
594 /** | |
595 * @see Layout#computeSize(Composite, int, int, bool) | |
596 */ | |
597 /+protected+/ override Point computeSize(Composite parent, int wHint, int hHint, | |
598 bool changed) { | |
599 Control[] children = parent.getChildren(); | |
600 if (changed) { | |
601 cache.flush(); | |
602 } | |
603 if (children.length is 0) { | |
604 return new Point(0, 0); | |
605 } | |
606 cache.setControls(children); | |
607 | |
608 int parentWidth = wHint; | |
609 changed = true; | |
610 initializeIfNeeded(parent, changed); | |
611 if (initialLayout) { | |
612 changed = true; | |
613 initialLayout = false; | |
614 } | |
615 if (grid is null || changed) { | |
616 changed = true; | |
104
04b47443bb01
Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections.
Frank Benoit <benoit@tionex.de>
parents:
85
diff
changeset
|
617 grid = new Vector(); |
75 | 618 createGrid(parent); |
619 } | |
620 resetColumnWidths(); | |
621 int minWidth = internalGetMinimumWidth(parent, changed); | |
622 int maxWidth = internalGetMaximumWidth(parent, changed); | |
623 | |
624 if (wHint is DWT.DEFAULT) | |
625 parentWidth = maxWidth; | |
626 | |
627 int tableWidth = parentWidth; | |
628 int[] columnWidths; | |
629 if (parentWidth <= minWidth) { | |
630 tableWidth = minWidth; | |
631 if (makeColumnsEqualWidth) { | |
632 columnWidths = new int[numColumns]; | |
633 for (int i = 0; i < numColumns; i++) { | |
634 columnWidths[i] = widestColumnWidth; | |
635 } | |
636 } else | |
637 columnWidths = minColumnWidths; | |
638 } else if (parentWidth >= maxWidth) { | |
639 if (makeColumnsEqualWidth) { | |
640 columnWidths = new int[numColumns]; | |
641 int colSpace = parentWidth - leftMargin - rightMargin; | |
642 colSpace -= (numColumns - 1) * horizontalSpacing; | |
643 int col = colSpace / numColumns; | |
644 for (int i = 0; i < numColumns; i++) { | |
645 columnWidths[i] = col; | |
646 } | |
647 } else { | |
648 tableWidth = maxWidth; | |
649 columnWidths = maxColumnWidths; | |
650 } | |
651 } else { | |
652 columnWidths = new int[numColumns]; | |
653 if (makeColumnsEqualWidth) { | |
654 int colSpace = tableWidth - leftMargin - rightMargin; | |
655 colSpace -= (numColumns - 1) * horizontalSpacing; | |
656 int col = colSpace / numColumns; | |
657 for (int i = 0; i < numColumns; i++) { | |
658 columnWidths[i] = col; | |
659 } | |
660 } else { | |
661 columnWidths = assignExtraSpace(tableWidth, maxWidth, minWidth); | |
662 } | |
663 } | |
664 int totalHeight = 0; | |
665 int innerHeight = 0; | |
666 // compute widths | |
667 for (int i = 0; i < grid.size(); i++) { | |
104
04b47443bb01
Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections.
Frank Benoit <benoit@tionex.de>
parents:
85
diff
changeset
|
668 TableWrapData[] row = arrayFromObject!(TableWrapData)( grid.elementAt(i)); |
75 | 669 // assign widths, calculate heights |
670 int rowHeight = 0; | |
671 for (int j = 0; j < numColumns; j++) { | |
672 TableWrapData td = row[j]; | |
673 if (td.isItemData is false) { | |
674 continue; | |
675 } | |
676 Control child = children[td.childIndex]; | |
677 int span = td.colspan; | |
678 int cwidth = 0; | |
679 for (int k = j; k < j + span; k++) { | |
680 if (k > j) | |
681 cwidth += horizontalSpacing; | |
682 cwidth += columnWidths[k]; | |
683 } | |
684 int cy = td.heightHint; | |
685 if (cy is DWT.DEFAULT) { | |
686 Point size = computeSize(td.childIndex, cwidth, td.indent, td.maxWidth, td.maxHeight); | |
687 cy = size.y; | |
688 } | |
104
04b47443bb01
Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections.
Frank Benoit <benoit@tionex.de>
parents:
85
diff
changeset
|
689 RowSpan rowspan = cast(RowSpan) rowspans.get(child); |
75 | 690 if (rowspan !is null) { |
691 // don't take the height of this child into acount | |
692 // because it spans multiple rows | |
693 rowspan.height = cy; | |
694 } else { | |
695 rowHeight = Math.max(rowHeight, cy); | |
696 } | |
697 } | |
698 updateRowSpans(i, rowHeight); | |
699 if (i > 0) | |
700 innerHeight += verticalSpacing; | |
701 innerHeight += rowHeight; | |
702 } | |
104
04b47443bb01
Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections.
Frank Benoit <benoit@tionex.de>
parents:
85
diff
changeset
|
703 if (!rowspans.isEmpty()) |
75 | 704 innerHeight = compensateForRowSpans(innerHeight); |
705 totalHeight = topMargin + innerHeight + bottomMargin; | |
706 return new Point(tableWidth, totalHeight); | |
707 } | |
708 | |
709 private void updateRowSpans(int row, int rowHeight) { | |
710 if (rowspans is null || rowspans.size() is 0) | |
711 return; | |
104
04b47443bb01
Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections.
Frank Benoit <benoit@tionex.de>
parents:
85
diff
changeset
|
712 for (Enumeration enm = rowspans.elements(); enm.hasMoreElements();) { |
04b47443bb01
Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections.
Frank Benoit <benoit@tionex.de>
parents:
85
diff
changeset
|
713 RowSpan rowspan = cast(RowSpan) enm.nextElement(); |
75 | 714 rowspan.update(row, rowHeight); |
715 } | |
716 } | |
717 | |
718 private int compensateForRowSpans(int totalHeight) { | |
104
04b47443bb01
Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections.
Frank Benoit <benoit@tionex.de>
parents:
85
diff
changeset
|
719 for (Enumeration enm = rowspans.elements(); enm.hasMoreElements();) { |
04b47443bb01
Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections.
Frank Benoit <benoit@tionex.de>
parents:
85
diff
changeset
|
720 RowSpan rowspan = cast(RowSpan) enm.nextElement(); |
75 | 721 totalHeight += rowspan.getRequiredHeightIncrease(); |
722 } | |
723 return totalHeight; | |
724 } | |
725 | |
726 int internalGetMinimumWidth(Composite parent, bool changed) { | |
727 if (changed) | |
728 //calculateMinimumColumnWidths(parent, true); | |
729 calculateColumnWidths(parent, minColumnWidths, false, true); | |
730 int minimumWidth = 0; | |
731 widestColumnWidth = 0; | |
732 if (makeColumnsEqualWidth) { | |
733 for (int i = 0; i < numColumns; i++) { | |
734 widestColumnWidth = Math.max(widestColumnWidth, | |
735 minColumnWidths[i]); | |
736 } | |
737 } | |
738 for (int i = 0; i < numColumns; i++) { | |
739 if (i > 0) | |
740 minimumWidth += horizontalSpacing; | |
741 if (makeColumnsEqualWidth) | |
742 minimumWidth += widestColumnWidth; | |
743 else | |
744 minimumWidth += minColumnWidths[i]; | |
745 } | |
746 // add margins | |
747 minimumWidth += leftMargin + rightMargin; | |
748 return minimumWidth; | |
749 } | |
750 | |
751 int internalGetMaximumWidth(Composite parent, bool changed) { | |
752 if (changed) | |
753 //calculateMaximumColumnWidths(parent, true); | |
754 calculateColumnWidths(parent, maxColumnWidths, true, true); | |
755 int maximumWidth = 0; | |
756 for (int i = 0; i < numColumns; i++) { | |
757 if (i > 0) | |
758 maximumWidth += horizontalSpacing; | |
759 maximumWidth += maxColumnWidths[i]; | |
760 } | |
761 // add margins | |
762 maximumWidth += leftMargin + rightMargin; | |
763 return maximumWidth; | |
764 } | |
765 | |
766 void resetColumnWidths() { | |
767 if (minColumnWidths is null) | |
768 minColumnWidths = new int[numColumns]; | |
769 if (maxColumnWidths is null) | |
770 maxColumnWidths = new int[numColumns]; | |
771 for (int i = 0; i < numColumns; i++) { | |
772 minColumnWidths[i] = 0; | |
773 } | |
774 for (int i = 0; i < numColumns; i++) { | |
775 maxColumnWidths[i] = 0; | |
776 } | |
777 } | |
778 | |
779 void calculateColumnWidths(Composite parent, int [] columnWidths, bool max, bool changed) { | |
780 bool secondPassNeeded=false; | |
781 for (int i = 0; i < grid.size(); i++) { | |
104
04b47443bb01
Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections.
Frank Benoit <benoit@tionex.de>
parents:
85
diff
changeset
|
782 TableWrapData[] row = arrayFromObject!(TableWrapData)( grid.elementAt(i)); |
75 | 783 for (int j = 0; j < numColumns; j++) { |
784 TableWrapData td = row[j]; | |
785 if (td.isItemData is false) | |
786 continue; | |
787 | |
788 if (td.colspan>1) { | |
789 // we will not do controls with multiple column span | |
790 // here - increment and continue | |
791 secondPassNeeded=true; | |
792 j+=td.colspan-1; | |
793 continue; | |
794 } | |
795 | |
796 SizeCache childCache = cache.getCache(td.childIndex); | |
797 // !! | |
798 int width = max?childCache.computeMaximumWidth():childCache.computeMinimumWidth(); | |
799 if (td.maxWidth !is DWT.DEFAULT) | |
800 width = Math.min(width, td.maxWidth); | |
801 | |
802 width += td.indent; | |
803 columnWidths[j] = Math.max(columnWidths[j], width); | |
804 } | |
805 } | |
806 if (!secondPassNeeded) return; | |
807 | |
808 // Second pass for controls with multi-column horizontal span | |
809 for (int i = 0; i < grid.size(); i++) { | |
104
04b47443bb01
Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections.
Frank Benoit <benoit@tionex.de>
parents:
85
diff
changeset
|
810 TableWrapData[] row = arrayFromObject!(TableWrapData)( grid.elementAt(i)); |
75 | 811 for (int j = 0; j < numColumns; j++) { |
812 TableWrapData td = row[j]; | |
813 if (td.isItemData is false || td.colspan is 1) | |
814 continue; | |
815 | |
816 SizeCache childCache = cache.getCache(td.childIndex); | |
817 int width = max?childCache.computeMaximumWidth():childCache.computeMinimumWidth(); | |
818 if (td.maxWidth !is DWT.DEFAULT) | |
819 width = Math.min(width, td.maxWidth); | |
820 | |
821 width += td.indent; | |
822 // check if the current width is enough to | |
823 // support the control; if not, add the delta to | |
824 // the last column or to all the growing columns, if present | |
825 int current = 0; | |
826 for (int k = j; k < j + td.colspan; k++) { | |
827 if (k > j) | |
828 current += horizontalSpacing; | |
829 current += columnWidths[k]; | |
830 } | |
831 if (width <= current) { | |
832 // we are ok - nothing to do here | |
833 } else { | |
834 int ndiv = 0; | |
835 if (growingColumns !is null) { | |
836 for (int k = j; k < j + td.colspan; k++) { | |
837 if (isGrowingColumn(k)) { | |
838 ndiv++; | |
839 } | |
840 } | |
841 } | |
842 if (ndiv is 0) { | |
843 // add the delta to the last column | |
844 columnWidths[j + td.colspan - 1] += width | |
845 - current; | |
846 } else { | |
847 // distribute the delta to the growing | |
848 // columns | |
849 int percolumn = (width - current) / ndiv; | |
850 if ((width - current) % ndiv > 0) | |
851 percolumn++; | |
852 for (int k = j; k < j + td.colspan; k++) { | |
853 if (isGrowingColumn(k)) | |
854 columnWidths[k] += percolumn; | |
855 } | |
856 } | |
857 } | |
858 } | |
859 } | |
860 } | |
861 | |
862 bool isWrap(Control control) { | |
863 if (null !is cast(Composite)control | |
864 && null !is cast(ILayoutExtension)((cast(Composite) control).getLayout()) ) | |
865 return true; | |
866 return (control.getStyle() & DWT.WRAP) !is 0; | |
867 } | |
868 | |
869 private void initializeIfNeeded(Composite parent, bool changed) { | |
870 if (changed) | |
871 initialLayout = true; | |
872 if (initialLayout) { | |
873 initializeLayoutData(parent); | |
874 initialLayout = false; | |
875 } | |
876 } | |
877 | |
878 void initializeLayoutData(Composite composite) { | |
879 Control[] children = composite.getChildren(); | |
880 for (int i = 0; i < children.length; i++) { | |
881 Control child = children[i]; | |
882 if (child.getLayoutData() is null) { | |
883 child.setLayoutData(new TableWrapData()); | |
884 } | |
885 } | |
886 } | |
887 } |