1 11 12 package org.eclipse.ui.internal.layout; 13 14 import java.util.ArrayList ; 15 import java.util.List ; 16 17 import org.eclipse.swt.SWT; 18 import org.eclipse.swt.graphics.Point; 19 import org.eclipse.swt.graphics.Rectangle; 20 import org.eclipse.swt.widgets.Composite; 21 import org.eclipse.swt.widgets.Control; 22 import org.eclipse.swt.widgets.Layout; 23 24 68 public class CellLayout extends Layout { 69 70 74 private Row defaultRowSettings = new Row(false); 75 76 80 private Row defaultColSettings = new Row(true); 81 82 89 int horizontalSpacing = 5; 90 91 97 int verticalSpacing = 5; 98 99 105 public int marginWidth = 5; 106 107 113 public int marginHeight = 5; 114 115 119 private int numCols; 120 121 125 private List cols; 126 127 131 private List rows = new ArrayList (16); 132 133 private GridInfo gridInfo = new GridInfo(); 135 136 private int[] cachedRowMin = null; 137 138 private int[] cachedColMin = null; 139 140 public static int cacheMisses; 141 142 public static int cacheHits; 143 144 private LayoutCache cache = new LayoutCache(); 145 146 148 154 public CellLayout(int numCols) { 155 super(); 156 this.numCols = numCols; 157 cols = new ArrayList (numCols == 0 ? 3 : numCols); 158 } 159 160 166 public CellLayout setSpacing(int horizontalSpacing, int verticalSpacing) { 167 this.horizontalSpacing = horizontalSpacing; 168 this.verticalSpacing = verticalSpacing; 169 170 return this; 171 } 172 173 179 public CellLayout setSpacing(Point newSpacing) { 180 horizontalSpacing = newSpacing.x; 181 verticalSpacing = newSpacing.y; 182 return this; 183 } 184 185 191 public Point getSpacing() { 192 return new Point(horizontalSpacing, verticalSpacing); 193 } 194 195 203 public CellLayout setMargins(int marginWidth, int marginHeight) { 204 this.marginWidth = marginWidth; 205 this.marginHeight = marginHeight; 206 return this; 207 } 208 209 215 public CellLayout setMargins(Point newMargins) { 216 marginWidth = newMargins.x; 217 marginHeight = newMargins.y; 218 return this; 219 } 220 221 226 public Point getMargins() { 227 return new Point(marginWidth, marginHeight); 228 } 229 230 237 public CellLayout setDefaultColumn(Row info) { 238 defaultColSettings = info; 239 return this; 240 } 241 242 251 public CellLayout setColumn(int colNum, Row info) { 252 while (cols.size() <= colNum) { 253 cols.add(null); 254 } 255 256 cols.set(colNum, info); 257 258 return this; 259 } 260 261 268 public CellLayout setDefaultRow(Row info) { 269 defaultRowSettings = info; 270 271 return this; 272 } 273 274 282 public CellLayout setRow(int rowNum, Row info) { 283 while (rows.size() <= rowNum) { 284 rows.add(null); 285 } 286 287 rows.set(rowNum, info); 288 289 return this; 290 } 291 292 300 private Row getRow(int rowNum, boolean isHorizontal) { 301 if (isHorizontal) { 302 if (rowNum >= rows.size()) { 303 return defaultRowSettings; 304 } 305 306 Row result = (Row) rows.get(rowNum); 307 308 if (result == null) { 309 result = defaultRowSettings; 310 } 311 312 return result; 313 } else { 314 if (rowNum >= cols.size()) { 315 return defaultColSettings; 316 } 317 318 Row result = (Row) cols.get(rowNum); 319 320 if (result == null) { 321 result = defaultColSettings; 322 } 323 324 return result; 325 } 326 } 327 328 333 private void initGrid(Control[] children) { 334 cache.setControls(children); 335 gridInfo.initGrid(children, this); 336 cachedRowMin = null; 337 cachedColMin = null; 338 } 339 340 343 protected Point computeSize(Composite composite, int wHint, int hHint, 344 boolean flushCache) { 345 Control[] children = composite.getChildren(); 346 initGrid(children); 347 348 if (flushCache) { 349 cache.flush(); 350 } 351 352 Point emptySpace = totalEmptySpace(); 354 355 int[] heightConstraints = computeConstraints(true); 356 357 int width; 358 if (wHint == SWT.DEFAULT) { 359 width = preferredSize(heightConstraints, false); 360 } else { 361 width = wHint - emptySpace.x; 362 } 363 364 int height = hHint; 365 if (hHint == SWT.DEFAULT) { 366 height = preferredSize( 367 computeSizes(heightConstraints, width, false), true); 368 } else { 369 height = hHint - emptySpace.y; 370 } 371 372 Point preferredSize = new Point(width + emptySpace.x, height 373 + emptySpace.y); 374 375 378 Point minimumSize = CellLayoutUtil.computeMinimumSize(composite); 387 388 boolean wider = (preferredSize.x >= minimumSize.x); 389 boolean taller = (preferredSize.y >= minimumSize.y); 390 391 if (wider) { 392 if (taller) { 393 return preferredSize; 396 } else { 397 return computeSize(composite, wHint, minimumSize.y, false); 400 } 401 } else { 402 if (taller) { 403 return computeSize(composite, minimumSize.x, hHint, false); 406 } else { 407 return minimumSize; 410 } 411 } 412 } 413 414 int[] computeSizes(int[] constraints, int availableSpace, 415 boolean computingRows) { 416 int[] result = computeMinSizes(constraints, computingRows); 417 418 int totalFixed = sumOfSizes(result); 419 int denominator = getResizeDenominator(computingRows); 420 int numRows = gridInfo.getNumRows(computingRows); 421 422 if (totalFixed < availableSpace) { 423 int remaining = availableSpace - totalFixed; 424 425 for (int idx = 0; idx < numRows && denominator > 0; idx++) { 426 Row row = getRow(idx, computingRows); 427 428 if (row.grows) { 429 int greed = row.size; 430 int amount = remaining * greed / denominator; 431 432 result[idx] += amount; 433 remaining -= amount; 434 denominator -= greed; 435 } 436 } 437 } 438 439 return result; 440 } 441 442 451 int preferredSize(int[] constraints, boolean computingRows) { 452 int[] fixedSizes = computeMinSizes(constraints, computingRows); 453 454 return sumOfSizes(fixedSizes) 455 + getDynamicSize(constraints, fixedSizes, computingRows); 456 } 457 458 462 static int sumOfSizes(int[] input) { 463 return sumOfSizes(input, 0, input.length); 464 } 465 466 static int sumOfSizes(int[] input, int start, int length) { 467 int sum = 0; 468 for (int idx = start; idx < start + length; idx++) { 469 int next = input[idx]; 470 471 if (next == SWT.DEFAULT) { 472 return SWT.DEFAULT; 473 } 474 475 sum += next; 476 } 477 478 return sum; 479 } 480 481 489 int getDynamicSize(int[] constraints, int[] fixedSizes, 490 boolean computingRows) { 491 int result = 0; 492 int numerator = getResizeDenominator(computingRows); 493 494 if (numerator == 0) { 496 return 0; 497 } 498 499 int rowSpacing = computingRows ? verticalSpacing : horizontalSpacing; 500 int colSpacing = computingRows ? horizontalSpacing : verticalSpacing; 501 502 int numControls = gridInfo.controls.length; 503 for (int idx = 0; idx < numControls; idx++) { 504 int controlRowStart = gridInfo.getStartPos(idx, computingRows); 505 int controlRowSpan = getSpan(idx, computingRows); 506 int controlColStart = gridInfo.getStartPos(idx, !computingRows); 507 int controlColSpan = getSpan(idx, !computingRows); 508 509 int denominator = getGrowthRatio(controlRowStart, controlRowSpan, 510 computingRows); 511 512 if (denominator > 0) { 513 514 int widthHint = sumOfSizes(constraints, controlColStart, 515 controlColSpan); 516 if (widthHint != SWT.DEFAULT) { 517 widthHint += colSpacing * (controlColSpan - 1); 518 } 519 520 int controlSize = computeControlSize(idx, widthHint, 522 computingRows); 523 524 controlSize -= sumOfSizes(fixedSizes, controlRowStart, 526 controlRowSpan); 527 528 controlSize -= (rowSpacing * (controlRowSpan - 1)); 530 531 result = Math 532 .max(result, controlSize * numerator / denominator); 533 } 534 } 535 536 return result; 537 } 538 539 547 int computeControlSize(int control, int constraint, boolean computingHeight) { 548 CellData data = gridInfo.getCellData(control); 549 550 if (constraint == SWT.DEFAULT) { 552 Point result = data.computeSize(cache.getCache(control), 553 SWT.DEFAULT, SWT.DEFAULT); 554 555 if (computingHeight) { 557 return result.y; 558 } 559 return result.x; 560 } 561 562 if (computingHeight) { 564 return data.computeSize(cache.getCache(control), constraint, 565 SWT.DEFAULT).y; 566 } 567 568 return data.computeSize(cache.getCache(control), SWT.DEFAULT, 569 constraint).x; 570 } 571 572 581 int getGrowthRatio(int start, int length, boolean computingRows) { 582 boolean willGrow = false; 583 int sum = 0; 584 585 int end = start + length; 586 for (int idx = start; idx < end; idx++) { 587 Row row = getRow(idx, computingRows); 588 589 if (row.largerThanChildren && row.grows) { 590 willGrow = true; 591 } 592 593 sum += row.size; 594 } 595 596 if (!willGrow) { 597 return 0; 598 } 599 600 return sum; 601 } 602 603 int[] computeMinSizes(int[] constraints, boolean computingRows) { 604 int[] result = computingRows ? cachedRowMin : cachedColMin; 607 608 if (result == null) { 609 int columnSpacing; 610 int rowSpacing; 611 612 if (computingRows) { 613 columnSpacing = horizontalSpacing; 614 rowSpacing = verticalSpacing; 615 } else { 616 columnSpacing = verticalSpacing; 617 rowSpacing = horizontalSpacing; 618 } 619 620 int rowCount = gridInfo.getNumRows(computingRows); 621 result = new int[rowCount]; 622 int colCount = gridInfo.getNumRows(!computingRows); 623 int[] rowControls = new int[colCount]; 624 625 int lastGrowingRow = -1; 626 627 for (int idx = 0; idx < rowCount; idx++) { 628 Row row = getRow(idx, computingRows); 629 630 if (row.grows) { 631 lastGrowingRow = idx; 633 result[idx] = 0; 634 } else { 635 result[idx] = row.size; 636 637 if (row.largerThanChildren) { 638 gridInfo.getRow(rowControls, idx, computingRows); 640 641 for (int colIdx = 0; colIdx < rowControls.length; colIdx++) { 642 int control = rowControls[colIdx]; 643 644 if (control != -1) { 646 int controlStart = gridInfo.getStartPos( 647 control, computingRows); 648 int controlSpan = getSpan(control, 649 computingRows); 650 651 if (controlStart + controlSpan - 1 == idx 653 && controlStart > lastGrowingRow) { 654 int controlColStart = gridInfo.getStartPos( 655 control, !computingRows); 656 int controlColSpan = getSpan(control, 657 !computingRows); 658 int controlRowSpan = getSpan(control, 659 computingRows); 660 661 int spannedWidth = sumOfSizes(constraints, 663 controlColStart, controlColSpan); 664 if (spannedWidth != SWT.DEFAULT) { 665 spannedWidth += (columnSpacing * (controlSpan - 1)); 666 } 667 668 int controlHeight = computeControlSize( 669 control, spannedWidth, 670 computingRows); 671 672 int allocatedHeight = sumOfSizes(result, 674 controlColStart, controlRowSpan - 1) 675 + (rowSpacing * (controlRowSpan - 1)); 676 677 result[idx] = Math.max(result[idx], 678 controlHeight - allocatedHeight); 679 } 680 } 681 } 682 } 683 } 684 } 685 } 686 687 if (computingRows) { 689 cachedRowMin = result; 690 } else { 691 cachedColMin = result; 692 } 693 694 return result; 695 } 696 697 704 private int[] computeConstraints(boolean horizontal) { 705 int numRows = gridInfo.getNumRows(horizontal); 708 int[] result = new int[numRows]; 709 710 for (int idx = 0; idx < numRows; idx++) { 711 Row row = getRow(idx, horizontal); 712 713 if (!(row.grows || row.largerThanChildren)) { 714 result[idx] = row.size; 715 } else { 716 result[idx] = SWT.DEFAULT; 717 } 718 } 719 720 return result; 721 } 722 723 728 private int getResizeDenominator(boolean horizontal) { 729 int result = 0; 730 int numRows = gridInfo.getNumRows(horizontal); 731 732 for (int idx = 0; idx < numRows; idx++) { 733 Row row = getRow(idx, horizontal); 734 735 if (row.grows) { 736 result += row.size; 737 } 738 } 739 740 return result; 741 } 742 743 763 protected int getSpan(int controlId, boolean isRow) { 764 CellData data = gridInfo.getCellData(controlId); 765 766 if (isRow) { 767 return data.verticalSpan; 768 } 769 return data.horizontalSpan; 770 } 771 772 778 private Point totalEmptySpace() { 779 int numRows = gridInfo.getRows(); 780 781 return new Point((2 * marginWidth) 782 + ((gridInfo.getCols() - 1) * horizontalSpacing), 783 (2 * marginHeight) + ((numRows - 1) * verticalSpacing)); 784 } 785 786 796 private static int[] computeRowPositions(int startPos, int[] sizes, 797 int spacing) { 798 int[] result = new int[sizes.length + 1]; 799 800 result[0] = startPos; 801 for (int idx = 0; idx < sizes.length; idx++) { 802 result[idx + 1] = result[idx] + sizes[idx] + spacing; 803 } 804 805 return result; 806 } 807 808 811 protected void layout(Composite composite, boolean flushCache) { 812 Control[] children = composite.getChildren(); 813 814 if (children.length == 0) 816 return; 817 818 initGrid(children); 819 820 if (flushCache) { 821 cache.flush(); 822 } 823 824 Point emptySpace = totalEmptySpace(); 825 826 int availableWidth = composite.getClientArea().width - emptySpace.x; 828 int availableHeight = composite.getClientArea().height - emptySpace.y; 829 830 int[] heights = computeConstraints(true); 831 int[] widths = new int[gridInfo.getCols()]; 832 833 widths = computeSizes(heights, availableWidth, false); 835 836 heights = computeSizes(widths, availableHeight, true); 838 839 Rectangle currentCell = new Rectangle(0, 0, 0, 0); 840 841 int[] starty = computeRowPositions(composite.getClientArea().y 842 + marginHeight, heights, verticalSpacing); 843 int[] startx = computeRowPositions(composite.getClientArea().x 844 + marginWidth, widths, horizontalSpacing); 845 846 int numChildren = gridInfo.controls.length; 847 for (int controlId = 0; controlId < numChildren; controlId++) { 848 CellData data = gridInfo.getCellData(controlId); 849 850 int row = gridInfo.controlRow[controlId]; 851 int col = gridInfo.controlCol[controlId]; 852 853 currentCell.x = startx[col]; 854 currentCell.width = startx[col + data.horizontalSpan] 855 - currentCell.x - horizontalSpacing; 856 857 currentCell.y = starty[row]; 858 currentCell.height = starty[row + data.verticalSpan] 859 - currentCell.y - verticalSpacing; 860 861 data.positionControl(cache.getCache(controlId), currentCell); 862 } 863 } 864 865 868 public int getColumns() { 869 return numCols; 870 } 871 872 public boolean canGrow(Composite composite, boolean horizontally) { 873 initGrid(composite.getChildren()); 874 875 int numRows = gridInfo.getNumRows(horizontally); 876 877 for (int idx = 0; idx < numRows; idx++) { 878 Row row = getRow(idx, horizontally); 879 880 if (row.grows) { 881 return true; 882 } 883 } 884 885 return false; 886 887 } 888 } 889 | Popular Tags |