1 /*******************************************************************************
2 * Copyright (c) 2000, 2004 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.swt.layout;
12
13 import org.eclipse.swt;
14 import org.eclipse.swt.widgets;
15 import org.eclipse.swt.graphics;
16 import java.util.Enumeration;
17 import java.util.Hashtable;
18 import java.util.Vector;
19
20 /**
21 * Instances of this class lay out the control children of a
22 * <code>Composite</code> in a grid.
23 * <p>
24 * <code>GridLayout</code> has a number of configuration fields, and the
25 * controls it lays out can have an associated layout data object, called
26 * <code>GridData</code>. The power of <code>GridLayout</code> lies in the
27 * ability to configure <code>GridData</code> for each control in the layout.
28 * </p>
29 * <p>
30 * The following code creates a shell managed by a <code>GridLayout</code>
31 * with 3 columns:
32 * <pre>
33 * Display display = new Display();
34 * Shell shell = new Shell(display);
35 * GridLayout gridLayout = new GridLayout();
36 * gridLayout.numColumns = 3;
37 * shell.setLayout(gridLayout);
38 * </pre>
39 * The <code>numColumns</code> field is the most important field in a
40 * <code>GridLayout</code>. Widgets are laid out in columns from left
41 * to right, and a new row is created when <code>numColumns</code> + 1
42 * controls are added to the <code>Composite<code>.
43 * </p>
44 *
45 * @see GridData
46 */
47 public final class GridLayout extends Layout {
48 /**
49 * marginWidth specifies the number of pixels of horizontal margin
50 * that will be placed along the left and right edges of the layout.
51 *
52 * The default value is 5.
53 */
54 public int marginWidth = 5;
55 /**
56 * marginHeight specifies the number of pixels of vertical margin
57 * that will be placed along the top and bottom edges of the layout.
58 *
59 * The default value is 5.
60 */
61 public int marginHeight = 5;
62 /**
63 * numColumns specifies the number of cell columns in the layout.
64 *
65 * The default value is 1.
66 */
67 public int numColumns = 1;
68 /**
69 * makeColumnsEqualWidth specifies whether all columns in the layout
70 * will be forced to have the same width.
71 *
72 * The default value is false.
73 */
74 public boolean makeColumnsEqualWidth = false;
75 /**
76 * horizontalSpacing specifies the number of pixels between the right
77 * edge of one cell and the left edge of its neighbouring cell to
78 * the right.
79 *
80 * The default value is 5.
81 */
82 public int horizontalSpacing = 5;
83 /**
84 * verticalSpacing specifies the number of pixels between the bottom
85 * edge of one cell and the top edge of its neighbouring cell underneath.
86 *
87 * The default value is 5.
88 */
89 public int verticalSpacing = 5;
90
91 // Private variables. Cached values used to cut down on grid calculations.
92 Vector grid = new Vector();
93 int [] pixelColumnWidths;
94 int [] pixelRowHeights;
95 int [] expandableColumns;
96 int [] expandableRows;
97
98 /**
99 * Constructs a new instance of this class.
100 */
101 public GridLayout() {
102 }
103
104 /**
105 * Constructs a new instance of this class given the
106 * number of columns, and whether or not the columns
107 * should be forced to have the same width.
108 *
109 * @param numColumns the number of columns in the grid
110 * @param makeColumnsEqualWidth whether or not the columns will have equal width
111 *
112 * @since 2.0
113 */
114 public GridLayout(int numColumns, boolean makeColumnsEqualWidth) {
115 this.numColumns = numColumns;
116 this.makeColumnsEqualWidth = makeColumnsEqualWidth;
117 }
118
119 void adjustGridDimensions(Composite composite, boolean flushCache) {
120 // Ensure that controls that span more than one row or column have enough space.
121 for (int row = 0; row < grid.size(); row++) {
122 for (int column = 0; column < numColumns; column++) {
123 GridData spec = ((GridData[]) grid.elementAt(row))[column];
124 if (spec.isItemData()) {
125 // Widgets spanning columns.
126 if (spec.hSpan > 1) {
127 Control child = composite.getChildren()[spec.childIndex];
128 Point extent = child.computeSize(spec.widthHint, spec.heightHint, flushCache);
129
130 // Calculate the size of the control's spanned columns.
131 int lastSpanIndex = column + spec.hSpan;
132 int spannedSize = 0;
133 for (int c = column; c < lastSpanIndex; c++) {
134 spannedSize = spannedSize + pixelColumnWidths[c] + horizontalSpacing;
135 }
136 spannedSize = spannedSize - horizontalSpacing;
137
138 // If the spanned columns are not large enough to display the control, adjust the column
139 // sizes to account for the extra space that is needed.
140 if (extent.x + spec.horizontalIndent > spannedSize) {
141 int extraSpaceNeeded = extent.x + spec.horizontalIndent - spannedSize;
142 int lastColumn = column + spec.hSpan - 1;
143 int colWidth;
144 if (makeColumnsEqualWidth) {
145 // Evenly distribute the extra space amongst all of the columns.
146 int columnExtra = extraSpaceNeeded / numColumns;
147 int columnRemainder = extraSpaceNeeded % numColumns;
148 for (int i = 0; i < pixelColumnWidths.length; i++) {
149 colWidth = pixelColumnWidths[i] + columnExtra;
150 pixelColumnWidths[i] = colWidth;
151 }
152 colWidth = pixelColumnWidths[lastColumn] + columnRemainder;
153 pixelColumnWidths[lastColumn] = colWidth;
154 } else {
155 Vector localExpandableColumns = new Vector();
156 for (int i = column; i <= lastColumn; i++) {
157 for (int j = 0; j < expandableColumns.length; j++) {
158 if (expandableColumns[j] == i) {
159 localExpandableColumns.addElement(new Integer(i));
160 }
161 }
162 }
163 if (localExpandableColumns.size() > 0) {
164 // If any of the control's columns grab excess space, allocate the space amongst those columns.
165 int columnExtra = extraSpaceNeeded / localExpandableColumns.size();
166 int columnRemainder = extraSpaceNeeded % localExpandableColumns.size();
167 for (int i = 0; i < localExpandableColumns.size(); i++) {
168 int expandableCol = ((Integer) localExpandableColumns.elementAt(i)).intValue();
169 colWidth = pixelColumnWidths[expandableCol] + columnExtra;
170 pixelColumnWidths[expandableCol] = colWidth;
171 }
172 colWidth = pixelColumnWidths[lastColumn] + columnRemainder;
173 pixelColumnWidths[lastColumn] = colWidth;
174 } else {
175 // Add the extra space to the control's last column if none of its columns grab excess space.
176 colWidth = pixelColumnWidths[lastColumn] + extraSpaceNeeded;
177 pixelColumnWidths[lastColumn] = colWidth;
178 }
179 }
180 }
181 }
182
183 // Widgets spanning rows.
184 if (spec.verticalSpan > 1) {
185 Control child = composite.getChildren()[spec.childIndex];
186 Point extent = child.computeSize(spec.widthHint, spec.heightHint, flushCache);
187
188 // Calculate the size of the control's spanned rows.
189 int lastSpanIndex = row + spec.verticalSpan;
190 int spannedSize = 0;
191 for (int r = row; r < lastSpanIndex; r++) {
192 spannedSize = spannedSize + pixelRowHeights[r] + verticalSpacing;
193 }
194 spannedSize = spannedSize - verticalSpacing;
195 // If the spanned rows are not large enough to display the control, adjust the row
196 // sizes to account for the extra space that is needed.
197 if (extent.y > spannedSize) {
198 int extraSpaceNeeded = extent.y - spannedSize;
199 int lastRow = row + spec.verticalSpan - 1;
200 int rowHeight;
201 Vector localExpandableRows = new Vector();
202 for (int i = row; i <= lastRow; i++) {
203 for (int j = 0; j < expandableRows.length; j++) {
204 if (expandableRows[j] == i) {
205 localExpandableRows.addElement(new Integer(i));
206 }
207 }
208 }
209 if (localExpandableRows.size() > 0) {
210 // If any of the control's rows grab excess space, allocate the space amongst those rows.
211 int rowExtra = extraSpaceNeeded / localExpandableRows.size();
212 int rowRemainder = extraSpaceNeeded % localExpandableRows.size();
213 for (int i = 0; i < localExpandableRows.size(); i++) {
214 int expandableRow = ((Integer) localExpandableRows.elementAt(i)).intValue();
215 rowHeight = pixelRowHeights[expandableRow] + rowExtra;
216 pixelRowHeights[expandableRow] = rowHeight;
217 }
218 rowHeight = pixelRowHeights[lastRow] + rowRemainder;
219 pixelRowHeights[lastRow] = rowHeight;
220 } else {
221 // Add the extra space to the control's last row if no rows grab excess space.
222 rowHeight = pixelRowHeights[lastRow] + extraSpaceNeeded;
223 pixelRowHeights[lastRow] = rowHeight;
224 }
225 }
226 }
227 }
228 }
229 }
230 }
231 void calculateGridDimensions(Composite composite, boolean flushCache) {
232 int maxWidth, childWidth, maxHeight, childHeight;
233
234 //
235 Control[] children = composite.getChildren();
236 Point[] childSizes = new Point[children.length];
237 pixelColumnWidths = new int[numColumns];
238 pixelRowHeights = new int[grid.size()];
239
240 // Loop through the grid by column to get the width that each column needs to be.
241 // Each column will be as wide as its widest control.
242 for (int column = 0; column < numColumns; column++) {
243 maxWidth = 0;
244 for (int row = 0; row < grid.size(); row++) {
245 GridData spec = ((GridData[]) grid.elementAt(row))[column];
246 if (spec.isItemData()) {
247 Control child = children[spec.childIndex];
248 childSizes[spec.childIndex] = child.computeSize(spec.widthHint, spec.heightHint, flushCache);
249 childWidth = childSizes[spec.childIndex].x + spec.horizontalIndent;
250 if (spec.hSpan == 1) {
251 maxWidth = Math.max(maxWidth, childWidth);
252 }
253 }
254 }
255 // Cache the values for later use.
256 pixelColumnWidths[column] = maxWidth;
257 }
258
259 //
260 if (makeColumnsEqualWidth) {
261 maxWidth = 0;
262 // Find the largest column size that is necessary and make each column that size.
263 for (int i = 0; i < numColumns; i++) {
264 maxWidth = Math.max(maxWidth, pixelColumnWidths[i]);
265 }
266 maxWidth += horizontalSpacing;
267 for (int i = 0; i < numColumns; i++) {
268 pixelColumnWidths[i] = maxWidth;
269 }
270 }
271
272 // Loop through the grid by row to get the height that each row needs to be.
273 // Each row will be as high as its tallest control.
274 for (int row = 0; row < grid.size(); row++) {
275 maxHeight = 0;
276 for (int column = 0; column < numColumns; column++) {
277 GridData spec = ((GridData[]) grid.elementAt(row))[column];
278 if (spec.isItemData()) {
279 childHeight = childSizes[spec.childIndex].y;
280 if (spec.verticalSpan == 1) {
281 maxHeight = Math.max(maxHeight, childHeight);
282 }
283 }
284 }
285 // Cache the values for later use.
286 pixelRowHeights[row] = maxHeight;
287 }
288 }
289 void computeExpandableCells() {
290 // If a control grabs excess horizontal space, the last column that the control spans
291 // will be expandable. Similarly, if a control grabs excess vertical space, the
292 // last row that the control spans will be expandable.
293 Hashtable growColumns = new Hashtable();
294 Hashtable growRows = new Hashtable();
295 for (int col = 0; col < numColumns; col++) {
296 for (int row = 0; row < grid.size(); row++) {
297 GridData spec = ((GridData[]) grid.elementAt(row))[col];
298 if (spec.grabExcessHorizontalSpace) {
299 growColumns.put(new Integer(col + spec.hSpan - 1), new Object());
300 }
301 if (spec.grabExcessVerticalSpace) {
302 growRows.put(new Integer(row + spec.verticalSpan - 1), new Object());
303 }
304 }
305 }
306
307 // Cache the values. These values are used later during children layout.
308 int i = 0;
309 Enumeration enum = growColumns.keys();
310 expandableColumns = new int[growColumns.size()];
311 while (enum.hasMoreElements()) {
312 expandableColumns[i] = ((Integer)enum.nextElement()).intValue();
313 i = i + 1;
314 }
315 i = 0;
316 enum = growRows.keys();
317 expandableRows = new int[growRows.size()];
318 while (enum.hasMoreElements()) {
319 expandableRows[i] = ((Integer)enum.nextElement()).intValue();
320 i = i + 1;
321 }
322 }
323 Point computeLayoutSize(Composite composite, int wHint, int hHint, boolean flushCache) {
324 int totalMarginHeight, totalMarginWidth;
325 int totalWidth, totalHeight;
326 int cols, rows;
327
328 // Initialize the grid and other cached information that help with the grid layout.
329 if (grid.size() == 0) {
330 createGrid(composite);
331 calculateGridDimensions(composite, flushCache);
332 computeExpandableCells();
333 adjustGridDimensions(composite, flushCache);
334 }
335
336 //
337 cols = numColumns;
338 rows = grid.size();
339 totalMarginHeight = marginHeight;
340 totalMarginWidth = marginWidth;
341
342 // The total width is the margin plus border width plus space between each column,
343 // plus the width of each column.
344 totalWidth = (totalMarginWidth * 2) + ((cols - 1) * horizontalSpacing);
345
346 //Add up the width of each column.
347 for (int i = 0; i < pixelColumnWidths.length; i++) {
348 totalWidth = totalWidth + pixelColumnWidths[i];
349 }
350
351 // The total height is the margin plus border height, plus space between each row,
352 // plus the height of the tallest child in each row.
353 totalHeight = (totalMarginHeight * 2) + ((rows - 1) * verticalSpacing);
354
355 //Add up the height of each row.
356 for (int i = 0; i < pixelRowHeights.length; i++) {
357 totalHeight = totalHeight + pixelRowHeights[i];
358 }
359
360 if (wHint != SWT.DEFAULT) totalWidth = wHint;
361 if (hHint != SWT.DEFAULT) totalHeight = hHint;
362 // The preferred extent is the width and height that will accomodate the grid's controls.
363 return new Point(totalWidth, totalHeight);
364 }
365 protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) {
366 Control[] children = composite.getChildren();
367 int numChildren = children.length;
368
369 if (numChildren == 0) return new Point(0,0);
370
371 if (flushCache) {
372 // Cause the grid and its related information to be calculated
373 // again.
374 grid.removeAllElements();
375 }
376 return computeLayoutSize(composite, wHint, hHint, flushCache);
377 }
378 Point getFirstEmptyCell(int row, int column) {
379 GridData[] rowData = (GridData[]) grid.elementAt(row);
380 while (column < numColumns && rowData[column] != null) {
381 column++;
382 }
383 if (column == numColumns) {
384 row++;
385 column = 0;
386 if (row == grid.size()) {
387 grid.addElement(emptyRow());
388 }
389 return getFirstEmptyCell(row, column);
390 }
391 return new Point(row, column);
392 }
393 Point getLastEmptyCell(int row, int column) {
394 GridData[] rowData = (GridData[])grid.elementAt(row);
395 while (column < numColumns && rowData[column] == null ) {
396 column++;
397 }
398 return new Point(row, column - 1);
399 }
400 Point getCell(int row, int column, int width, int height) {
401 Point start = getFirstEmptyCell(row, column);
402 Point end = getLastEmptyCell(start.x, start.y);
403 if (end.y + 1 - start.y >= width) return start;
404 GridData[] rowData = (GridData[]) grid.elementAt(start.x);
405 for (int j = start.y; j < end.y + 1; j++) {
406 GridData spacerSpec = new GridData();
407 spacerSpec.isItemData = false;
408 rowData[j] = spacerSpec;
409 }
410 return getCell(end.x, end.y, width, height);
411 }
412 void createGrid(Composite composite) {
413 int row, column, rowFill, columnFill;
414 Control[] children;
415 GridData spacerSpec;
416
417 //
418 children = composite.getChildren();
419
420 //
421 grid.addElement(emptyRow());
422 row = 0;
423 column = 0;
424
425 // Loop through the children and place their associated layout specs in the
426 // grid. Placement occurs left to right, top to bottom (i.e., by row).
427 for (int i = 0; i < children.length; i++) {
428 // Find the first available spot in the grid.
429 Control child = children[i];
430 GridData spec = (GridData) child.getLayoutData();
431 if (spec == null) {
432 spec = new GridData();
433 child.setLayoutData(spec);
434 }
435 spec.hSpan = Math.min(spec.horizontalSpan, numColumns);
436 Point p = getCell(row, column, spec.hSpan, spec.verticalSpan);
437 row = p.x; column = p.y;
438
439 // The vertical span for the item will be at least 1. If it is > 1,
440 // add other rows to the grid.
441 for (int j = 2; j <= spec.verticalSpan; j++) {
442 if (row + j > grid.size()) {
443 grid.addElement(emptyRow());
444 }
445 }
446
447 // Store the layout spec. Also cache the childIndex. NOTE: That we assume the children of a
448 // composite are maintained in the order in which they are created and added to the composite.
449 ((GridData[]) grid.elementAt(row))[column] = spec;
450 spec.childIndex = i;
451
452 // Put spacers in the grid to account for the item's vertical and horizontal
453 // span.
454 rowFill = spec.verticalSpan - 1;
455 columnFill = spec.hSpan - 1;
456 for (int r = 1; r <= rowFill; r++) {
457 for (int c = 0; c < spec.hSpan; c++) {
458 spacerSpec = new GridData();
459 spacerSpec.isItemData = false;
460 ((GridData[]) grid.elementAt(row + r))[column + c] = spacerSpec;
461 }
462 }
463 for (int c = 1; c <= columnFill; c++) {
464 for (int r = 0; r < spec.verticalSpan; r++) {
465 spacerSpec = new GridData();
466 spacerSpec.isItemData = false;
467 ((GridData[]) grid.elementAt(row + r))[column + c] = spacerSpec;
468 }
469 }
470 column = column + spec.hSpan - 1;
471 }
472
473 // Fill out empty grid cells with spacers.
474 for (int r = row; r < grid.size(); r++) {
475 GridData[] rowData = (GridData[]) grid.elementAt(r);
476 for (int c = 0; c < numColumns; c++) {
477 if (rowData[c] == null) {
478 spacerSpec = new GridData();
479 spacerSpec.isItemData = false;
480 rowData[c] = spacerSpec;
481 }
482 }
483 }
484 }
485 GridData[] emptyRow() {
486 GridData[] row = new GridData[numColumns];
487 for (int i = 0; i < numColumns; i++) {
488 row[i] = null;}
489 return row;
490 }
491 protected void layout(Composite composite, boolean flushCache) {
492 int[] columnWidths;
493 int[] rowHeights;
494 int rowSize, rowY, columnX;
495 int compositeWidth, compositeHeight;
496 int excessHorizontal, excessVertical;
497 Control[] children;
498 if (flushCache) {
499 // Cause the grid and its related information to be calculated
500 // again.
501 grid.removeAllElements();
502 }
503 children = composite.getChildren();
504 if (children.length == 0)
505 return;
506
507 //
508 Point extent = computeSize(composite, SWT.DEFAULT, SWT.DEFAULT, flushCache);
509 columnWidths = new int[numColumns];
510 for (int i = 0; i < pixelColumnWidths.length; i++) {
511 columnWidths[i] = pixelColumnWidths[i];
512 }
513 rowHeights = new int[grid.size()];
514 for (int i = 0; i < pixelRowHeights.length; i++) {
515 rowHeights[i] = pixelRowHeights[i];
516 }
517 int columnWidth = 0;
518 rowSize = Math.max(1, grid.size());
519
520 //
521 compositeWidth = extent.x;
522 compositeHeight = extent.y;
523
524 // Calculate whether or not there is any extra space or not enough space due to a resize
525 // operation. Then allocate/deallocate the space to columns and rows that are expandable.
526 // If a control grabs excess space, its last column or row will be expandable.
527 excessHorizontal = composite.getClientArea().width - compositeWidth;
528 excessVertical = composite.getClientArea().height - compositeHeight;
529
530 // Allocate/deallocate horizontal space.
531 if (expandableColumns.length != 0) {
532 int excess, remainder, last;
533 int colWidth;
534 excess = excessHorizontal / expandableColumns.length;
535 remainder = excessHorizontal % expandableColumns.length;
536 last = 0;
537 for (int i = 0; i < expandableColumns.length; i++) {
538 int expandableCol = expandableColumns[i];
539 colWidth = columnWidths[expandableCol];
540 colWidth = colWidth + excess;
541 columnWidths[expandableCol] = colWidth;
542 last = Math.max(last, expandableCol);
543 }
544 colWidth = columnWidths[last];
545 colWidth = colWidth + remainder;
546 columnWidths[last] = colWidth;
547 }
548
549 // Go through all specs in each expandable column and get the maximum specified
550 // widthHint. Use this as the minimumWidth for the column.
551 for (int i = 0; i < expandableColumns.length; i++) {
552 int expandableCol = expandableColumns[i];
553 int colWidth = columnWidths[expandableCol];
554 int minWidth = 0;
555 for (int j = 0; j < grid.size(); j++) {
556 GridData[] row = (GridData[]) grid.elementAt(j);
557 GridData spec = row[expandableCol];
558 if (spec.hSpan == 1) {
559 minWidth = Math.max(minWidth, spec.widthHint);
560 }
561 }
562 columnWidths[expandableCol] = Math.max(colWidth, minWidth);
563 }
564 // Allocate/deallocate vertical space.
565 if (expandableRows.length != 0) {
566 int excess, remainder, last;
567 int rowHeight;
568 excess = excessVertical / expandableRows.length;
569 remainder = excessVertical % expandableRows.length;
570 last = 0;
571 for (int i = 0; i < expandableRows.length; i++) {
572 int expandableRow = expandableRows[i];
573 rowHeight = rowHeights[expandableRow];
574 rowHeight = rowHeight + excess;
575 rowHeights[expandableRow] = rowHeight;
576 last = Math.max(last, expandableRow);
577 }
578 rowHeight = rowHeights[last];
579 rowHeight = rowHeight + remainder;
580 rowHeights[last] = rowHeight;
581 }
582 // Go through all specs in each expandable row and get the maximum specified
583 // heightHint. Use this as the minimumHeight for the row.
584 for (int i = 0; i < expandableRows.length; i++) {
585 int expandableRow = expandableRows[i];
586 int rowHeight = rowHeights[expandableRow];
587 int minHeight = 0;
588 GridData[] row = (GridData[]) grid.elementAt(expandableRow);
589 for (int j = 0; j < numColumns; j++) {
590 GridData spec = row[j];
591 if (spec.verticalSpan == 1) {
592 minHeight = Math.max(minHeight, spec.heightHint);
593 }
594 }
595 rowHeights[expandableRow] = Math.max(rowHeight, minHeight);
596 }
597
598 // Get the starting x and y.
599 columnX = marginWidth + composite.getClientArea().x;
600 rowY = marginHeight + composite.getClientArea().y;
601
602 // Layout the control left to right, top to bottom.
603 for (int r = 0; r < rowSize; r++) {
604 int rowHeight = rowHeights[r];
605 GridData[] row = (GridData[]) grid.elementAt(r);
606
607 //
608 for (int c = 0; c < row.length; c++) {
609 int spannedWidth = 0, spannedHeight = 0;
610 int hAlign = 0, vAlign = 0;
611 int widgetX = 0, widgetY = 0;
612 int widgetW = 0, widgetH = 0;
613
614 //
615 GridData spec = (GridData) row[c];
616 if (makeColumnsEqualWidth) {
617 columnWidth = composite.getClientArea().width - 2 * (marginWidth) - ((numColumns - 1) * horizontalSpacing);
618 columnWidth = columnWidth / numColumns;
619 for (int i = 0; i < columnWidths.length; i++) {
620 columnWidths[i] = columnWidth;
621 }
622 } else {
623 columnWidth = columnWidths[c];
624 }
625
626 //
627 spannedWidth = columnWidth;
628 for (int k = 1; k < spec.hSpan; k++) {
629 if ((c + k) <= numColumns) {
630 if (!makeColumnsEqualWidth) {
631 columnWidth = columnWidths[c + k];
632 }
633 spannedWidth = spannedWidth + columnWidth + horizontalSpacing;
634 }
635 }
636
637 //
638 spannedHeight = rowHeight;
639 for (int k = 1; k < spec.verticalSpan; k++) {
640 if ((r + k) <= grid.size()) {
641 spannedHeight = spannedHeight + rowHeights[r + k] + verticalSpacing;
642 }
643 }
644
645 //
646 if (spec.isItemData()) {
647 Control child = children[spec.childIndex];
648 Point childExtent = child.computeSize(spec.widthHint, spec.heightHint, flushCache);
649 hAlign = spec.horizontalAlignment;
650 widgetX = columnX;
651
652 // Calculate the x and width values for the control.
653 if (hAlign == GridData.CENTER || hAlign == SWT.CENTER) {
654 widgetX = widgetX + (spannedWidth / 2) - (childExtent.x / 2);
655 } else
656 if (hAlign == GridData.END || hAlign == SWT.END || hAlign == SWT.RIGHT) {
657 widgetX = widgetX + spannedWidth - childExtent.x - spec.horizontalIndent;
658 } else {
659 widgetX = widgetX + spec.horizontalIndent;
660 }
661 if (hAlign == GridData.FILL) {
662 widgetW = spannedWidth - spec.horizontalIndent;
663 widgetX = columnX + spec.horizontalIndent;
664 } else {
665 widgetW = childExtent.x;
666 }
667
668 // Calculate the y and height values for the control.
669 vAlign = spec.verticalAlignment;
670 widgetY = rowY;
671 if (vAlign == GridData.CENTER || vAlign == SWT.CENTER) {
672 widgetY = widgetY + (spannedHeight / 2) - (childExtent.y / 2);
673 } else
674 if (vAlign == GridData.END || vAlign == SWT.END || vAlign == SWT.BOTTOM) {
675 widgetY = widgetY + spannedHeight - childExtent.y;
676 }
677 if (vAlign == GridData.FILL) {
678 widgetH = spannedHeight;
679 widgetY = rowY;
680 } else {
681 widgetH = childExtent.y;
682 }
683 // Place the control.
684 child.setBounds(widgetX, widgetY, widgetW, widgetH);
685 }
686 // Update the starting x value.
687 columnX = columnX + columnWidths[c] + horizontalSpacing;
688 }
689 // Update the starting y value and since we're starting a new row, reset the starting x value.
690 rowY = rowY + rowHeights[r] + verticalSpacing;
691 columnX = marginWidth + composite.getClientArea().x;
692 }
693 }
694 }