package bluej.utility.javafx;
|
| This file contains source taken from Oracle JavaFX "FlowPane" class, available under the
|* GPL-with-classpath-exception license as per the original copyright notice above. Modifications
* have been made for use in BlueJ/Greenfoot.
*
* Modified: 2015, 2018.
import javafx.css.SimpleStyleableDoubleProperty;
import javafx.scene.layout.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.DoublePropertyBase;
import javafx.beans.property.ObjectProperty;
import javafx.css.CssMetaData;
import javafx.css.StyleableObjectProperty;
import javafx.css.StyleableProperty;
import javafx.css.converter.EnumConverter;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.Orientation;
import javafx.geometry.Pos;
import javafx.geometry.VPos;
import javafx.scene.Node;
import javafx.css.Styleable;
| FlowPane lays out its children in a flow that wraps at the flowpane's boundary.
|
| A horizontal flowpane (the default) will layout nodes in rows, wrapping at the
| flowpane's width. A vertical flowpane lays out nodes in columns,
| wrapping at the flowpane's height. If the flowpane has a border and/or padding set,
| the content will be flowed within those insets.
|
| FlowPane's prefWrapLength property establishes it's preferred width
| (for horizontal) or preferred height (for vertical). Applications should set
| prefWrapLength if the default value (400) doesn't suffice. Note that prefWrapLength
| is used only for calculating the preferred size and may not reflect the actual
| wrapping dimension, which tracks the actual size of the flowpane.
|
| The alignment property controls how the rows and columns are aligned
| within the bounds of the flowpane and defaults to Pos.TOP_LEFT. It is also possible
| to control the alignment of nodes within the rows and columns by setting
| rowValignment for horizontal or columnHalignment for vertical.
|
| Example of a horizontal flowpane:
| <pre><code> Image images[] = {}... };
| FlowPane flow = new FlowPane();
| flow.setVgap(8);
| flow.setHgap(4);
| flow.setPrefWrapLength(300); // preferred width = 300
| for (int i = 0; i < images.length; i++) {} * flow.getChildren().add(new ImageView(image[i]);
| }
| </code></pre>
|
|<p>
| Example of a vertical flowpane:
| <pre><code> FlowPane flow = new FlowPane(Orientation.VERTICAL);
| flow.setColumnHalignment(HPos.LEFT); // align labels on left
| flow.setPrefWrapLength(200); // preferred height = 200
| for (int i = 0; i < titles.size(); i++) {} * flow.getChildren().add(new Label(titles[i]);
| }
| </code></pre>
|
| FlowPane lays out each managed child regardless of the child's visible property value;
| unmanaged children are ignored for all layout calculations.</p>
|
| FlowPane may be styled with backgrounds and borders using CSS. See
| {}link javafx.scene.layout.Region Region} superclass for details.</p>
|
| <h4>Resizable Range</h4>
|
| A flowpane's parent will resize the flowpane within the flowpane's resizable range
| during layout. By default the flowpane computes this range based on its content
| as outlined in the tables below.
|
| horizontal:
| <table border="1">
|* <tr><td></td><th>width</th><th>height</th></tr>
* <tr><th>minimum</th>
* <td>left/right insets plus largest of children's pref widths</td>
* <td>top/bottom insets plus height required to display all children at their preferred heights when wrapped at a specified width</td></tr>
| <tr><th>preferred</th>
| <td>left/right insets plus prefWrapLength</td>
| <td>top/bottom insets plus height required to display all children at their pref heights when wrapped at a specified width</td></tr>
| <tr><th>maximum</th>
| <td>Double.MAX_VALUE</td><td>Double.MAX_VALUE</td></tr>
| </table>
|
| vertical:
| <table border="1">
|* <tr><td></td><th>width</th><th>height</th></tr>
* <tr><th>minimum</th>
* <td>left/right insets plus width required to display all children at their preferred widths when wrapped at a specified height</td>
| <td>top/bottom insets plus largest of children's pref heights</td><tr>
| <tr><th>preferred</th>
| <td>left/right insets plus width required to display all children at their pref widths when wrapped at the specified height</td>
| <td>top/bottom insets plus prefWrapLength</td><tr>
| <tr><th>maximum</th>
| <td>Double.MAX_VALUE</td><td>Double.MAX_VALUE</td></tr>
| </table>
|
| A flowpane's unbounded maximum width and height are an indication to the parent that
| it may be resized beyond its preferred size to fill whatever space is assigned to it.
|
| FlowPane provides properties for setting the size range directly. These
| properties default to the sentinel value Region.USE_COMPUTED_SIZE, however the
| application may set them to other values as needed:
| <pre><code>
| <b>flowpane.setMaxWidth(500);</b>
| </code></pre>
| Applications may restore the computed values by setting these properties back
| to Region.USE_COMPUTED_SIZE.
|
| FlowPane does not clip its content by default, so it is possible that childrens'
| bounds may extend outside its own bounds if a child's pref size is larger than
| the space flowpane has to allocate for it.</p>
|
| @since JavaFX 2.0
|
public class HangingFlowPane
extends Pane {
/********************************************************************
| BEGIN static methods
|
private static final String MARGIN_CONSTRAINT = "flowpane-margin";
| Sets the margin for the child when contained by a flowpane.
| If set, the flowpane will layout it out with the margin space around it.
| Setting the value to null will remove the constraint.
| @param child the child node of a flowpane
| @param value the margin of space around the child
|
public static void setMargin(Node child, Insets value)
{
FlowPane.setMargin(child, value);
}
| Returns the child's margin constraint if set.
| @param child the child node of a flowpane
| @return the margin for the child or null if no margin was set
|
public static Insets getMargin(Node child)
{
return FlowPane.getMargin(child);
}
| Removes all flowpane constraints from the child node.
| @param child the child node
|
public static void clearConstraints(Node child)
{
setMargin(child, null);
}
/********************************************************************
| END static methods
|
| Creates a horizontal FlowPane layout with hgap/vgap = 0.
|
public HangingFlowPane()
{
super();
getStyleClass().add("hanging-flow-pane");
}
| Creates a horizontal FlowPane layout with hgap/vgap = 0.
| @param children The initial set of children for this pane.
| @since JavaFX 8.0
|
public HangingFlowPane(Node... children)
{
this();
getChildren().addAll(children);
}
private SimpleStyleableDoubleProperty hangingIndentProperty = new SimpleStyleableDoubleProperty(StyleableProperties.HANGING_INDENT, 0.0);
| The amount that each row after the first is indented by.
|
public SimpleStyleableDoubleProperty hangingIndentProperty()
{
return hangingIndentProperty;
}
public void setHangingIndent(double pixels)
{
hangingIndentProperty.set(pixels);
}
| The gap between rows when there are multiple rows
|
private SimpleStyleableDoubleProperty rowSpacingProperty = new SimpleStyleableDoubleProperty(StyleableProperties.ROW_SPACING, 0.0);
| The preferred width where content should wrap in a horizontal flowpane or
| the preferred height where content should wrap in a vertical flowpane.
|
| This value is used only to compute the preferred size of the flowpane and may
| not reflect the actual width or height, which may change if the flowpane is
| resized to something other than its preferred size.
|
| Applications should initialize this value to define a reasonable span
| for wrapping the content.
|
public final DoubleProperty prefWrapLengthProperty()
{
if (prefWrapLength == null) {
prefWrapLength = new DoublePropertyBase(400) {
@Override
protected void invalidated()
{
requestLayout();
}
@Override
public Object getBean()
{
return HangingFlowPane.this;
}
@Override
public String getName()
{
return "prefWrapLength";
}
};
}
return prefWrapLength;
}
private DoubleProperty prefWrapLength;
public final void setPrefWrapLength(double value)
{
prefWrapLengthProperty().set(value);
}
public final double getPrefWrapLength()
{
return prefWrapLength == null ? 400 : prefWrapLength.get();
}
| The overall alignment of the flowpane's content within its width and height.
| <p>For a horizontal flowpane, each row will be aligned within the flowpane's width
| using the alignment's hpos value, and the rows will be aligned within the
| flowpane's height using the alignment's vpos value.
| <p>For a vertical flowpane, each column will be aligned within the flowpane's height
| using the alignment's vpos value, and the columns will be aligned within the
| flowpane's width using the alignment's hpos value.
|
public final ObjectProperty alignmentProperty()
{
if (alignment == null) {
alignment = new StyleableObjectProperty<Pos>(Pos.TOP_LEFT) {
@Override
public void invalidated()
{
requestLayout();
}
@Override
public CssMetaData getCssMetaData()
{
return StyleableProperties.ALIGNMENT;
}
@Override
public Object getBean()
{
return HangingFlowPane.this;
}
@Override
public String getName()
{
return "alignment";
}
};
}
return alignment;
}
private ObjectProperty<Pos> alignment;
public final void setAlignment(Pos value)
{
alignmentProperty().set(value);
}
public final Pos getAlignment()
{
return alignment == null ? Pos.TOP_LEFT : alignment.get();
}
private Pos getAlignmentInternal()
{
Pos localPos = getAlignment();
return localPos == null ? Pos.TOP_LEFT : localPos;
}
| The vertical alignment of nodes within each row of a horizontal flowpane.
| If this property is set to VPos.BASELINE, then the flowpane will always
| resize children to their preferred heights, rather than expanding heights
| to fill the row height.
| The property is ignored for vertical flowpanes.
|
public final ObjectProperty rowValignmentProperty()
{
if (rowValignment == null) {
rowValignment = new StyleableObjectProperty<VPos>(VPos.CENTER) {
@Override
public void invalidated()
{
requestLayout();
}
@Override
public CssMetaData getCssMetaData()
{
return StyleableProperties.ROW_VALIGNMENT;
}
@Override
public Object getBean()
{
return HangingFlowPane.this;
}
@Override
public String getName()
{
return "rowValignment";
}
};
}
return rowValignment;
}
private ObjectProperty<VPos> rowValignment;
public final void setRowValignment(VPos value)
{
rowValignmentProperty().set(value);
}
public final VPos getRowValignment()
{
return rowValignment == null ? VPos.CENTER : rowValignment.get();
}
private VPos getRowValignmentInternal()
{
VPos localPos = getRowValignment();
return localPos == null ? VPos.CENTER : localPos;
}
@Override public Orientation getContentBias()
{
return Orientation.HORIZONTAL;
}
@Override protected double computeMinWidth(double height)
{
double maxPref = 0;
final List<Node> children = getChildren();
for (int i=0, size=children.size(); i<size; i++) {
Node child = children.get(i);
if (child.isManaged()) {
maxPref = Math.max(maxPref, child.prefWidth(-1));
}
}
final Insets insets = getInsets();
return insets.getLeft() + snapSize(maxPref) + insets.getRight();
}
@Override protected double computeMinHeight(double width)
{
return computePrefHeight(width);
}
@Override protected double computePrefWidth(double forHeight)
{
final Insets insets = getInsets();
double maxRunWidth = getPrefWrapLength();
List<Run> hruns = getRuns(maxRunWidth);
double w = computeContentWidth(hruns);
w = getPrefWrapLength() > w ? getPrefWrapLength() : w;
return insets.getLeft() + snapSize(w) + insets.getRight();
}
@Override protected double computePrefHeight(double forWidth)
{
final Insets insets = getInsets();
double maxRunWidth = forWidth != -1?
forWidth - insets.getLeft() - insets.getRight() : getPrefWrapLength();
List<Run> hruns = getRuns(maxRunWidth);
return insets.getTop() + computeContentHeight(hruns) + insets.getBottom();
}
@Override public void requestLayout()
{
if (!computingRuns) {
runs = null;
}
super.requestLayout();
}
private List<Run> runs = null;
private double lastMaxRunLength = -1;
boolean computingRuns = false;
private List getRuns(double maxRunLength)
{
if (runs == null || maxRunLength != lastMaxRunLength) {
computingRuns = true;
lastMaxRunLength = maxRunLength;
runs = new ArrayList();
double runLength = 0;
double runOffset = 0;
Run run = new Run();
double vgap = rowSpacingProperty.get();
double hgap = 0;
final List<Node> children = getChildren();
boolean goingBackwards = false;
int furthestReached = 0;
for (int i=0, size=children.size(); i<size; i++) {
Node child = children.get(i);
if (child.isManaged()) {
LayoutRect nodeRect = new LayoutRect();
nodeRect.node = child;
Insets margin = getMargin(child);
nodeRect.width = computeChildPrefAreaWidth(child, margin);
nodeRect.height = computeChildPrefAreaHeight(child, margin);
nodeRect.alignment = getAlignment(child);
double nodeLength = nodeRect.width;
if (goingBackwards || (runLength + nodeLength > maxRunLength && run.rects.size() >= 1))
{
if (goingBackwards)
{
runLength -= run.rects.get(run.rects.size() - 1).width + hgap;
run.rects.remove(run.rects.size() - 1);
}
if (!canBreakBefore(child) && run.rects.size() > 0 && (goingBackwards || i > furthestReached))
{
furthestReached = Math.max(i, furthestReached);
goingBackwards = true;
i -= 2;
continue;
}
if (run.rects.size() > 0)
{
normalizeRun(run, runOffset);
runOffset += run.height + vgap;
runs.add(run);
runLength = hangingIndentProperty.get();
run = new Run();
}
}
goingBackwards = false;
nodeRect.x = runLength;
runLength += nodeRect.width + hgap;
run.rects.add(nodeRect);
}
}
normalizeRun(run, runOffset);
runs.add(run);
computingRuns = false;
}
return runs;
}
private void normalizeRun(final Run run, double runOffset)
{
ArrayList<Node> rownodes = new ArrayList();
double hgap = 0;
run.width = (run.rects.size()-1)*snapSpace(hgap);
for (int i=0, max=run.rects.size(); i<max; i++) {
LayoutRect lrect = run.rects.get(i);
rownodes.add(lrect.node);
run.width += lrect.width;
lrect.y = runOffset;
}
run.height = computeMaxPrefAreaHeight(rownodes, getRowValignment());
run.baselineOffset = getRowValignment() == VPos.BASELINE?
getAreaBaselineOffset(rownodes, run.rects, run.height, true) : 0;
}
private double computeContentWidth(List<Run> runs)
{
double cwidth = 0;
for (int i=0, max=runs.size(); i<max; i++) {
Run run = runs.get(i);
cwidth = Math.max(cwidth, run.width);
}
return cwidth;
}
private double computeContentHeight(List<Run> runs)
{
double vgap = rowSpacingProperty.get();
double cheight = (runs.size()-1)*snapSpace(vgap);
for (int i=0, max=runs.size(); i<max; i++) {
Run run = runs.get(i);
cheight += run.height;
}
return cheight;
}
@Override protected void layoutChildren()
{
final Insets insets = getInsets();
final double width = getWidth();
final double height = getHeight();
final double top = insets.getTop();
final double left = insets.getLeft();
final double bottom = insets.getBottom();
final double right = insets.getRight();
final double insideWidth = width - left - right;
final double insideHeight = height - top - bottom;
final List<Run> runs = getRuns(insideWidth);
for (int i=0, max=runs.size(); i<max; i++) {
final Run run = runs.get(i);
final double xoffset = left + computeXOffset(insideWidth,
run.width,
getAlignmentInternal().getHpos());
final double yoffset = top + computeYOffset(insideHeight,
computeContentHeight(runs),
getAlignmentInternal().getVpos());
int leftNode = 0;
for (; leftNode < run.rects.size() && run.rects.get(leftNode).alignment == FlowAlignment.LEFT; leftNode++) {
final LayoutRect lrect = run.rects.get(leftNode);
final double x = xoffset + lrect.x;
final double y = yoffset + lrect.y;
layoutInArea(lrect.node, x, y,
lrect.width,
run.height,
run.baselineOffset, getMargin(lrect.node),
HPos.LEFT, getRowValignmentInternal());
}
if (leftNode < run.rects.size())
{
double rightOffset = computeXOffset(insideWidth, 0, HPos.RIGHT) - (run.rects.get(run.rects.size() - 1).x + run.rects.get(run.rects.size() - 1).width);
for (int rightNode = leftNode; rightNode < run.rects.size(); rightNode++)
{
final LayoutRect lrect = run.rects.get(rightNode);
final double x = xoffset + rightOffset + lrect.x;
final double y = yoffset + lrect.y;
layoutInArea(lrect.node, x, y,
lrect.width,
run.height,
run.baselineOffset, getMargin(lrect.node),
HPos.LEFT, getRowValignmentInternal());
}
}
}
}
/***************************************************************************
|
| Stylesheet Handling *
|
| Super-lazy instantiation pattern from Bill Pugh.
| @treatAsPrivate implementation detail
|
private static class StyleableProperties
{
private static final CssMetaData<HangingFlowPane,Pos> ALIGNMENT =
new CssMetaData<HangingFlowPane,Pos>("-fx-alignment",
new EnumConverter<Pos>(Pos.class), Pos.TOP_LEFT) {
@Override
public boolean isSettable(HangingFlowPane node)
{
return node.alignment == null || !node.alignment.isBound();
}
@Override
public StyleableProperty getStyleableProperty(HangingFlowPane node)
{
return (StyleableProperty<Pos>)node.alignmentProperty();
}
};
private static final CssMetaData<HangingFlowPane, Number> HANGING_INDENT = JavaFXUtil.cssSize("-bj-hanging-indent", hfp -> hfp.hangingIndentProperty);
private static final CssMetaData<HangingFlowPane, Number> ROW_SPACING = JavaFXUtil.cssSize("-bj-row-spacing", hfp -> hfp.rowSpacingProperty);
private static final CssMetaData<HangingFlowPane,VPos> ROW_VALIGNMENT =
new CssMetaData<HangingFlowPane,VPos>("-fx-row-valignment",
new EnumConverter<VPos>(VPos.class), VPos.CENTER) {
@Override
public boolean isSettable(HangingFlowPane node)
{
return node.rowValignment == null || !node.rowValignment.isBound();
}
@Override
public StyleableProperty getStyleableProperty(HangingFlowPane node)
{
return (StyleableProperty<VPos>)node.rowValignmentProperty();
}
};
private static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES;
static {
final List<CssMetaData<? extends Styleable, ?>> styleables =
new ArrayList<CssMetaData<? extends Styleable, ?>>(Region.getClassCssMetaData());
styleables.add(ALIGNMENT);
styleables.add(ROW_VALIGNMENT);
styleables.add(HANGING_INDENT);
styleables.add(ROW_SPACING);
STYLEABLES = Collections.unmodifiableList(styleables);
}
}
| @return The CssMetaData associated with this class, which may include the
| CssMetaData of its super classes.
| @since JavaFX 8.0
|
public static List> getClassCssMetaData()
{
return StyleableProperties.STYLEABLES;
}
| {}inheritDoc}
|
| @since JavaFX 8.0
|
@Override
public List> getCssMetaData()
{
return getClassCssMetaData();
}
private static class LayoutRect
{
public Node node;
double x;
double y;
double width;
double height;
FlowAlignment alignment;
@Override public String toString()
{
return "LayoutRect node id="+node.getId()+" "+x+","+y+" "+width+"x"+height;
}
}
private static class Run
{
ArrayList<LayoutRect> rects = new ArrayList();
double width;
double height;
double baselineOffset;
}
p.public static double computeXOffset(double width, double contentWidth, HPos hpos)
{
switch(hpos) {
case LEFT:
return 0;
case CENTER:
return (width - contentWidth) / 2;
case RIGHT:
return width - contentWidth;
default:
throw new AssertionError("Unhandled hPos");
}
}
p.public static double computeYOffset(double height, double contentHeight, VPos vpos)
{
switch(vpos) {
case BASELINE:
case TOP:
return 0;
case CENTER:
return (height - contentHeight) / 2;
case BOTTOM:
return height - contentHeight;
default:
throw new AssertionError("Unhandled vPos");
}
}
double getAreaBaselineOffset(List<Node> children,
ArrayList<LayoutRect> positionToWidth,
double areaHeight, boolean fillHeight) {
return getAreaBaselineOffset(children, positionToWidth, areaHeight, fillHeight, isSnapToPixel());
}
static double getAreaBaselineOffset(List<Node> children,
ArrayList<LayoutRect> positionToWidth,
double areaHeight, boolean fillHeight, boolean snapToPixel) {
return getAreaBaselineOffset(children, positionToWidth, areaHeight, fillHeight,
getMinBaselineComplement(children), snapToPixel);
}
| Returns the baseline offset of provided children, with respect to the minimum complement, computed
| by {}link #getMinBaselineComplement(java.util.List)} from the same set of children.
| @param children the children with baseline alignment
| @param margins their margins (callback)
| @param positionToWidth callback for children widths (can return -1 if no bias is used)
| @param areaHeight height of the area to layout in
| @param fillHeight callback to specify children that has fillHeight constraint
| @param minComplement minimum complement
|
static double getAreaBaselineOffset(List<Node> children,
ArrayList<LayoutRect> positionToWidth,
double areaHeight, boolean fillHeight, double minComplement, boolean snapToPixel) {
double b = 0;
for (int i = 0;i < children.size(); ++i) {
Node n = children.get(i);
Insets margin = getMargin(n);
double top = margin != null? snapSpace(margin.getTop(), snapToPixel) : 0;
double bottom = (margin != null? snapSpace(margin.getBottom(), snapToPixel) : 0);
final double bo = n.getBaselineOffset();
if (bo == BASELINE_OFFSET_SAME_AS_HEIGHT) {
double alt = -1;
if (n.getContentBias() == Orientation.HORIZONTAL) {
alt = positionToWidth.get(i).width;
}
if (fillHeight) {
b = Math.max(b, top + boundedSize(n.minHeight(alt), areaHeight - minComplement - top - bottom,
n.maxHeight(alt)));
}
else {
b = Math.max(b, top + boundedSize(n.minHeight(alt), n.prefHeight(alt),
Math.min(n.maxHeight(alt), areaHeight - minComplement - top - bottom)));
}
}
else {
b = Math.max(b, top + bo);
}
}
return b;
}
| Return the minimum complement of baseline
| @param children
| @return
|
static double getMinBaselineComplement(List<Node> children)
{
return getBaselineComplement(children, true, false);
}
private static double getBaselineComplement(List<Node> children, boolean min, boolean max)
{
double bc = 0;
for (Node n : children) {
final double bo = n.getBaselineOffset();
if (bo == BASELINE_OFFSET_SAME_AS_HEIGHT) {
continue;
}
if (n.isResizable()) {
bc = Math.max(bc, (min ? n.minHeight(-1) : max ? n.maxHeight(-1) : n.prefHeight(-1)) - bo);
}
else {
bc = Math.max(bc, n.getLayoutBounds().getHeight() - bo);
}
}
return bc;
}
p.public static double boundedSize(double min, double pref, double max)
{
double a = pref >= min ? pref : min;
double b = min >= max ? min : max;
return a <= b ? a : b;
}
| If snapToPixel is true, then the value is rounded using Math.round. Otherwise,
| the value is simply returned. This method will surely be JIT'd under normal
| circumstances, however on an interpreter it would be better to inline this
| method. However the use of Math.round here, and Math.ceil in snapSize is
| not obvious, and so for code maintenance this logic is pulled out into
| a separate method.
|
| @param value The value that needs to be snapped
| @param snapToPixel Whether to snap to pixel
| @return value either as passed in or rounded based on snapToPixel
|
private static double snapSpace(double value, boolean snapToPixel)
{
return snapToPixel ? Math.round(value) : value;
}
p.public double computeChildPrefAreaWidth(Node child, Insets margin)
{
return computeChildPrefAreaWidth(child, -1, margin, -1, false);
}
p.public double computeChildPrefAreaWidth(Node child, double baselineComplement, Insets margin, double height, boolean fillHeight)
{
final boolean snap = isSnapToPixel();
double left = margin != null? snapSpace(margin.getLeft(), snap) : 0;
double right = margin != null? snapSpace(margin.getRight(), snap) : 0;
double alt = -1;
if (height != -1 && child.isResizable() && child.getContentBias() == Orientation.VERTICAL) {
double top = margin != null? snapSpace(margin.getTop(), snap) : 0;
double bottom = margin != null? snapSpace(margin.getBottom(), snap) : 0;
double bo = child.getBaselineOffset();
final double contentHeight = bo == BASELINE_OFFSET_SAME_AS_HEIGHT && baselineComplement != -1 ?
height - top - bottom - baselineComplement :
height - top - bottom;
if (fillHeight) {
alt = snapSize(boundedSize(
child.minHeight(-1), contentHeight,
child.maxHeight(-1)));
}
else {
alt = snapSize(boundedSize(
child.minHeight(-1),
child.prefHeight(-1),
Math.min(child.maxHeight(-1), contentHeight)));
}
}
return left + snapSize(boundedSize(child.minWidth(alt), child.prefWidth(alt), child.maxWidth(alt))) + right;
}
p.public double computeChildPrefAreaHeight(Node child, Insets margin)
{
return computeChildPrefAreaHeight(child, -1, margin, -1);
}
p.public double computeChildPrefAreaHeight(Node child, double prefBaselineComplement, Insets margin, double width)
{
final boolean snap = isSnapToPixel();
double top = margin != null? snapSpace(margin.getTop(), snap) : 0;
double bottom = margin != null? snapSpace(margin.getBottom(), snap) : 0;
double alt = -1;
if (child.isResizable() && child.getContentBias() == Orientation.HORIZONTAL) {
double left = margin != null ? snapSpace(margin.getLeft(), snap) : 0;
double right = margin != null ? snapSpace(margin.getRight(), snap) : 0;
alt = snapSize(boundedSize(
child.minWidth(-1), width != -1 ? width - left - right
: child.prefWidth(-1), child.maxWidth(-1)));
}
if (prefBaselineComplement != -1) {
double baseline = child.getBaselineOffset();
if (child.isResizable() && baseline == BASELINE_OFFSET_SAME_AS_HEIGHT) {
return top + snapSize(boundedSize(child.minHeight(alt), child.prefHeight(alt), child.maxHeight(alt))) + bottom
+ prefBaselineComplement;
}
else {
return top + baseline + prefBaselineComplement + bottom;
}
}
else {
return top + snapSize(boundedSize(child.minHeight(alt), child.prefHeight(alt), child.maxHeight(alt))) + bottom;
}
}
double computeMaxPrefAreaHeight(List<Node>children, VPos valignment) {
return getMaxAreaHeight(children, null, valignment, false);
}
| utility method for computing the max of children's min or pref heights, taking into account baseline alignment
|
private double getMaxAreaHeight(List<Node> children, double childWidths[], VPos valignment, boolean minimum)
{
final double singleChildWidth = childWidths == null ? -1 : childWidths.length == 1 ? childWidths[0] : Double.NaN;
if (valignment == VPos.BASELINE) {
double maxAbove = 0;
double maxBelow = 0;
for (int i = 0, maxPos = children.size(); i < maxPos; i++) {
final Node child = children.get(i);
final double childWidth = Double.isNaN(singleChildWidth) ? childWidths[i] : singleChildWidth;
Insets margin = getMargin(child);
final double top = margin != null? snapSpace(margin.getTop()) : 0;
final double bottom = margin != null? snapSpace(margin.getBottom()) : 0;
final double baseline = child.getBaselineOffset();
final double childHeight = minimum? snapSize(child.minHeight(childWidth)) : snapSize(child.prefHeight(childWidth));
if (baseline == BASELINE_OFFSET_SAME_AS_HEIGHT) {
maxAbove = Math.max(maxAbove, childHeight + top);
}
else {
maxAbove = Math.max(maxAbove, baseline + top);
maxBelow = Math.max(maxBelow,
snapSpace(minimum?snapSize(child.minHeight(childWidth)) : snapSize(child.prefHeight(childWidth))) -
baseline + bottom);
}
}
return maxAbove + maxBelow;
}
else {
double max = 0;
for (int i = 0, maxPos = children.size(); i < maxPos; i++) {
final Node child = children.get(i);
Insets margin = getMargin(child);
final double childWidth = Double.isNaN(singleChildWidth) ? childWidths[i] : singleChildWidth;
max = Math.max(max, minimum?
computeChildMinAreaHeight(child, -1, margin, childWidth) :
computeChildPrefAreaHeight(child, -1, margin, childWidth));
}
return max;
}
}
p.public double computeChildMinAreaHeight(Node child, double minBaselineComplement, Insets margin, double width)
{
final boolean snap = isSnapToPixel();
double top =margin != null? snapSpace(margin.getTop(), snap) : 0;
double bottom = margin != null? snapSpace(margin.getBottom(), snap) : 0;
double alt = -1;
if (child.isResizable() && child.getContentBias() == Orientation.HORIZONTAL) {
double left = margin != null? snapSpace(margin.getLeft(), snap) : 0;
double right = margin != null? snapSpace(margin.getRight(), snap) : 0;
alt = snapSize(width != -1? boundedSize(child.minWidth(-1), width - left - right, child.maxWidth(-1)) :
child.maxWidth(-1));
}
if (minBaselineComplement != -1) {
double baseline = child.getBaselineOffset();
if (child.isResizable() && baseline == BASELINE_OFFSET_SAME_AS_HEIGHT) {
return top + snapSize(child.minHeight(alt)) + bottom
+ minBaselineComplement;
}
else {
return baseline + minBaselineComplement;
}
}
else {
return top + snapSize(child.minHeight(alt)) + bottom;
}
}
public static enum FlowAlignment { LEFT, RIGHT
}
private static final String ALIGNMENT = "hangingflowpane-alignment";
| Sets the alignment for the child when contained by a border pane.
| If set, will override the border pane's default alignment for the child's position.
| Setting the value to null will remove the constraint.
| @param child the child node of a border pane
| @param value the alignment position for the child
|
public static void setAlignment(Node child, FlowAlignment value)
{
setConstraint(child, ALIGNMENT, value);
}
private static FlowAlignment getAlignment(Node child)
{
FlowAlignment a = (FlowAlignment)getConstraint(child, ALIGNMENT);
if (a != null)
return a;
else{ return FlowAlignment.LEFT;
}
}
private static final String BREAK_BEFORE = "hangingflowpane-breakbefore";
public static void setBreakBefore(Node child, Boolean canBreakBefore)
{
setConstraint(child, BREAK_BEFORE, canBreakBefore);
}
private static boolean canBreakBefore(Node child)
{
Boolean b = (Boolean)getConstraint(child, BREAK_BEFORE);
if (b == null)
return true;
else{ return b;
}
}
private static void setConstraint(Node node, Object key, Object value)
{
if (value == null) {
node.getProperties().remove(key);
}
else {
node.getProperties().put(key, value);
}
if (node.getParent() != null) {
node.getParent().requestLayout();
}
}
private static Object getConstraint(Node node, Object key)
{
if (node.hasProperties()) {
return node.getProperties().get(key);
}
return null;
}
}
top,
use,
map,
class HangingFlowPane
. setMargin
. getMargin
. clearConstraints
. HangingFlowPane
. HangingFlowPane
. hangingIndentProperty
. setHangingIndent
. prefWrapLengthProperty
. invalidated
. getBean
. getName
. setPrefWrapLength
. getPrefWrapLength
. alignmentProperty
. invalidated
. getCssMetaData
. getBean
. getName
. setAlignment
. getAlignment
. getAlignmentInternal
. rowValignmentProperty
. invalidated
. getCssMetaData
. getBean
. getName
. setRowValignment
. getRowValignment
. getRowValignmentInternal
. getContentBias
. computeMinWidth
. computeMinHeight
. computePrefWidth
. computePrefHeight
. requestLayout
. getRuns
. normalizeRun
. computeContentWidth
. computeContentHeight
. layoutChildren
top,
use,
map,
class StyleableProperties
. isSettable
. getStyleableProperty
. isSettable
. getStyleableProperty
. ?>>
. getClassCssMetaData
. getCssMetaData
top,
use,
map,
class LayoutRect
. toString
top,
use,
map,
class Run
. computeXOffset
. computeYOffset
. getAreaBaselineOffset
. getAreaBaselineOffset
. getMinBaselineComplement
. getBaselineComplement
. boundedSize
. snapSpace
. computeChildPrefAreaWidth
. computeChildPrefAreaWidth
. computeChildPrefAreaHeight
. computeChildPrefAreaHeight
. getMaxAreaHeight
. computeChildMinAreaHeight
. setAlignment
. getAlignment
. setBreakBefore
. canBreakBefore
. setConstraint
. getConstraint
1114 neLoCode
+ 159 LoComm