1187 for (int i = 0; i < managed.size(); ++i) {
1188 final Orientation b = managed.get(i).getContentBias();
1189 if (b != null) {
1190 bias = b;
1191 if (b == Orientation.HORIZONTAL) {
1192 break;
1193 }
1194 }
1195 }
1196
1197 metricsDirty = false;
1198 }
1199 }
1200
1201 @Override protected double computeMinWidth(double height) {
1202 computeGridMetrics();
1203 performingLayout = true;
1204 try {
1205 final double[] heights = height == -1 ? null : computeHeightsToFit(height).asArray();
1206
1207 return snapSpace(getInsets().getLeft()) +
1208 computeMinWidths(heights).computeTotalWithMultiSize() +
1209 snapSpace(getInsets().getRight());
1210 } finally {
1211 performingLayout = false;
1212 }
1213
1214 }
1215
1216 @Override protected double computeMinHeight(double width) {
1217 computeGridMetrics();
1218 performingLayout = true;
1219 try {
1220 final double[] widths = width == -1 ? null : computeWidthsToFit(width).asArray();
1221
1222 return snapSpace(getInsets().getTop()) +
1223 computeMinHeights(widths).computeTotalWithMultiSize() +
1224 snapSpace(getInsets().getBottom());
1225 } finally {
1226 performingLayout = false;
1227 }
1228 }
1229
1230 @Override protected double computePrefWidth(double height) {
1231 computeGridMetrics();
1232 performingLayout = true;
1233 try {
1234 final double[] heights = height == -1 ? null : computeHeightsToFit(height).asArray();
1235
1236 return snapSpace(getInsets().getLeft()) +
1237 computePrefWidths(heights).computeTotalWithMultiSize() +
1238 snapSpace(getInsets().getRight());
1239 } finally {
1240 performingLayout = false;
1241 }
1242 }
1243
1244 @Override protected double computePrefHeight(double width) {
1245 computeGridMetrics();
1246 performingLayout = true;
1247 try {
1248 final double[] widths = width == -1 ? null : computeWidthsToFit(width).asArray();
1249
1250 return snapSpace(getInsets().getTop()) +
1251 computePrefHeights(widths).computeTotalWithMultiSize() +
1252 snapSpace(getInsets().getBottom());
1253 } finally {
1254 performingLayout = false;
1255 }
1256 }
1257
1258 private VPos getRowValignment(int rowIndex) {
1259 if (rowIndex < getRowConstraints().size()) {
1260 RowConstraints constraints = getRowConstraints().get(rowIndex);
1261 if (constraints.getValignment() != null) {
1262 return constraints.getValignment();
1263 }
1264 }
1265 return VPos.CENTER;
1266 }
1267
1268 private HPos getColumnHalignment(int columnIndex) {
1269 if (columnIndex < getColumnConstraints().size()) {
1270 ColumnConstraints constraints = getColumnConstraints().get(columnIndex);
1271 if (constraints.getHalignment() != null) {
1272 return constraints.getHalignment();
1345 if (getNodeColumnSpan(child) == 1) {
1346 return widths[getNodeColumnIndex(child)];
1347 } else {
1348 double total = 0;
1349 for (int i = getNodeColumnIndex(child), last = getNodeColumnEndConvertRemaining(child); i <= last; ++i) {
1350 total += widths[i];
1351 }
1352 return total;
1353 }
1354 }
1355
1356 private CompositeSize computeMaxHeights() {
1357 if (rowMaxHeight == null) {
1358 rowMaxHeight = createCompositeRows(Double.MAX_VALUE); // Do not restrict the row (to allow grow). The
1359 // Nodes will be restricted to their computed size
1360 // in Region.layoutInArea call
1361 final ObservableList<RowConstraints> rowConstr = getRowConstraints();
1362 CompositeSize prefHeights = null;
1363 for (int i = 0; i < rowConstr.size(); ++i) {
1364 final RowConstraints curConstraint = rowConstr.get(i);
1365 double maxRowHeight = snapSize(curConstraint.getMaxHeight());
1366 if (maxRowHeight == USE_PREF_SIZE) {
1367 if (prefHeights == null) {
1368 prefHeights = computePrefHeights(null);
1369 }
1370 rowMaxHeight.setPresetSize(i, prefHeights.getSize(i));
1371 } else if (maxRowHeight != USE_COMPUTED_SIZE) {
1372 final double min = snapSize(curConstraint.getMinHeight());
1373 if (min >= 0 ) {
1374 rowMaxHeight.setPresetSize(i, boundedSize(min, maxRowHeight, maxRowHeight));
1375 } else {
1376 rowMaxHeight.setPresetSize(i, maxRowHeight);
1377 }
1378 }
1379 }
1380 }
1381 return rowMaxHeight;
1382 }
1383
1384 private CompositeSize computePrefHeights(double[] widths) {
1385 CompositeSize result;
1386 if (widths == null) {
1387 if (rowPrefHeight != null) {
1388 return rowPrefHeight;
1389 }
1390 rowPrefHeight = createCompositeRows(0);
1391 result = rowPrefHeight;
1392 } else {
1393 result = createCompositeRows(0);
1394 }
1395
1396 final ObservableList<RowConstraints> rowConstr = getRowConstraints();
1397 for (int i = 0; i < rowConstr.size(); ++i) {
1398 final RowConstraints curConstraint = rowConstr.get(i);
1399 double prefRowHeight = snapSize(curConstraint.getPrefHeight());
1400 final double min = snapSize(curConstraint.getMinHeight());
1401 if (prefRowHeight != USE_COMPUTED_SIZE) {
1402 final double max = snapSize(curConstraint.getMaxHeight());
1403 if (min >= 0 || max >= 0) {
1404 result.setPresetSize(i, boundedSize(min < 0 ? 0 : min,
1405 prefRowHeight,
1406 max < 0 ? Double.POSITIVE_INFINITY : max));
1407 } else {
1408 result.setPresetSize(i, prefRowHeight);
1409 }
1410 } else if (min > 0){
1411 result.setSize(i, min);
1412 }
1413 }
1414 List<Node> managed = getManagedChildren();
1415 for (int i = 0, size = managed.size(); i < size; i++) {
1416 Node child = managed.get(i);
1417 int start = getNodeRowIndex(child);
1418 int end = getNodeRowEndConvertRemaining(child);
1419 double childPrefAreaHeight = computeChildPrefAreaHeight(child, isNodePositionedByBaseline(child) ? rowPrefBaselineComplement[start] : -1, getMargin(child),
1420 widths == null ? -1 : getTotalWidthOfNodeColumns(child, widths));
1421 if (start == end && !result.isPreset(start)) {
1422 double min = getRowMinHeight(start);
1427 }
1428 }
1429 return result;
1430 }
1431
1432 private CompositeSize computeMinHeights(double[] widths) {
1433 CompositeSize result;
1434 if (widths == null) {
1435 if (rowMinHeight != null) {
1436 return rowMinHeight;
1437 }
1438 rowMinHeight = createCompositeRows(0);
1439 result = rowMinHeight;
1440 } else {
1441 result = createCompositeRows(0);
1442 }
1443
1444 final ObservableList<RowConstraints> rowConstr = getRowConstraints();
1445 CompositeSize prefHeights = null;
1446 for (int i = 0; i < rowConstr.size(); ++i) {
1447 double minRowHeight = snapSize(rowConstr.get(i).getMinHeight());
1448 if (minRowHeight == USE_PREF_SIZE) {
1449 if (prefHeights == null) {
1450 prefHeights = computePrefHeights(widths);
1451 }
1452 result.setPresetSize(i, prefHeights.getSize(i));
1453 } else if (minRowHeight != USE_COMPUTED_SIZE) {
1454 result.setPresetSize(i, minRowHeight);
1455 }
1456 }
1457 List<Node> managed = getManagedChildren();
1458 for (int i = 0, size = managed.size(); i < size; i++) {
1459 Node child = managed.get(i);
1460 int start = getNodeRowIndex(child);
1461 int end = getNodeRowEndConvertRemaining(child);
1462 double childMinAreaHeight = computeChildMinAreaHeight(child, isNodePositionedByBaseline(child) ? rowMinBaselineComplement[start] : -1, getMargin(child),
1463 widths == null ? -1 : getTotalWidthOfNodeColumns(child, widths));
1464 if (start == end && !result.isPreset(start)) {
1465 result.setMaxSize(start, childMinAreaHeight);
1466 } else if (start != end){
1467 result.setMaxMultiSize(start, end + 1, childMinAreaHeight);
1474 if (getNodeRowSpan(child) == 1) {
1475 return heights[getNodeRowIndex(child)];
1476 } else {
1477 double total = 0;
1478 for (int i = getNodeRowIndex(child), last = getNodeRowEndConvertRemaining(child); i <= last; ++i) {
1479 total += heights[i];
1480 }
1481 return total;
1482 }
1483 }
1484
1485 private CompositeSize computeMaxWidths() {
1486 if (columnMaxWidth == null) {
1487 columnMaxWidth = createCompositeColumns(Double.MAX_VALUE);// Do not restrict the column (to allow grow). The
1488 // Nodes will be restricted to their computed size
1489 // in Region.layoutInArea call
1490 final ObservableList<ColumnConstraints> columnConstr = getColumnConstraints();
1491 CompositeSize prefWidths = null;
1492 for (int i = 0; i < columnConstr.size(); ++i) {
1493 final ColumnConstraints curConstraint = columnConstr.get(i);
1494 double maxColumnWidth = snapSize(curConstraint.getMaxWidth());
1495 if (maxColumnWidth == USE_PREF_SIZE) {
1496 if (prefWidths == null) {
1497 prefWidths = computePrefWidths(null);
1498 }
1499 columnMaxWidth.setPresetSize(i, prefWidths.getSize(i));
1500 } else if (maxColumnWidth != USE_COMPUTED_SIZE) {
1501 final double min = snapSize(curConstraint.getMinWidth());
1502 if (min >= 0) {
1503 columnMaxWidth.setPresetSize(i, boundedSize(min, maxColumnWidth, maxColumnWidth));
1504 } else {
1505 columnMaxWidth.setPresetSize(i, maxColumnWidth);
1506 }
1507 }
1508 }
1509 }
1510 return columnMaxWidth;
1511 }
1512
1513 private CompositeSize computePrefWidths(double[] heights) {
1514 CompositeSize result;
1515 if (heights == null) {
1516 if (columnPrefWidth != null) {
1517 return columnPrefWidth;
1518 }
1519 columnPrefWidth = createCompositeColumns(0);
1520 result = columnPrefWidth;
1521 } else {
1522 result = createCompositeColumns(0);
1523 }
1524
1525 final ObservableList<ColumnConstraints> columnConstr = getColumnConstraints();
1526 for (int i = 0; i < columnConstr.size(); ++i) {
1527 final ColumnConstraints curConstraint = columnConstr.get(i);
1528 double prefColumnWidth = snapSize(curConstraint.getPrefWidth());
1529 final double min = snapSize(curConstraint.getMinWidth());
1530 if (prefColumnWidth != USE_COMPUTED_SIZE) {
1531 final double max = snapSize(curConstraint.getMaxWidth());
1532 if (min >= 0 || max >= 0) {
1533 result.setPresetSize(i, boundedSize(min < 0 ? 0 : min,
1534 prefColumnWidth,
1535 max < 0 ? Double.POSITIVE_INFINITY : max));
1536 } else {
1537 result.setPresetSize(i, prefColumnWidth);
1538 }
1539 } else if (min > 0){
1540 result.setSize(i, min);
1541 }
1542 }
1543 List<Node> managed = getManagedChildren();
1544 for (int i = 0, size = managed.size(); i < size; i++) {
1545 Node child = managed.get(i);
1546 int start = getNodeColumnIndex(child);
1547 int end = getNodeColumnEndConvertRemaining(child);
1548 if (start == end && !result.isPreset(start)) {
1549 double min = getColumnMinWidth(start);
1550 double max = getColumnMaxWidth(start);
1551 result.setMaxSize(start, boundedSize(min < 0 ? 0 : min, computeChildPrefAreaWidth(child,
1559 }
1560 }
1561 return result;
1562 }
1563
1564 private CompositeSize computeMinWidths(double[] heights) {
1565 CompositeSize result;
1566 if (heights == null) {
1567 if (columnMinWidth != null) {
1568 return columnMinWidth;
1569 }
1570 columnMinWidth = createCompositeColumns(0);
1571 result = columnMinWidth;
1572 } else {
1573 result = createCompositeColumns(0);
1574 }
1575
1576 final ObservableList<ColumnConstraints> columnConstr = getColumnConstraints();
1577 CompositeSize prefWidths = null;
1578 for (int i = 0; i < columnConstr.size(); ++i) {
1579 double minColumnWidth = snapSize(columnConstr.get(i).getMinWidth());
1580 if (minColumnWidth == USE_PREF_SIZE) {
1581 if (prefWidths == null) {
1582 prefWidths = computePrefWidths(heights);
1583 }
1584 result.setPresetSize(i, prefWidths.getSize(i));
1585 } else if (minColumnWidth != USE_COMPUTED_SIZE) {
1586 result.setPresetSize(i, minColumnWidth);
1587 }
1588 }
1589 List<Node> managed = getManagedChildren();
1590 for (int i = 0, size = managed.size(); i < size; i++) {
1591 Node child = managed.get(i);
1592 int start = getNodeColumnIndex(child);
1593 int end = getNodeColumnEndConvertRemaining(child);
1594 if (start == end && !result.isPreset(start)) {
1595 result.setMaxSize(start, computeChildMinAreaWidth(child, getBaselineComplementForChild(child),
1596 getMargin(child),
1597 heights == null ? -1 : getTotalHeightOfNodeRows(child, heights),false));
1598 } else if (start != end){
1599 result.setMaxMultiSize(start, end + 1, computeChildMinAreaWidth(child, getBaselineComplementForChild(child),
1646 // next layout pass.
1647 if (performingLayout) {
1648 return;
1649 } else if (metricsDirty) {
1650 super.requestLayout();
1651 return;
1652 }
1653 metricsDirty = true;
1654 bias = null;
1655 rowGrow = null;
1656 rowMinHeight = rowPrefHeight = rowMaxHeight = null;
1657 columnGrow = null;
1658 columnMinWidth = columnPrefWidth = columnMaxWidth = null;
1659 rowMinBaselineComplement = rowPrefBaselineComplement = rowMaxBaselineComplement = null;
1660 super.requestLayout();
1661 }
1662
1663 @Override protected void layoutChildren() {
1664 performingLayout = true;
1665 try {
1666 final double snaphgap = snapSpace(getHgap());
1667 final double snapvgap = snapSpace(getVgap());
1668 final double top = snapSpace(getInsets().getTop());
1669 final double bottom = snapSpace(getInsets().getBottom());
1670 final double left = snapSpace(getInsets().getLeft());
1671 final double right = snapSpace(getInsets().getRight());
1672
1673 final double width = getWidth();
1674 final double height = getHeight();
1675 final double contentHeight = height - top - bottom;
1676 final double contentWidth = width - left - right;
1677 double columnTotal;
1678 double rowTotal;
1679 computeGridMetrics();
1680
1681 Orientation contentBias = getContentBias();
1682 CompositeSize heights;
1683 final CompositeSize widths;
1684 if (contentBias == null) {
1685 heights = (CompositeSize) computePrefHeights(null).clone();
1686 widths = (CompositeSize) computePrefWidths(null).clone();
1687 rowTotal = adjustRowHeights(heights, height);
1688 columnTotal = adjustColumnWidths(widths, width);
1689 } else if (contentBias == Orientation.HORIZONTAL) {
1690 widths = (CompositeSize) computePrefWidths(null).clone();
1691 columnTotal = adjustColumnWidths(widths, width);
1782 baselineOffset = baselineOffsets[rowIndex];
1783 }
1784
1785 Insets margin = getMargin(child);
1786 layoutInArea(child, areaX, areaY, areaW, areaH,
1787 baselineOffset,
1788 margin,
1789 fillWidth, fillHeight,
1790 halign, valign);
1791 }
1792 layoutGridLines(widths, heights, x, y, rowTotal, columnTotal);
1793 currentHeights = heights;
1794 currentWidths = widths;
1795 } finally {
1796 performingLayout = false;
1797 }
1798 }
1799
1800 private double adjustRowHeights(final CompositeSize heights, double height) {
1801 assert(height != -1);
1802 final double snapvgap = snapSpace(getVgap());
1803 final double top = snapSpace(getInsets().getTop());
1804 final double bottom = snapSpace(getInsets().getBottom());
1805 final double vgaps = snapvgap * (getNumberOfRows() - 1);
1806 final double contentHeight = height - top - bottom;
1807
1808 // if there are percentage rows, give them their percentages first
1809 if (rowPercentTotal > 0) {
1810 double remainder = 0;
1811 for (int i = 0; i < rowPercentHeight.length; i++) {
1812 if (rowPercentHeight[i] >= 0) {
1813 double size = (contentHeight - vgaps) * (rowPercentHeight[i]/100);
1814 double floor = Math.floor(size);
1815 remainder += size - floor;
1816
1817 // snap size to integer boundary based on the computed remainder as we loop through the rows.
1818 size = floor;
1819 if (remainder >= 0.5) {
1820 size++;
1821 remainder = (-1.0) + remainder;
1822 }
1823 heights.setSize(i, size);
1824 }
1987 double available = extraHeight; // will be negative in shrinking case
1988 boolean handleRemainder = false;
1989 double portion = 0;
1990
1991 // RT-25684: We have to be careful that when subtracting change
1992 // that we don't jump right past 0 - this leads to an infinite
1993 // loop
1994 final boolean wasPositive = available >= 0.0;
1995 boolean isPositive = wasPositive;
1996
1997 CompositeSize limitSize = shrinking? computeMinHeights(null) :
1998 computeMaxHeights();
1999 while (available != 0 && wasPositive == isPositive && adjusting.size() > 0) {
2000 if (!handleRemainder) {
2001 portion = available > 0 ? Math.floor(available / adjusting.size()) :
2002 Math.ceil(available / adjusting.size()); // negative in shrinking case
2003 }
2004 if (portion != 0) {
2005 for (Iterator<Integer> i = adjusting.iterator(); i.hasNext();) {
2006 final int index = i.next();
2007 double limit = snapSpace(limitSize.getProportionalMinOrMaxSize(index, shrinking))
2008 - heights.getSize(index); // negative in shrinking case
2009 if (shrinking && limit > 0
2010 || !shrinking && limit < 0) { // Limit completely if current size
2011 // (originally based on preferred) already passed the computed limit
2012 limit = 0;
2013 }
2014 final double change = Math.abs(limit) <= Math.abs(portion)? limit : portion;
2015 heights.addSize(index, change);
2016 available -= change;
2017 isPositive = available >= 0.0;
2018 if (Math.abs(change) < Math.abs(portion)) {
2019 i.remove();
2020 }
2021 if (available == 0) {
2022 break;
2023 }
2024 }
2025 } else {
2026 // Handle the remainder
2027 portion = (int)(available) % adjusting.size();
2028 if (portion == 0) {
2029 break;
2030 } else {
2031 // We have a remainder evenly distribute it.
2032 portion = shrinking ? -1 : 1;
2033 handleRemainder = true;
2034 }
2035 }
2036 }
2037
2038 return available; // might be negative in shrinking case
2039 }
2040
2041 private double adjustColumnWidths(final CompositeSize widths, double width) {
2042 assert(width != -1);
2043 final double snaphgap = snapSpace(getHgap());
2044 final double left = snapSpace(getInsets().getLeft());
2045 final double right = snapSpace(getInsets().getRight());
2046 final double hgaps = snaphgap * (getNumberOfColumns() - 1);
2047 final double contentWidth = width - left - right;
2048
2049 // if there are percentage rows, give them their percentages first
2050 if (columnPercentTotal > 0) {
2051 double remainder = 0;
2052 for (int i = 0; i < columnPercentWidth.length; i++) {
2053 if (columnPercentWidth[i] >= 0) {
2054 double size = (contentWidth - hgaps) * (columnPercentWidth[i]/100);
2055 double floor = Math.floor(size);
2056 remainder += size - floor;
2057
2058 // snap size to integer boundary based on the computed remainder as we loop through the columns.
2059 size = floor;
2060 if (remainder >= 0.5) {
2061 size++;
2062 remainder = (-1.0) + remainder;
2063 }
2064 widths.setSize(i, size);
2065 }
2231 double available = extraWidth; // will be negative in shrinking case
2232 boolean handleRemainder = false;
2233 double portion = 0;
2234
2235 // RT-25684: We have to be careful that when subtracting change
2236 // that we don't jump right past 0 - this leads to an infinite
2237 // loop
2238 final boolean wasPositive = available >= 0.0;
2239 boolean isPositive = wasPositive;
2240
2241 CompositeSize limitSize = shrinking? computeMinWidths(null) :
2242 computeMaxWidths();
2243 while (available != 0 && wasPositive == isPositive && adjusting.size() > 0) {
2244 if (!handleRemainder) {
2245 portion = available > 0 ? Math.floor(available / adjusting.size()) :
2246 Math.ceil(available / adjusting.size()); // negative in shrinking case
2247 }
2248 if (portion != 0) {
2249 for (Iterator<Integer> i = adjusting.iterator(); i.hasNext();) {
2250 final int index = i.next();
2251 double limit = snapSpace(limitSize.getProportionalMinOrMaxSize(index, shrinking))
2252 - widths.getSize(index); // negative in shrinking case
2253 if (shrinking && limit > 0
2254 || !shrinking && limit < 0) { // Limit completely if current size
2255 // (originally based on preferred) already passed the computed limit
2256 limit = 0;
2257 }
2258 final double change = Math.abs(limit) <= Math.abs(portion)? limit : portion;
2259 widths.addSize(index, change);
2260 available -= change;
2261 isPositive = available >= 0.0;
2262 if (Math.abs(change) < Math.abs(portion)) {
2263 i.remove();
2264 }
2265 if (available == 0) {
2266 break;
2267 }
2268 }
2269 } else {
2270 // Handle the remainder
2271 portion = (int)(available) % adjusting.size();
2272 if (portion == 0) {
2273 break;
2274 } else {
2275 // We have a remainder evenly distribute it.
2276 portion = shrinking ? -1 : 1;
2277 handleRemainder = true;
2278 }
2279 }
2280 }
2281
2282 return available; // might be negative in shrinking case
2283 }
2284
2285 private void layoutGridLines(CompositeSize columnWidths, CompositeSize rowHeights, double x, double y, double columnHeight, double rowWidth) {
2286 if (!isGridLinesVisible()) {
2287 return;
2288 }
2289 if (!gridLines.getChildren().isEmpty()) {
2290 gridLines.getChildren().clear();
2291 }
2292 double hgap = snapSpace(getHgap());
2293 double vgap = snapSpace(getVgap());
2294
2295 // create vertical lines
2296 double linex = x;
2297 double liney = y;
2298 for (int i = 0; i <= columnWidths.getLength(); i++) {
2299 gridLines.getChildren().add(createGridLine(linex, liney, linex, liney + columnHeight));
2300 if (i > 0 && i < columnWidths.getLength() && getHgap() != 0) {
2301 linex += getHgap();
2302 gridLines.getChildren().add(createGridLine(linex, liney, linex, liney + columnHeight));
2303 }
2304 if (i < columnWidths.getLength()) {
2305 linex += columnWidths.getSize(i);
2306 }
2307 }
2308 // create horizontal lines
2309 linex = x;
2310 for (int i = 0; i <= rowHeights.getLength(); i++) {
2311 gridLines.getChildren().add(createGridLine(linex, liney, linex + rowWidth, liney));
2312 if (i > 0 && i < rowHeights.getLength() && getVgap() != 0) {
2313 liney += getVgap();
2324 line.setStartX(startX);
2325 line.setStartY(startY);
2326 line.setEndX(endX);
2327 line.setEndY(endY);
2328 line.setStroke(GRID_LINE_COLOR);
2329 line.setStrokeDashOffset(GRID_LINE_DASH);
2330
2331 return line;
2332 }
2333
2334 /**
2335 * Returns a string representation of this {@code GridPane} object.
2336 * @return a string representation of this {@code GridPane} object.
2337 */
2338 @Override public String toString() {
2339 return "Grid hgap="+getHgap()+", vgap="+getVgap()+", alignment="+getAlignment();
2340 }
2341
2342 private CompositeSize createCompositeRows(double initSize) {
2343 return new CompositeSize(getNumberOfRows(), rowPercentHeight, rowPercentTotal,
2344 snapSpace(getVgap()), initSize);
2345 }
2346
2347 private CompositeSize createCompositeColumns(double initSize) {
2348 return new CompositeSize(getNumberOfColumns(), columnPercentWidth, columnPercentTotal,
2349 snapSpace(getHgap()), initSize);
2350 }
2351
2352 private int getNodeRowEndConvertRemaining(Node child) {
2353 int rowSpan = getNodeRowSpan(child);
2354 return rowSpan != REMAINING? getNodeRowIndex(child) + rowSpan - 1 : getNumberOfRows() - 1;
2355 }
2356
2357 private int getNodeColumnEndConvertRemaining(Node child) {
2358 int columnSpan = getNodeColumnSpan(child);
2359 return columnSpan != REMAINING? getNodeColumnIndex(child) + columnSpan - 1 : getNumberOfColumns() - 1;
2360 }
2361
2362
2363 // This methods are inteded to be used by GridPaneDesignInfo
2364 private CompositeSize currentHeights;
2365 private CompositeSize currentWidths;
2366
2367 double[][] getGrid() {
2368 if (currentHeights == null || currentWidths == null) {
2369 return null;
2723 int nColumns = this.getColumnConstraints().size();
2724 for (int i = 0; i < this.getChildren().size(); i++) {
2725 Node child = this.getChildren().get(i);
2726 if (child.isManaged()) {
2727 int columnIndex = GridPane.getNodeColumnIndex(child);
2728 int columnEnd = GridPane.getNodeColumnEnd(child);
2729 nColumns = Math.max(nColumns, (columnEnd != GridPane.REMAINING? columnEnd : columnIndex) + 1);
2730 }
2731 }
2732 return nColumns;
2733 }
2734
2735 /**
2736 * Copied from GridPaneDesignInfo for SceneBuilder.
2737 *
2738 * @treatAsPrivate implementation detail
2739 * @deprecated This is an internal API that is not intended for use and will be removed in the next version
2740 */
2741 @Deprecated // SB-dependency: RT-33381 has been filed to track this
2742 public final Bounds impl_getCellBounds(int columnIndex, int rowIndex) {
2743 final double snaphgap = this.snapSpace(this.getHgap());
2744 final double snapvgap = this.snapSpace(this.getVgap());
2745 final double top = this.snapSpace(this.getInsets().getTop());
2746 final double right = this.snapSpace(this.getInsets().getRight());
2747 final double bottom = this.snapSpace(this.getInsets().getBottom());
2748 final double left = this.snapSpace(this.getInsets().getLeft());
2749 final double gridPaneHeight = this.snapSize(this.getHeight()) - (top + bottom);
2750 final double gridPaneWidth = this.snapSize(this.getWidth()) - (left + right);
2751
2752 // Compute grid. Result contains two double arrays, first for columns, second for rows
2753 double[] columnWidths;
2754 double[] rowHeights;
2755
2756 double[][] grid = this.getGrid();
2757 if (grid == null) {
2758 rowHeights = new double[] {0};
2759 rowIndex = 0;
2760 columnWidths = new double[] {0};
2761 columnIndex = 0;
2762 } else {
2763 columnWidths = grid[0];
2764 rowHeights = grid[1];
2765 }
2766
2767 // Compute the total row height
2768 double rowTotal = 0;
2769 for (int i = 0; i < rowHeights.length; i++) {
2770 rowTotal += rowHeights[i];
|
1187 for (int i = 0; i < managed.size(); ++i) {
1188 final Orientation b = managed.get(i).getContentBias();
1189 if (b != null) {
1190 bias = b;
1191 if (b == Orientation.HORIZONTAL) {
1192 break;
1193 }
1194 }
1195 }
1196
1197 metricsDirty = false;
1198 }
1199 }
1200
1201 @Override protected double computeMinWidth(double height) {
1202 computeGridMetrics();
1203 performingLayout = true;
1204 try {
1205 final double[] heights = height == -1 ? null : computeHeightsToFit(height).asArray();
1206
1207 return snapSpaceX(getInsets().getLeft()) +
1208 computeMinWidths(heights).computeTotalWithMultiSize() +
1209 snapSpaceX(getInsets().getRight());
1210 } finally {
1211 performingLayout = false;
1212 }
1213
1214 }
1215
1216 @Override protected double computeMinHeight(double width) {
1217 computeGridMetrics();
1218 performingLayout = true;
1219 try {
1220 final double[] widths = width == -1 ? null : computeWidthsToFit(width).asArray();
1221
1222 return snapSpaceY(getInsets().getTop()) +
1223 computeMinHeights(widths).computeTotalWithMultiSize() +
1224 snapSpaceY(getInsets().getBottom());
1225 } finally {
1226 performingLayout = false;
1227 }
1228 }
1229
1230 @Override protected double computePrefWidth(double height) {
1231 computeGridMetrics();
1232 performingLayout = true;
1233 try {
1234 final double[] heights = height == -1 ? null : computeHeightsToFit(height).asArray();
1235
1236 return snapSpaceX(getInsets().getLeft()) +
1237 computePrefWidths(heights).computeTotalWithMultiSize() +
1238 snapSpaceX(getInsets().getRight());
1239 } finally {
1240 performingLayout = false;
1241 }
1242 }
1243
1244 @Override protected double computePrefHeight(double width) {
1245 computeGridMetrics();
1246 performingLayout = true;
1247 try {
1248 final double[] widths = width == -1 ? null : computeWidthsToFit(width).asArray();
1249
1250 return snapSpaceY(getInsets().getTop()) +
1251 computePrefHeights(widths).computeTotalWithMultiSize() +
1252 snapSpaceY(getInsets().getBottom());
1253 } finally {
1254 performingLayout = false;
1255 }
1256 }
1257
1258 private VPos getRowValignment(int rowIndex) {
1259 if (rowIndex < getRowConstraints().size()) {
1260 RowConstraints constraints = getRowConstraints().get(rowIndex);
1261 if (constraints.getValignment() != null) {
1262 return constraints.getValignment();
1263 }
1264 }
1265 return VPos.CENTER;
1266 }
1267
1268 private HPos getColumnHalignment(int columnIndex) {
1269 if (columnIndex < getColumnConstraints().size()) {
1270 ColumnConstraints constraints = getColumnConstraints().get(columnIndex);
1271 if (constraints.getHalignment() != null) {
1272 return constraints.getHalignment();
1345 if (getNodeColumnSpan(child) == 1) {
1346 return widths[getNodeColumnIndex(child)];
1347 } else {
1348 double total = 0;
1349 for (int i = getNodeColumnIndex(child), last = getNodeColumnEndConvertRemaining(child); i <= last; ++i) {
1350 total += widths[i];
1351 }
1352 return total;
1353 }
1354 }
1355
1356 private CompositeSize computeMaxHeights() {
1357 if (rowMaxHeight == null) {
1358 rowMaxHeight = createCompositeRows(Double.MAX_VALUE); // Do not restrict the row (to allow grow). The
1359 // Nodes will be restricted to their computed size
1360 // in Region.layoutInArea call
1361 final ObservableList<RowConstraints> rowConstr = getRowConstraints();
1362 CompositeSize prefHeights = null;
1363 for (int i = 0; i < rowConstr.size(); ++i) {
1364 final RowConstraints curConstraint = rowConstr.get(i);
1365 double maxRowHeight = snapSizeY(curConstraint.getMaxHeight());
1366 if (maxRowHeight == USE_PREF_SIZE) {
1367 if (prefHeights == null) {
1368 prefHeights = computePrefHeights(null);
1369 }
1370 rowMaxHeight.setPresetSize(i, prefHeights.getSize(i));
1371 } else if (maxRowHeight != USE_COMPUTED_SIZE) {
1372 final double min = snapSizeY(curConstraint.getMinHeight());
1373 if (min >= 0 ) {
1374 rowMaxHeight.setPresetSize(i, boundedSize(min, maxRowHeight, maxRowHeight));
1375 } else {
1376 rowMaxHeight.setPresetSize(i, maxRowHeight);
1377 }
1378 }
1379 }
1380 }
1381 return rowMaxHeight;
1382 }
1383
1384 private CompositeSize computePrefHeights(double[] widths) {
1385 CompositeSize result;
1386 if (widths == null) {
1387 if (rowPrefHeight != null) {
1388 return rowPrefHeight;
1389 }
1390 rowPrefHeight = createCompositeRows(0);
1391 result = rowPrefHeight;
1392 } else {
1393 result = createCompositeRows(0);
1394 }
1395
1396 final ObservableList<RowConstraints> rowConstr = getRowConstraints();
1397 for (int i = 0; i < rowConstr.size(); ++i) {
1398 final RowConstraints curConstraint = rowConstr.get(i);
1399 double prefRowHeight = snapSizeY(curConstraint.getPrefHeight());
1400 final double min = snapSizeY(curConstraint.getMinHeight());
1401 if (prefRowHeight != USE_COMPUTED_SIZE) {
1402 final double max = snapSizeY(curConstraint.getMaxHeight());
1403 if (min >= 0 || max >= 0) {
1404 result.setPresetSize(i, boundedSize(min < 0 ? 0 : min,
1405 prefRowHeight,
1406 max < 0 ? Double.POSITIVE_INFINITY : max));
1407 } else {
1408 result.setPresetSize(i, prefRowHeight);
1409 }
1410 } else if (min > 0){
1411 result.setSize(i, min);
1412 }
1413 }
1414 List<Node> managed = getManagedChildren();
1415 for (int i = 0, size = managed.size(); i < size; i++) {
1416 Node child = managed.get(i);
1417 int start = getNodeRowIndex(child);
1418 int end = getNodeRowEndConvertRemaining(child);
1419 double childPrefAreaHeight = computeChildPrefAreaHeight(child, isNodePositionedByBaseline(child) ? rowPrefBaselineComplement[start] : -1, getMargin(child),
1420 widths == null ? -1 : getTotalWidthOfNodeColumns(child, widths));
1421 if (start == end && !result.isPreset(start)) {
1422 double min = getRowMinHeight(start);
1427 }
1428 }
1429 return result;
1430 }
1431
1432 private CompositeSize computeMinHeights(double[] widths) {
1433 CompositeSize result;
1434 if (widths == null) {
1435 if (rowMinHeight != null) {
1436 return rowMinHeight;
1437 }
1438 rowMinHeight = createCompositeRows(0);
1439 result = rowMinHeight;
1440 } else {
1441 result = createCompositeRows(0);
1442 }
1443
1444 final ObservableList<RowConstraints> rowConstr = getRowConstraints();
1445 CompositeSize prefHeights = null;
1446 for (int i = 0; i < rowConstr.size(); ++i) {
1447 double minRowHeight = snapSizeY(rowConstr.get(i).getMinHeight());
1448 if (minRowHeight == USE_PREF_SIZE) {
1449 if (prefHeights == null) {
1450 prefHeights = computePrefHeights(widths);
1451 }
1452 result.setPresetSize(i, prefHeights.getSize(i));
1453 } else if (minRowHeight != USE_COMPUTED_SIZE) {
1454 result.setPresetSize(i, minRowHeight);
1455 }
1456 }
1457 List<Node> managed = getManagedChildren();
1458 for (int i = 0, size = managed.size(); i < size; i++) {
1459 Node child = managed.get(i);
1460 int start = getNodeRowIndex(child);
1461 int end = getNodeRowEndConvertRemaining(child);
1462 double childMinAreaHeight = computeChildMinAreaHeight(child, isNodePositionedByBaseline(child) ? rowMinBaselineComplement[start] : -1, getMargin(child),
1463 widths == null ? -1 : getTotalWidthOfNodeColumns(child, widths));
1464 if (start == end && !result.isPreset(start)) {
1465 result.setMaxSize(start, childMinAreaHeight);
1466 } else if (start != end){
1467 result.setMaxMultiSize(start, end + 1, childMinAreaHeight);
1474 if (getNodeRowSpan(child) == 1) {
1475 return heights[getNodeRowIndex(child)];
1476 } else {
1477 double total = 0;
1478 for (int i = getNodeRowIndex(child), last = getNodeRowEndConvertRemaining(child); i <= last; ++i) {
1479 total += heights[i];
1480 }
1481 return total;
1482 }
1483 }
1484
1485 private CompositeSize computeMaxWidths() {
1486 if (columnMaxWidth == null) {
1487 columnMaxWidth = createCompositeColumns(Double.MAX_VALUE);// Do not restrict the column (to allow grow). The
1488 // Nodes will be restricted to their computed size
1489 // in Region.layoutInArea call
1490 final ObservableList<ColumnConstraints> columnConstr = getColumnConstraints();
1491 CompositeSize prefWidths = null;
1492 for (int i = 0; i < columnConstr.size(); ++i) {
1493 final ColumnConstraints curConstraint = columnConstr.get(i);
1494 double maxColumnWidth = snapSizeX(curConstraint.getMaxWidth());
1495 if (maxColumnWidth == USE_PREF_SIZE) {
1496 if (prefWidths == null) {
1497 prefWidths = computePrefWidths(null);
1498 }
1499 columnMaxWidth.setPresetSize(i, prefWidths.getSize(i));
1500 } else if (maxColumnWidth != USE_COMPUTED_SIZE) {
1501 final double min = snapSizeX(curConstraint.getMinWidth());
1502 if (min >= 0) {
1503 columnMaxWidth.setPresetSize(i, boundedSize(min, maxColumnWidth, maxColumnWidth));
1504 } else {
1505 columnMaxWidth.setPresetSize(i, maxColumnWidth);
1506 }
1507 }
1508 }
1509 }
1510 return columnMaxWidth;
1511 }
1512
1513 private CompositeSize computePrefWidths(double[] heights) {
1514 CompositeSize result;
1515 if (heights == null) {
1516 if (columnPrefWidth != null) {
1517 return columnPrefWidth;
1518 }
1519 columnPrefWidth = createCompositeColumns(0);
1520 result = columnPrefWidth;
1521 } else {
1522 result = createCompositeColumns(0);
1523 }
1524
1525 final ObservableList<ColumnConstraints> columnConstr = getColumnConstraints();
1526 for (int i = 0; i < columnConstr.size(); ++i) {
1527 final ColumnConstraints curConstraint = columnConstr.get(i);
1528 double prefColumnWidth = snapSizeX(curConstraint.getPrefWidth());
1529 final double min = snapSizeX(curConstraint.getMinWidth());
1530 if (prefColumnWidth != USE_COMPUTED_SIZE) {
1531 final double max = snapSizeX(curConstraint.getMaxWidth());
1532 if (min >= 0 || max >= 0) {
1533 result.setPresetSize(i, boundedSize(min < 0 ? 0 : min,
1534 prefColumnWidth,
1535 max < 0 ? Double.POSITIVE_INFINITY : max));
1536 } else {
1537 result.setPresetSize(i, prefColumnWidth);
1538 }
1539 } else if (min > 0){
1540 result.setSize(i, min);
1541 }
1542 }
1543 List<Node> managed = getManagedChildren();
1544 for (int i = 0, size = managed.size(); i < size; i++) {
1545 Node child = managed.get(i);
1546 int start = getNodeColumnIndex(child);
1547 int end = getNodeColumnEndConvertRemaining(child);
1548 if (start == end && !result.isPreset(start)) {
1549 double min = getColumnMinWidth(start);
1550 double max = getColumnMaxWidth(start);
1551 result.setMaxSize(start, boundedSize(min < 0 ? 0 : min, computeChildPrefAreaWidth(child,
1559 }
1560 }
1561 return result;
1562 }
1563
1564 private CompositeSize computeMinWidths(double[] heights) {
1565 CompositeSize result;
1566 if (heights == null) {
1567 if (columnMinWidth != null) {
1568 return columnMinWidth;
1569 }
1570 columnMinWidth = createCompositeColumns(0);
1571 result = columnMinWidth;
1572 } else {
1573 result = createCompositeColumns(0);
1574 }
1575
1576 final ObservableList<ColumnConstraints> columnConstr = getColumnConstraints();
1577 CompositeSize prefWidths = null;
1578 for (int i = 0; i < columnConstr.size(); ++i) {
1579 double minColumnWidth = snapSizeX(columnConstr.get(i).getMinWidth());
1580 if (minColumnWidth == USE_PREF_SIZE) {
1581 if (prefWidths == null) {
1582 prefWidths = computePrefWidths(heights);
1583 }
1584 result.setPresetSize(i, prefWidths.getSize(i));
1585 } else if (minColumnWidth != USE_COMPUTED_SIZE) {
1586 result.setPresetSize(i, minColumnWidth);
1587 }
1588 }
1589 List<Node> managed = getManagedChildren();
1590 for (int i = 0, size = managed.size(); i < size; i++) {
1591 Node child = managed.get(i);
1592 int start = getNodeColumnIndex(child);
1593 int end = getNodeColumnEndConvertRemaining(child);
1594 if (start == end && !result.isPreset(start)) {
1595 result.setMaxSize(start, computeChildMinAreaWidth(child, getBaselineComplementForChild(child),
1596 getMargin(child),
1597 heights == null ? -1 : getTotalHeightOfNodeRows(child, heights),false));
1598 } else if (start != end){
1599 result.setMaxMultiSize(start, end + 1, computeChildMinAreaWidth(child, getBaselineComplementForChild(child),
1646 // next layout pass.
1647 if (performingLayout) {
1648 return;
1649 } else if (metricsDirty) {
1650 super.requestLayout();
1651 return;
1652 }
1653 metricsDirty = true;
1654 bias = null;
1655 rowGrow = null;
1656 rowMinHeight = rowPrefHeight = rowMaxHeight = null;
1657 columnGrow = null;
1658 columnMinWidth = columnPrefWidth = columnMaxWidth = null;
1659 rowMinBaselineComplement = rowPrefBaselineComplement = rowMaxBaselineComplement = null;
1660 super.requestLayout();
1661 }
1662
1663 @Override protected void layoutChildren() {
1664 performingLayout = true;
1665 try {
1666 final double snaphgap = snapSpaceX(getHgap());
1667 final double snapvgap = snapSpaceY(getVgap());
1668 final double top = snapSpaceY(getInsets().getTop());
1669 final double bottom = snapSpaceY(getInsets().getBottom());
1670 final double left = snapSpaceX(getInsets().getLeft());
1671 final double right = snapSpaceX(getInsets().getRight());
1672
1673 final double width = getWidth();
1674 final double height = getHeight();
1675 final double contentHeight = height - top - bottom;
1676 final double contentWidth = width - left - right;
1677 double columnTotal;
1678 double rowTotal;
1679 computeGridMetrics();
1680
1681 Orientation contentBias = getContentBias();
1682 CompositeSize heights;
1683 final CompositeSize widths;
1684 if (contentBias == null) {
1685 heights = (CompositeSize) computePrefHeights(null).clone();
1686 widths = (CompositeSize) computePrefWidths(null).clone();
1687 rowTotal = adjustRowHeights(heights, height);
1688 columnTotal = adjustColumnWidths(widths, width);
1689 } else if (contentBias == Orientation.HORIZONTAL) {
1690 widths = (CompositeSize) computePrefWidths(null).clone();
1691 columnTotal = adjustColumnWidths(widths, width);
1782 baselineOffset = baselineOffsets[rowIndex];
1783 }
1784
1785 Insets margin = getMargin(child);
1786 layoutInArea(child, areaX, areaY, areaW, areaH,
1787 baselineOffset,
1788 margin,
1789 fillWidth, fillHeight,
1790 halign, valign);
1791 }
1792 layoutGridLines(widths, heights, x, y, rowTotal, columnTotal);
1793 currentHeights = heights;
1794 currentWidths = widths;
1795 } finally {
1796 performingLayout = false;
1797 }
1798 }
1799
1800 private double adjustRowHeights(final CompositeSize heights, double height) {
1801 assert(height != -1);
1802 final double snapvgap = snapSpaceY(getVgap());
1803 final double top = snapSpaceY(getInsets().getTop());
1804 final double bottom = snapSpaceY(getInsets().getBottom());
1805 final double vgaps = snapvgap * (getNumberOfRows() - 1);
1806 final double contentHeight = height - top - bottom;
1807
1808 // if there are percentage rows, give them their percentages first
1809 if (rowPercentTotal > 0) {
1810 double remainder = 0;
1811 for (int i = 0; i < rowPercentHeight.length; i++) {
1812 if (rowPercentHeight[i] >= 0) {
1813 double size = (contentHeight - vgaps) * (rowPercentHeight[i]/100);
1814 double floor = Math.floor(size);
1815 remainder += size - floor;
1816
1817 // snap size to integer boundary based on the computed remainder as we loop through the rows.
1818 size = floor;
1819 if (remainder >= 0.5) {
1820 size++;
1821 remainder = (-1.0) + remainder;
1822 }
1823 heights.setSize(i, size);
1824 }
1987 double available = extraHeight; // will be negative in shrinking case
1988 boolean handleRemainder = false;
1989 double portion = 0;
1990
1991 // RT-25684: We have to be careful that when subtracting change
1992 // that we don't jump right past 0 - this leads to an infinite
1993 // loop
1994 final boolean wasPositive = available >= 0.0;
1995 boolean isPositive = wasPositive;
1996
1997 CompositeSize limitSize = shrinking? computeMinHeights(null) :
1998 computeMaxHeights();
1999 while (available != 0 && wasPositive == isPositive && adjusting.size() > 0) {
2000 if (!handleRemainder) {
2001 portion = available > 0 ? Math.floor(available / adjusting.size()) :
2002 Math.ceil(available / adjusting.size()); // negative in shrinking case
2003 }
2004 if (portion != 0) {
2005 for (Iterator<Integer> i = adjusting.iterator(); i.hasNext();) {
2006 final int index = i.next();
2007 double limit = snapSpaceY(limitSize.getProportionalMinOrMaxSize(index, shrinking))
2008 - heights.getSize(index); // negative in shrinking case
2009 if (shrinking && limit > 0
2010 || !shrinking && limit < 0) { // Limit completely if current size
2011 // (originally based on preferred) already passed the computed limit
2012 limit = 0;
2013 }
2014 final double change = Math.abs(limit) <= Math.abs(portion)? limit : portion;
2015 heights.addSize(index, change);
2016 available -= change;
2017 isPositive = available >= 0.0;
2018 if (Math.abs(change) < Math.abs(portion)) {
2019 i.remove();
2020 }
2021 if (available == 0) {
2022 break;
2023 }
2024 }
2025 } else {
2026 // Handle the remainder
2027 portion = (int)(available) % adjusting.size();
2028 if (portion == 0) {
2029 break;
2030 } else {
2031 // We have a remainder evenly distribute it.
2032 portion = shrinking ? -1 : 1;
2033 handleRemainder = true;
2034 }
2035 }
2036 }
2037
2038 return available; // might be negative in shrinking case
2039 }
2040
2041 private double adjustColumnWidths(final CompositeSize widths, double width) {
2042 assert(width != -1);
2043 final double snaphgap = snapSpaceX(getHgap());
2044 final double left = snapSpaceX(getInsets().getLeft());
2045 final double right = snapSpaceX(getInsets().getRight());
2046 final double hgaps = snaphgap * (getNumberOfColumns() - 1);
2047 final double contentWidth = width - left - right;
2048
2049 // if there are percentage rows, give them their percentages first
2050 if (columnPercentTotal > 0) {
2051 double remainder = 0;
2052 for (int i = 0; i < columnPercentWidth.length; i++) {
2053 if (columnPercentWidth[i] >= 0) {
2054 double size = (contentWidth - hgaps) * (columnPercentWidth[i]/100);
2055 double floor = Math.floor(size);
2056 remainder += size - floor;
2057
2058 // snap size to integer boundary based on the computed remainder as we loop through the columns.
2059 size = floor;
2060 if (remainder >= 0.5) {
2061 size++;
2062 remainder = (-1.0) + remainder;
2063 }
2064 widths.setSize(i, size);
2065 }
2231 double available = extraWidth; // will be negative in shrinking case
2232 boolean handleRemainder = false;
2233 double portion = 0;
2234
2235 // RT-25684: We have to be careful that when subtracting change
2236 // that we don't jump right past 0 - this leads to an infinite
2237 // loop
2238 final boolean wasPositive = available >= 0.0;
2239 boolean isPositive = wasPositive;
2240
2241 CompositeSize limitSize = shrinking? computeMinWidths(null) :
2242 computeMaxWidths();
2243 while (available != 0 && wasPositive == isPositive && adjusting.size() > 0) {
2244 if (!handleRemainder) {
2245 portion = available > 0 ? Math.floor(available / adjusting.size()) :
2246 Math.ceil(available / adjusting.size()); // negative in shrinking case
2247 }
2248 if (portion != 0) {
2249 for (Iterator<Integer> i = adjusting.iterator(); i.hasNext();) {
2250 final int index = i.next();
2251 double limit = snapSpaceX(limitSize.getProportionalMinOrMaxSize(index, shrinking))
2252 - widths.getSize(index); // negative in shrinking case
2253 if (shrinking && limit > 0
2254 || !shrinking && limit < 0) { // Limit completely if current size
2255 // (originally based on preferred) already passed the computed limit
2256 limit = 0;
2257 }
2258 final double change = Math.abs(limit) <= Math.abs(portion)? limit : portion;
2259 widths.addSize(index, change);
2260 available -= change;
2261 isPositive = available >= 0.0;
2262 if (Math.abs(change) < Math.abs(portion)) {
2263 i.remove();
2264 }
2265 if (available == 0) {
2266 break;
2267 }
2268 }
2269 } else {
2270 // Handle the remainder
2271 portion = (int)(available) % adjusting.size();
2272 if (portion == 0) {
2273 break;
2274 } else {
2275 // We have a remainder evenly distribute it.
2276 portion = shrinking ? -1 : 1;
2277 handleRemainder = true;
2278 }
2279 }
2280 }
2281
2282 return available; // might be negative in shrinking case
2283 }
2284
2285 private void layoutGridLines(CompositeSize columnWidths, CompositeSize rowHeights, double x, double y, double columnHeight, double rowWidth) {
2286 if (!isGridLinesVisible()) {
2287 return;
2288 }
2289 if (!gridLines.getChildren().isEmpty()) {
2290 gridLines.getChildren().clear();
2291 }
2292 double hgap = snapSpaceX(getHgap());
2293 double vgap = snapSpaceY(getVgap());
2294
2295 // create vertical lines
2296 double linex = x;
2297 double liney = y;
2298 for (int i = 0; i <= columnWidths.getLength(); i++) {
2299 gridLines.getChildren().add(createGridLine(linex, liney, linex, liney + columnHeight));
2300 if (i > 0 && i < columnWidths.getLength() && getHgap() != 0) {
2301 linex += getHgap();
2302 gridLines.getChildren().add(createGridLine(linex, liney, linex, liney + columnHeight));
2303 }
2304 if (i < columnWidths.getLength()) {
2305 linex += columnWidths.getSize(i);
2306 }
2307 }
2308 // create horizontal lines
2309 linex = x;
2310 for (int i = 0; i <= rowHeights.getLength(); i++) {
2311 gridLines.getChildren().add(createGridLine(linex, liney, linex + rowWidth, liney));
2312 if (i > 0 && i < rowHeights.getLength() && getVgap() != 0) {
2313 liney += getVgap();
2324 line.setStartX(startX);
2325 line.setStartY(startY);
2326 line.setEndX(endX);
2327 line.setEndY(endY);
2328 line.setStroke(GRID_LINE_COLOR);
2329 line.setStrokeDashOffset(GRID_LINE_DASH);
2330
2331 return line;
2332 }
2333
2334 /**
2335 * Returns a string representation of this {@code GridPane} object.
2336 * @return a string representation of this {@code GridPane} object.
2337 */
2338 @Override public String toString() {
2339 return "Grid hgap="+getHgap()+", vgap="+getVgap()+", alignment="+getAlignment();
2340 }
2341
2342 private CompositeSize createCompositeRows(double initSize) {
2343 return new CompositeSize(getNumberOfRows(), rowPercentHeight, rowPercentTotal,
2344 snapSpaceY(getVgap()), initSize);
2345 }
2346
2347 private CompositeSize createCompositeColumns(double initSize) {
2348 return new CompositeSize(getNumberOfColumns(), columnPercentWidth, columnPercentTotal,
2349 snapSpaceX(getHgap()), initSize);
2350 }
2351
2352 private int getNodeRowEndConvertRemaining(Node child) {
2353 int rowSpan = getNodeRowSpan(child);
2354 return rowSpan != REMAINING? getNodeRowIndex(child) + rowSpan - 1 : getNumberOfRows() - 1;
2355 }
2356
2357 private int getNodeColumnEndConvertRemaining(Node child) {
2358 int columnSpan = getNodeColumnSpan(child);
2359 return columnSpan != REMAINING? getNodeColumnIndex(child) + columnSpan - 1 : getNumberOfColumns() - 1;
2360 }
2361
2362
2363 // This methods are inteded to be used by GridPaneDesignInfo
2364 private CompositeSize currentHeights;
2365 private CompositeSize currentWidths;
2366
2367 double[][] getGrid() {
2368 if (currentHeights == null || currentWidths == null) {
2369 return null;
2723 int nColumns = this.getColumnConstraints().size();
2724 for (int i = 0; i < this.getChildren().size(); i++) {
2725 Node child = this.getChildren().get(i);
2726 if (child.isManaged()) {
2727 int columnIndex = GridPane.getNodeColumnIndex(child);
2728 int columnEnd = GridPane.getNodeColumnEnd(child);
2729 nColumns = Math.max(nColumns, (columnEnd != GridPane.REMAINING? columnEnd : columnIndex) + 1);
2730 }
2731 }
2732 return nColumns;
2733 }
2734
2735 /**
2736 * Copied from GridPaneDesignInfo for SceneBuilder.
2737 *
2738 * @treatAsPrivate implementation detail
2739 * @deprecated This is an internal API that is not intended for use and will be removed in the next version
2740 */
2741 @Deprecated // SB-dependency: RT-33381 has been filed to track this
2742 public final Bounds impl_getCellBounds(int columnIndex, int rowIndex) {
2743 final double snaphgap = this.snapSpaceX(this.getHgap());
2744 final double snapvgap = this.snapSpaceY(this.getVgap());
2745 final double top = this.snapSpaceY(this.getInsets().getTop());
2746 final double right = this.snapSpaceX(this.getInsets().getRight());
2747 final double bottom = this.snapSpaceY(this.getInsets().getBottom());
2748 final double left = this.snapSpaceX(this.getInsets().getLeft());
2749 final double gridPaneHeight = this.snapSizeY(this.getHeight()) - (top + bottom);
2750 final double gridPaneWidth = this.snapSizeX(this.getWidth()) - (left + right);
2751
2752 // Compute grid. Result contains two double arrays, first for columns, second for rows
2753 double[] columnWidths;
2754 double[] rowHeights;
2755
2756 double[][] grid = this.getGrid();
2757 if (grid == null) {
2758 rowHeights = new double[] {0};
2759 rowIndex = 0;
2760 columnWidths = new double[] {0};
2761 columnIndex = 0;
2762 } else {
2763 columnWidths = grid[0];
2764 rowHeights = grid[1];
2765 }
2766
2767 // Compute the total row height
2768 double rowTotal = 0;
2769 for (int i = 0; i < rowHeights.length; i++) {
2770 rowTotal += rowHeights[i];
|