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