Spec-Zone .ru
спецификации, руководства, описания, API
|
001/* 002 * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. Oracle designates this 008 * particular file as subject to the "Classpath" exception as provided 009 * by Oracle in the LICENSE file that accompanied this code. 010 * 011 * This code is distributed in the hope that it will be useful, but WITHOUT 012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 014 * version 2 for more details (a copy is included in the LICENSE file that 015 * accompanied this code). 016 * 017 * You should have received a copy of the GNU General Public License version 018 * 2 along with this work; if not, write to the Free Software Foundation, 019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 020 * 021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 022 * or visit www.oracle.com if you need additional information or have any 023 * questions. 024 */ 025 026package javafx.scene.layout; 027 028import com.sun.javafx.geom.Vec2d; 029import java.util.List; 030import javafx.beans.property.ObjectProperty; 031import javafx.beans.property.ObjectPropertyBase; 032import javafx.collections.ListChangeListener; 033import javafx.geometry.HPos; 034import javafx.geometry.Insets; 035import javafx.geometry.Orientation; 036import javafx.geometry.Pos; 037import javafx.geometry.VPos; 038import javafx.scene.Node; 039import static javafx.scene.layout.Region.positionInArea; 040 041 042/** 043 * BorderPane lays out children in top, left, right, bottom, and center positions. 044 * 045 * <p> <img src="doc-files/borderpane.png"/> </p> 046 * 047 * The top and bottom children will be resized to their preferred heights and 048 * extend the width of the border pane. The left and right children will be resized 049 * to their preferred widths and extend the length between the top and bottom nodes. 050 * And the center node will be resized to fill the available space in the middle. 051 * Any of the positions may be null. 052 * 053 * Example: 054 * <pre><code> <b>BorderPane borderPane = new BorderPane();</b> 055 * ToolBar toolbar = new ToolBar(); 056 * HBox statusbar = new HBox(); 057 * Node appContent = new AppContentNode(); 058 * <b>borderPane.setTop(toolbar); 059 * borderPane.setCenter(appContent); 060 * borderPane.setBottom(statusbar);</b> 061 * </code></pre> 062 * <p> 063 * Borderpanes may be styled with backgrounds and borders using CSS. See 064 * {@link javafx.scene.layout.Region Region} superclass for details.</p> 065 * 066 * <p> 067 * BorderPane honors the minimum, preferred, and maximum sizes of its children. 068 * If the child's resizable range prevents it from be resized to fit within its 069 * position, it will be aligned relative to the space using a default alignment 070 * as follows: 071 * <ul> 072 * <li>top: Pos.TOP_LEFT</li> 073 * <li>bottom: Pos.BOTTOM_LEFT</li> 074 * <li>left: Pos.TOP_LEFT</li> 075 * <li>right: Pos.TOP_RIGHT</li> 076 * <li>center: Pos.CENTER</li> 077 * </ul> 078 * See "Optional Layout Constraints" on how to customize these alignments. 079 * 080 * <p> 081 * BorderPane lays out each child set in the five positions regardless of the child's 082 * visible property value; unmanaged children are ignored.</p> 083 * 084 * <h4>Resizable Range</h4> 085 * BorderPane is commonly used as the root of a {@link javafx.scene.Scene Scene}, 086 * in which case its size will track the size of the scene. If the scene or stage 087 * size has not been directly set by the application, the scene size will be 088 * initialized to the border pane's preferred size. However, if a border pane 089 * has a parent other than the scene, that parent will resize the border pane within 090 * the border pane's resizable range during layout. By default the border pane 091 * computes this range based on its content as outlined in the table below. 092 * <p> 093 * <table border="1"> 094 * <tr><td></td><th>width</th><th>height</th></tr> 095 * <tr><th>minimum</th> 096 * <td>left/right insets plus width required to display right/left children at their pref widths and top/bottom/center with at least their min widths</td> 097 * <td>top/bottom insets plus height required to display top/bottom children at their pref heights and left/right/center with at least their min heights</td></tr> 098 * <tr><th>preferred</th> 099 * <td>left/right insets plus width required to display top/right/bottom/left/center children with at least their pref widths</td> 100 * <td>top/bottom insets plus height required to display top/right/bottom/left/center children with at least their pref heights</td></tr> 101 * <tr><th>maximum</th> 102 * <td>Double.MAX_VALUE</td><td>Double.MAX_VALUE</td></tr> 103 * </table> 104 * <p> 105 * A border pane's unbounded maximum width and height are an indication to the parent that 106 * it may be resized beyond its preferred size to fill whatever space is assigned to it. 107 * <p> 108 * BorderPane provides properties for setting the size range directly. These 109 * properties default to the sentinel value Region.USE_COMPUTED_SIZE, however the 110 * application may set them to other values as needed: 111 * <pre><code> 112 * <b>borderPane.setPrefSize(500,400);</b> 113 * </code></pre> 114 * Applications may restore the computed values by setting these properties back 115 * to Region.USE_COMPUTED_SIZE. 116 * <p> 117 * BorderPane does not clip its content by default, so it is possible that childrens' 118 * bounds may extend outside its own bounds if a child's min size prevents it from 119 * being fit within it space.</p> 120 * 121 * <h4>Optional Layout Constraints</h4> 122 * 123 * An application may set constraints on individual children to customize BorderPane's layout. 124 * For each constraint, BorderPane provides a static method for setting it on the child. 125 * <p> 126 * <table border="1"> 127 * <tr><th>Constraint</th><th>Type</th><th>Description</th></tr> 128 * <tr><td>alignment</td><td>javafx.geometry.Pos</td><td>The alignment of the child within its area of the border pane.</td></tr> 129 * <tr><td>margin</td><td>javafx.geometry.Insets</td><td>Margin space around the outside of the child.</td></tr> 130 * </table> 131 * <p> 132 * Example: 133 * <pre><code> ListView list = new ListView(); 134 * <b>BorderPane.setAlignment(list, Pos.TOP_LEFT); 135 * BorderPane.setMargin(list, new Insets(12,12,12,12));</b> 136 * borderPane.setCenter(list); 137 * </code></pre> 138 * 139 */ 140public class BorderPane extends Pane { 141 /******************************************************************** 142 * BEGIN static methods 143 ********************************************************************/ 144 145 private static final String MARGIN = "borderpane-margin"; 146 private static final String ALIGNMENT = "borderpane-alignment"; 147 148 /** 149 * Sets the alignment for the child when contained by a border pane. 150 * If set, will override the border pane's default alignment for the child's position. 151 * Setting the value to null will remove the constraint. 152 * @param child the child node of a border pane 153 * @param value the alignment position for the child 154 */ 155 public static void setAlignment(Node child, Pos value) { 156 setConstraint(child, ALIGNMENT, value); 157 } 158 159 /** 160 * Returns the child's alignment constraint if set. 161 * @param child the child node of a border pane 162 * @return the alignment position for the child or null if no alignment was set 163 */ 164 public static Pos getAlignment(Node child) { 165 return (Pos)getConstraint(child, ALIGNMENT); 166 } 167 168 /** 169 * Sets the margin for the child when contained by a border pane. 170 * If set, the border pane will lay it out with the margin space around it. 171 * Setting the value to null will remove the constraint. 172 * @param child the child node of a border pane 173 * @param value the margin of space around the child 174 */ 175 public static void setMargin(Node child, Insets value) { 176 setConstraint(child, MARGIN, value); 177 } 178 179 /** 180 * Returns the child's margin constraint if set. 181 * @param child the child node of a border pane 182 * @return the margin for the child or null if no margin was set 183 */ 184 public static Insets getMargin(Node child) { 185 return (Insets)getConstraint(child, MARGIN); 186 } 187 188 // convenience for handling null margins 189 private static Insets getNodeMargin(Node child) { 190 Insets margin = getMargin(child); 191 return margin != null ? margin : Insets.EMPTY; 192 } 193 194 /** 195 * Removes all border pane constraints from the child node. 196 * @param child the child node 197 */ 198 public static void clearConstraints(Node child) { 199 setAlignment(child, null); 200 setMargin(child, null); 201 } 202 203 /******************************************************************** 204 * END static methods 205 ********************************************************************/ 206 207 /** 208 * Creates a BorderPane layout. 209 */ 210 public BorderPane() { 211 super(); 212 } 213 214 /** 215 * Creates an BorderPane layout with the given Node as the center of the BorderPane. 216 * @param center The node to set as the center of the BorderPane. 217 */ 218 public BorderPane(Node center) { 219 super(); 220 setCenter(center); 221 } 222 223 /** 224 * Creates an BorderPane layout with the given Nodes to use for each of the main 225 * layout areas of the Border Pane. The top, right, bottom, and left nodes are listed 226 * in clockwise order. 227 * @param center The node to set as the center of the BorderPane. 228 * @param top The node to set as the top of the BorderPane. 229 * @param right The node to set as the right of the BorderPane. 230 * @param bottom The node to set as the bottom of the BorderPane. 231 * @param left The node to set as the left of the BorderPane. 232 */ 233 public BorderPane(Node center, Node top, Node right, Node bottom, Node left) { 234 super(); 235 setCenter(center); 236 setTop(top); 237 setRight(right); 238 setBottom(bottom); 239 setLeft(left); 240 } 241 242 /** 243 * The node placed in the center of this border pane. 244 * If resizable, it will be resized fill the center of the border pane 245 * between the top, bottom, left, and right nodes. If the node cannot be 246 * resized to fill the center space (it's not resizable or its max size prevents 247 * it) then it will be center aligned unless the child's alignment constraint 248 * has been set. 249 */ 250 public final ObjectProperty<Node> centerProperty() { 251 if (center == null) { 252 center = new BorderPositionProperty("center"); 253 } 254 return center; 255 } 256 private ObjectProperty<Node> center; 257 public final void setCenter(Node value) { centerProperty().set(value); } 258 public final Node getCenter() { return center == null ? null : center.get(); } 259 260 /** 261 * The node placed on the top edge of this border pane. 262 * If resizable, it will be resized to its preferred height and it's width 263 * will span the width of the border pane. If the node cannot be 264 * resized to fill the top space (it's not resizable or its max size prevents 265 * it) then it will be aligned top-left within the space unless the child's 266 * alignment constraint has been set. 267 */ 268 public final ObjectProperty<Node> topProperty() { 269 if (top == null) { 270 top = new BorderPositionProperty("top"); 271 } 272 return top; 273 } 274 private ObjectProperty<Node> top; 275 public final void setTop(Node value) { topProperty().set(value); } 276 public final Node getTop() { return top == null ? null : top.get(); } 277 278 /** 279 * The node placed on the bottom edge of this border pane. 280 * If resizable, it will be resized to its preferred height and it's width 281 * will span the width of the border pane. If the node cannot be 282 * resized to fill the bottom space (it's not resizable or its max size prevents 283 * it) then it will be aligned bottom-left within the space unless the child's 284 * alignment constraint has been set. 285 */ 286 public final ObjectProperty<Node> bottomProperty() { 287 if (bottom == null) { 288 bottom = new BorderPositionProperty("bottom"); 289 } 290 return bottom; 291 } 292 private ObjectProperty<Node> bottom; 293 public final void setBottom(Node value) { bottomProperty().set(value); } 294 public final Node getBottom() { return bottom == null ? null : bottom.get(); } 295 296 /** 297 * The node placed on the left edge of this border pane. 298 * If resizable, it will be resized to its preferred width and it's height 299 * will span the height of the border pane between the top and bottom nodes. 300 * If the node cannot be resized to fill the left space (it's not resizable 301 * or its max size prevents it) then it will be aligned top-left within the space 302 * unless the child's alignment constraint has been set. 303 */ 304 public final ObjectProperty<Node> leftProperty() { 305 if (left == null) { 306 left = new BorderPositionProperty("left"); 307 } 308 return left; 309 } 310 private ObjectProperty<Node> left; 311 public final void setLeft(Node value) { leftProperty().set(value); } 312 public final Node getLeft() { return left == null ? null : left.get(); } 313 314 /** 315 * The node placed on the right edge of this border pane. 316 * If resizable, it will be resized to its preferred width and it's height 317 * will span the height of the border pane between the top and bottom nodes. 318 * If the node cannot be resized to fill the right space (it's not resizable 319 * or its max size prevents it) then it will be aligned top-right within the space 320 * unless the child's alignment constraint has been set. 321 */ 322 public final ObjectProperty<Node> rightProperty() { 323 if (right == null) { 324 right = new BorderPositionProperty("right"); 325 } 326 return right; 327 } 328 private ObjectProperty<Node> right; 329 public final void setRight(Node value) { rightProperty().set(value); } 330 public final Node getRight() { return right == null ? null : right.get(); } 331 332 /** 333 * @return null unless the center, right, bottom, left or top has a content bias. 334 */ 335 @Override public Orientation getContentBias() { 336 final Node c = getCenter(); 337 if (c != null && c.isManaged() && c.getContentBias() != null) { 338 return c.getContentBias(); 339 } 340 341 final Node r = getRight(); 342 if (r != null && r.isManaged() && r.getContentBias() == Orientation.VERTICAL) { 343 return r.getContentBias(); 344 } 345 346 final Node l = getLeft(); 347 if (l != null && l.isManaged() && l.getContentBias() == Orientation.VERTICAL) { 348 return l.getContentBias(); 349 } 350 final Node b = getBottom(); 351 if (b != null && b.isManaged() && b.getContentBias() == Orientation.HORIZONTAL) { 352 return b.getContentBias(); 353 } 354 355 final Node t = getTop(); 356 if (t != null && t.isManaged() && t.getContentBias() == Orientation.HORIZONTAL) { 357 return t.getContentBias(); 358 } 359 360 361 return null; 362 } 363 364 @Override protected double computeMinWidth(double height) { 365 double topMinWidth = getAreaWidth(getTop(), -1, true); 366 double bottomMinWidth = getAreaWidth(getBottom(), -1, true); 367 368 double leftPrefWidth; 369 double rightPrefWidth; 370 double centerMinWidth; 371 372 if (height != -1 && (childHasContentBias(getLeft(), Orientation.VERTICAL) || 373 childHasContentBias(getRight(), Orientation.VERTICAL) || 374 childHasContentBias(getCenter(), Orientation.VERTICAL))) { 375 double topPrefHeight = getAreaHeight(getTop(), -1, false); 376 double bottomPrefHeight = getAreaHeight(getBottom(), -1, false); 377 378 double middleAreaHeight = Math.max(0, height - topPrefHeight - bottomPrefHeight); 379 380 leftPrefWidth = getAreaWidth(getLeft(), middleAreaHeight, false); 381 rightPrefWidth = getAreaWidth(getRight(), middleAreaHeight, false); 382 centerMinWidth = getAreaWidth(getCenter(), middleAreaHeight, true); 383 } else { 384 leftPrefWidth = getAreaWidth(getLeft(), -1, false); 385 rightPrefWidth = getAreaWidth(getRight(), -1, false); 386 centerMinWidth = getAreaWidth(getCenter(), -1, true); 387 } 388 389 final Insets insets = getInsets(); 390 return insets.getLeft() + 391 Math.max(leftPrefWidth + centerMinWidth + rightPrefWidth, Math.max(topMinWidth,bottomMinWidth)) + 392 insets.getRight(); 393 } 394 395 @Override protected double computeMinHeight(double width) { 396 final Insets insets = getInsets(); 397 398 // Bottom and top are always at their pref height 399 double topPrefHeight = getAreaHeight(getTop(), width, false); 400 double bottomPrefHeight = getAreaHeight(getBottom(), width, false); 401 402 double leftMinHeight = getAreaHeight(getLeft(), -1, true); 403 double rightMinHeight = getAreaHeight(getRight(), -1, true); 404 405 double centerMinHeight; 406 if (width != -1 && childHasContentBias(getCenter(), Orientation.HORIZONTAL)) { 407 double leftPrefWidth = getAreaWidth(getLeft(), -1, false); 408 double rightPrefWidth = getAreaWidth(getRight(), -1, false); 409 centerMinHeight = getAreaHeight(getCenter(), 410 Math.max(0, width - leftPrefWidth - rightPrefWidth) , true); 411 } else { 412 centerMinHeight = getAreaHeight(getCenter(), -1, true); 413 } 414 415 double middleAreaMinHeigh = Math.max(centerMinHeight, Math.max(rightMinHeight, leftMinHeight)); 416 417 return insets.getTop() + topPrefHeight + middleAreaMinHeigh + bottomPrefHeight + insets.getBottom(); 418 } 419 420 @Override protected double computePrefWidth(double height) { 421 double topPrefWidth = getAreaWidth(getTop(), -1, false); 422 double bottomPrefWidth = getAreaWidth(getBottom(), -1, false); 423 424 double leftPrefWidth; 425 double rightPrefWidth; 426 double centerPrefWidth; 427 428 if ( height != -1 && (childHasContentBias(getLeft(), Orientation.VERTICAL) || 429 childHasContentBias(getRight(), Orientation.VERTICAL) || 430 childHasContentBias(getCenter(), Orientation.VERTICAL))) { 431 double topPrefHeight = getAreaHeight(getTop(), -1, false); 432 double bottomPrefHeight = getAreaHeight(getBottom(), -1, false); 433 434 double middleAreaHeight = Math.max(0, height - topPrefHeight - bottomPrefHeight); 435 436 leftPrefWidth = getAreaWidth(getLeft(), middleAreaHeight, false); 437 rightPrefWidth = getAreaWidth(getRight(), middleAreaHeight, false); 438 centerPrefWidth = getAreaWidth(getCenter(), middleAreaHeight, false); 439 } else { 440 leftPrefWidth = getAreaWidth(getLeft(), -1, false); 441 rightPrefWidth = getAreaWidth(getRight(), -1, false); 442 centerPrefWidth = getAreaWidth(getCenter(), -1, false); 443 } 444 445 final Insets insets = getInsets(); 446 return insets.getLeft() + 447 Math.max(leftPrefWidth + centerPrefWidth + rightPrefWidth, Math.max(topPrefWidth,bottomPrefWidth)) + 448 insets.getRight(); 449 } 450 451 @Override protected double computePrefHeight(double width) { 452 final Insets insets = getInsets(); 453 454 double topPrefHeight = getAreaHeight(getTop(), width, false); 455 double bottomPrefHeight = getAreaHeight(getBottom(), width, false); 456 double leftPrefHeight = getAreaHeight(getLeft(), -1, false); 457 double rightPrefHeight = getAreaHeight(getRight(), -1, false); 458 459 double centerPrefHeight; 460 if (width != -1 && childHasContentBias(getCenter(), Orientation.HORIZONTAL)) { 461 double leftPrefWidth = getAreaWidth(getLeft(), -1, false); 462 double rightPrefWidth = getAreaWidth(getRight(), -1, false); 463 centerPrefHeight = getAreaHeight(getCenter(), 464 Math.max(0, width - leftPrefWidth - rightPrefWidth) , false); 465 } else { 466 centerPrefHeight = getAreaHeight(getCenter(), -1, false); 467 } 468 469 double middleAreaPrefHeigh = Math.max(centerPrefHeight, Math.max(rightPrefHeight, leftPrefHeight)); 470 471 return insets.getTop() + topPrefHeight + middleAreaPrefHeigh + bottomPrefHeight + insets.getBottom(); 472 } 473 474 @Override protected void layoutChildren() { 475 final Insets insets = getInsets(); 476 double width = getWidth(); 477 double height = getHeight(); 478 final Orientation bias = getContentBias(); 479 480 if (bias == null) { 481 final double minWidth = minWidth(-1); 482 final double minHeight = minHeight(-1); 483 width = width < minWidth ? minWidth : width; 484 height = height < minHeight ? minHeight : height; 485 } else if (bias == Orientation.HORIZONTAL) { 486 final double minWidth = minWidth(-1); 487 width = width < minWidth ? minWidth : width; 488 final double minHeight = minHeight(width); 489 height = height < minHeight ? minHeight : height; 490 } else { 491 final double minHeight = minHeight(-1); 492 height = height < minHeight ? minHeight : height; 493 final double minWidth = minWidth(height); 494 width = width < minWidth ? minWidth : width; 495 } 496 497 final double insideX = insets.getLeft(); 498 final double insideY = insets.getTop(); 499 final double insideWidth = width - insideX - insets.getRight(); 500 final double insideHeight = height - insideY - insets.getBottom(); 501 final Node c = getCenter(); 502 final Node r = getRight(); 503 final Node b = getBottom(); 504 final Node l = getLeft(); 505 final Node t = getTop(); 506 507 double topHeight = 0; 508 if (t != null && t.isManaged()) { 509 Insets topMargin = getNodeMargin(t); 510 double adjustedWidth = adjustWidthByMargin(insideWidth, topMargin); 511 double adjustedHeight = adjustHeightByMargin(insideHeight, topMargin); 512 topHeight = snapSize(t.prefHeight(adjustedWidth)); 513 topHeight = Math.min(topHeight, adjustedHeight); 514 Vec2d result = boundedNodeSizeWithBias(t, adjustedWidth, 515 topHeight, true, true, TEMP_VEC2D); 516 topHeight = snapSize(result.y); 517 t.resize(snapSize(result.x), topHeight); 518 519 topHeight = snapSpace(topMargin.getBottom()) + topHeight + snapSpace(topMargin.getTop()); 520 Pos alignment = getAlignment(t); 521 positionInArea(t, insideX, insideY, insideWidth, topHeight, 0/*ignore baseline*/, 522 topMargin, 523 alignment != null? alignment.getHpos() : HPos.LEFT, 524 alignment != null? alignment.getVpos() : VPos.TOP, isSnapToPixel()); 525 } 526 527 double bottomHeight = 0; 528 if (b != null && b.isManaged()) { 529 Insets bottomMargin = getNodeMargin(b); 530 double adjustedWidth = adjustWidthByMargin(insideWidth, bottomMargin); 531 double adjustedHeight = adjustHeightByMargin(insideHeight - topHeight, bottomMargin); 532 bottomHeight = snapSize(b.prefHeight(adjustedWidth)); 533 bottomHeight = Math.min(bottomHeight, adjustedHeight); 534 Vec2d result = boundedNodeSizeWithBias(b, adjustedWidth, 535 bottomHeight, true, true, TEMP_VEC2D); 536 bottomHeight = snapSize(result.y); 537 b.resize(snapSize(result.x), bottomHeight); 538 539 bottomHeight = snapSpace(bottomMargin.getBottom()) + bottomHeight + snapSpace(bottomMargin.getTop()); 540 Pos alignment = getAlignment(b); 541 positionInArea(b, insideX, insideY + insideHeight - bottomHeight, 542 insideWidth, bottomHeight, 0/*ignore baseline*/, 543 bottomMargin, 544 alignment != null? alignment.getHpos() : HPos.LEFT, 545 alignment != null? alignment.getVpos() : VPos.BOTTOM, isSnapToPixel()); 546 } 547 548 double leftWidth = 0; 549 if (l != null && l.isManaged()) { 550 Insets leftMargin = getNodeMargin(l); 551 double adjustedWidth = adjustWidthByMargin(insideWidth, leftMargin); 552 double adjustedHeight = adjustHeightByMargin(insideHeight - topHeight - bottomHeight, leftMargin); // ???? 553 leftWidth = snapSize(l.prefWidth(adjustedHeight)); 554 leftWidth = Math.min(leftWidth, adjustedWidth); 555 Vec2d result = boundedNodeSizeWithBias(l, leftWidth, adjustedHeight, 556 true, true, TEMP_VEC2D); 557 leftWidth = snapSize(result.x); 558 l.resize(leftWidth, snapSize(result.y)); 559 560 leftWidth = snapSpace(leftMargin.getLeft()) + leftWidth + snapSpace(leftMargin.getRight()); 561 Pos alignment = getAlignment(l); 562 positionInArea(l, insideX, insideY + topHeight, 563 leftWidth, insideHeight - topHeight - bottomHeight, 0/*ignore baseline*/, 564 leftMargin, 565 alignment != null? alignment.getHpos() : HPos.LEFT, 566 alignment != null? alignment.getVpos() : VPos.TOP, isSnapToPixel()); 567 } 568 569 double rightWidth = 0; 570 if (r != null && r.isManaged()) { 571 Insets rightMargin = getNodeMargin(r); 572 double adjustedWidth = adjustWidthByMargin(insideWidth - leftWidth, rightMargin); 573 double adjustedHeight = adjustHeightByMargin(insideHeight - topHeight - bottomHeight, rightMargin); 574 575 rightWidth = snapSize(r.prefWidth(adjustedHeight)); 576 rightWidth = Math.min(rightWidth, adjustedWidth); 577 Vec2d result = boundedNodeSizeWithBias(r, rightWidth, adjustedHeight, 578 true, true, TEMP_VEC2D); 579 rightWidth = snapSize(result.x); 580 r.resize(rightWidth, snapSize(result.y)); 581 582 rightWidth = snapSpace(rightMargin.getLeft()) + rightWidth + snapSpace(rightMargin.getRight()); 583 Pos alignment = getAlignment(r); 584 positionInArea(r, insideX + insideWidth - rightWidth, insideY + topHeight, 585 rightWidth, insideHeight - topHeight - bottomHeight, 0/*ignore baseline*/, 586 rightMargin, 587 alignment != null? alignment.getHpos() : HPos.RIGHT, 588 alignment != null? alignment.getVpos() : VPos.TOP, isSnapToPixel()); 589 } 590 591 if (c != null && c.isManaged()) { 592 Pos alignment = getAlignment(c); 593 594 layoutInArea(c, insideX + leftWidth, insideY + topHeight, 595 insideWidth - leftWidth - rightWidth, 596 insideHeight - topHeight - bottomHeight, 0/*ignore baseline*/, 597 getNodeMargin(c), 598 alignment != null? alignment.getHpos() : HPos.CENTER, 599 alignment != null? alignment.getVpos() : VPos.CENTER); 600 } 601 } 602 603 private double getAreaWidth(Node child, double height, boolean minimum) { 604 if (child != null && child.isManaged()) { 605 Insets margin = getNodeMargin(child); 606 return minimum ? computeChildMinAreaWidth(child, margin, height): 607 computeChildPrefAreaWidth(child, margin, height); 608 } 609 return 0; 610 } 611 612 private double getAreaHeight(Node child, double width, boolean minimum) { 613 if (child != null && child.isManaged()) { 614 Insets margin = getNodeMargin(child); 615 return minimum ? computeChildMinAreaHeight(child, margin, width): 616 computeChildPrefAreaHeight(child, margin, width); 617 } 618 return 0; 619 } 620 621 private boolean childHasContentBias(Node child, Orientation orientation) { 622 if (child != null && child.isManaged()) { 623 return child.getContentBias() == orientation; 624 } 625 return false; 626 } 627 628 /*************************************************************************** 629 * * 630 * Private Inner Class * 631 * * 632 **************************************************************************/ 633 634 private final class BorderPositionProperty extends ObjectPropertyBase<Node> { 635 private Node oldValue = null; 636 private final String propertyName; 637 private boolean isBeingInvalidated; 638 639 BorderPositionProperty(String propertyName) { 640 this.propertyName = propertyName; 641 getChildren().addListener(new ListChangeListener<Node>() { 642 643 @Override 644 public void onChanged(ListChangeListener.Change<? extends Node> c) { 645 if (oldValue == null || isBeingInvalidated) { 646 return; 647 } 648 while (c.next()) { 649 if (c.wasRemoved()) { 650 List<? extends Node> removed = c.getRemoved(); 651 for (int i = 0, sz = removed.size(); i < sz; ++i) { 652 if (removed.get(i) == oldValue) { 653 oldValue = null; // Do not remove again in invalidated 654 set(null); 655 } 656 } 657 } 658 } 659 } 660 }); 661 } 662 663 @Override 664 protected void invalidated() { 665 final List<Node> children = getChildren(); 666 667 isBeingInvalidated = true; 668 try { 669 if (oldValue != null) { 670 children.remove(oldValue); 671 } 672 673 final Node _value = get(); 674 this.oldValue = _value; 675 676 if (_value != null) { 677 children.add(_value); 678 } 679 } finally { 680 isBeingInvalidated = false; 681 } 682 } 683 684 @Override 685 public Object getBean() { 686 return BorderPane.this; 687 } 688 689 @Override 690 public String getName() { 691 return propertyName; 692 } 693 } 694}