From 137a61e72be0bdd969cb95d3fd4251a853dc5e81 Mon Sep 17 00:00:00 2001 From: mstr2 <43553916+mstr2@users.noreply.github.com> Date: Tue, 14 Oct 2025 14:54:44 +0200 Subject: [PATCH 1/2] Update HeaderBar API --- .../java/javafx/scene/layout/HeaderBar.java | 242 ++++++++---------- .../javafx/scene/layout/HeaderBarTest.java | 76 +++--- .../fx/monkey/tools/StageTesterWindow.java | 36 +-- 3 files changed, 156 insertions(+), 198 deletions(-) diff --git a/modules/javafx.graphics/src/main/java/javafx/scene/layout/HeaderBar.java b/modules/javafx.graphics/src/main/java/javafx/scene/layout/HeaderBar.java index bfb55f95be7..015d8d14e7d 100644 --- a/modules/javafx.graphics/src/main/java/javafx/scene/layout/HeaderBar.java +++ b/modules/javafx.graphics/src/main/java/javafx/scene/layout/HeaderBar.java @@ -65,7 +65,7 @@ * method. *
* {@code HeaderBar} is a layout container that allows applications to place scene graph nodes in three areas: - * {@link #leadingProperty() leading}, {@link #centerProperty() center}, and {@link #trailingProperty() trailing}. + * {@link #leftProperty() left}, {@link #centerProperty() center}, and {@link #rightProperty() right}. * All areas can be {@code null}. The default {@link #minHeightProperty() minHeight} of the {@code HeaderBar} is * set to match the height of the platform-specific default header buttons. * @@ -80,8 +80,8 @@ * Applications that use multiple header bars might need to configure the additional padding inserted into the * layout to account for the system-reserved areas. For example, when two header bars are placed next to each * other in the horizontal direction, the default configuration incorrectly adds additional padding between the - * two header bars. In this case, the {@link #leadingSystemPaddingProperty() leadingSystemPadding} and - * {@link #trailingSystemPaddingProperty() trailingSystemPadding} properties can be used to remove the padding + * two header bars. In this case, the {@link #leftSystemPaddingProperty() leftSystemPadding} and + * {@link #rightSystemPaddingProperty() rightSystemPadding} properties can be used to remove the padding * that is not needed. * *
- * Note that the left system inset refers to the left side of the window, independent of layout orientation.
*/
private final ReadOnlyObjectWrapper
- * Note that the right system inset refers to the right side of the window, independent of layout orientation.
*/
private final ReadOnlyObjectWrapper
- * The leading area corresponds to the left area in a left-to-right layout, and to the right area
- * in a right-to-left layout.
+ * The left area of the {@code HeaderBar}.
*
* @defaultValue {@code null}
*/
- private final ObjectProperty
- * The trailing area corresponds to the right area in a left-to-right layout, and to the left area
- * in a right-to-left layout.
+ * The right area of the {@code HeaderBar}.
*
* @defaultValue {@code null}
*/
- private final ObjectProperty
* Applications that use a single {@code HeaderBar} extending the entire width of the window should
* set this property to {@code true} to prevent the header buttons from overlapping the content of the
* {@code HeaderBar}.
*
* @defaultValue {@code true}
- * @see #trailingSystemPaddingProperty() trailingSystemPadding
+ * @see #rightSystemPaddingProperty() rightSystemPadding
*/
- private final BooleanProperty leadingSystemPadding = new BooleanPropertyBase(true) {
+ private final BooleanProperty leftSystemPadding = new BooleanPropertyBase(true) {
@Override
public Object getBean() {
return HeaderBar.this;
@@ -543,7 +545,7 @@ public Object getBean() {
@Override
public String getName() {
- return "leadingSystemPadding";
+ return "leftSystemPadding";
}
@Override
@@ -552,32 +554,32 @@ protected void invalidated() {
}
};
- public final BooleanProperty leadingSystemPaddingProperty() {
- return leadingSystemPadding;
+ public final BooleanProperty leftSystemPaddingProperty() {
+ return leftSystemPadding;
}
- public final boolean isLeadingSystemPadding() {
- return leadingSystemPadding.get();
+ public final boolean isLeftSystemPadding() {
+ return leftSystemPadding.get();
}
- public final void setLeadingSystemPadding(boolean value) {
- leadingSystemPadding.set(value);
+ public final void setLeftSystemPadding(boolean value) {
+ leftSystemPadding.set(value);
}
/**
- * Specifies whether additional padding should be added to the trailing side of the {@code HeaderBar}.
+ * Specifies whether additional padding should be added to the right side of the {@code HeaderBar}.
* The size of the additional padding corresponds to the size of the system-reserved area that contains
* the default header buttons (iconify, maximize, and close). If the system-reserved area contains no
- * header buttons, no additional padding is added to the trailing side of the {@code HeaderBar}.
+ * header buttons, no additional padding is added to the right side of the {@code HeaderBar}.
*
* Applications that use a single {@code HeaderBar} extending the entire width of the window should
* set this property to {@code true} to prevent the header buttons from overlapping the content of the
* {@code HeaderBar}.
*
* @defaultValue {@code true}
- * @see #leadingSystemPaddingProperty() leadingSystemPadding
+ * @see #leftSystemPaddingProperty() leftSystemPadding
*/
- private final BooleanProperty trailingSystemPadding = new BooleanPropertyBase(true) {
+ private final BooleanProperty rightSystemPadding = new BooleanPropertyBase(true) {
@Override
public Object getBean() {
return HeaderBar.this;
@@ -585,7 +587,7 @@ public Object getBean() {
@Override
public String getName() {
- return "trailingSystemPadding";
+ return "rightSystemPadding";
}
@Override
@@ -594,153 +596,119 @@ protected void invalidated() {
}
};
- public final BooleanProperty trailingSystemPaddingProperty() {
- return trailingSystemPadding;
- }
-
- public final boolean isTrailingSystemPadding() {
- return trailingSystemPadding.get();
+ public final BooleanProperty rightSystemPaddingProperty() {
+ return rightSystemPadding;
}
- public final void setTrailingSystemPadding(boolean value) {
- trailingSystemPadding.set(value);
+ public final boolean isRightSystemPadding() {
+ return rightSystemPadding.get();
}
- private boolean isLeftSystemPadding(NodeOrientation nodeOrientation) {
- return nodeOrientation == NodeOrientation.LEFT_TO_RIGHT && isLeadingSystemPadding()
- || nodeOrientation == NodeOrientation.RIGHT_TO_LEFT && isTrailingSystemPadding();
- }
-
- private boolean isRightSystemPadding(NodeOrientation nodeOrientation) {
- return nodeOrientation == NodeOrientation.LEFT_TO_RIGHT && isTrailingSystemPadding()
- || nodeOrientation == NodeOrientation.RIGHT_TO_LEFT && isLeadingSystemPadding();
+ public final void setRightSystemPadding(boolean value) {
+ rightSystemPadding.set(value);
}
@Override
protected double computeMinWidth(double height) {
- Node leading = getLeading();
+ Node left = getLeft();
Node center = getCenter();
- Node trailing = getTrailing();
+ Node right = getRight();
Insets insets = getInsets();
double leftPrefWidth;
double rightPrefWidth;
double centerMinWidth;
- double systemPaddingWidth = 0;
if (height != -1
- && (childHasContentBias(leading, Orientation.VERTICAL) ||
- childHasContentBias(trailing, Orientation.VERTICAL) ||
+ && (childHasContentBias(left, Orientation.VERTICAL) ||
+ childHasContentBias(right, Orientation.VERTICAL) ||
childHasContentBias(center, Orientation.VERTICAL))) {
double areaHeight = Math.max(0, height);
- leftPrefWidth = getAreaWidth(leading, areaHeight, false);
- rightPrefWidth = getAreaWidth(trailing, areaHeight, false);
+ leftPrefWidth = getAreaWidth(left, areaHeight, false);
+ rightPrefWidth = getAreaWidth(right, areaHeight, false);
centerMinWidth = getAreaWidth(center, areaHeight, true);
} else {
- leftPrefWidth = getAreaWidth(leading, -1, false);
- rightPrefWidth = getAreaWidth(trailing, -1, false);
+ leftPrefWidth = getAreaWidth(left, -1, false);
+ rightPrefWidth = getAreaWidth(right, -1, false);
centerMinWidth = getAreaWidth(center, -1, true);
}
- NodeOrientation nodeOrientation = getEffectiveNodeOrientation();
-
- if (isLeftSystemPadding(nodeOrientation)) {
- systemPaddingWidth += getLeftSystemInset().getWidth();
- }
-
- if (isRightSystemPadding(nodeOrientation)) {
- systemPaddingWidth += getRightSystemInset().getWidth();
- }
+ double leftSystemPaddingWidth = isLeftSystemPadding() ? getLeftSystemInset().getWidth() : 0;
+ double rightSystemPaddingWidth = isRightSystemPadding() ? getRightSystemInset().getWidth() : 0;
return insets.getLeft()
+ leftPrefWidth
+ centerMinWidth
+ rightPrefWidth
+ insets.getRight()
- + systemPaddingWidth;
+ + leftSystemPaddingWidth
+ + rightSystemPaddingWidth;
}
@Override
protected double computeMinHeight(double width) {
- Node leading = getLeading();
+ Node left = getLeft();
Node center = getCenter();
- Node trailing = getTrailing();
+ Node right = getRight();
Insets insets = getInsets();
- double leadingMinHeight = getAreaHeight(leading, -1, true);
- double trailingMinHeight = getAreaHeight(trailing, -1, true);
+ double leftMinHeight = getAreaHeight(left, -1, true);
+ double rightMinHeight = getAreaHeight(right, -1, true);
double centerMinHeight;
if (width != -1 && childHasContentBias(center, Orientation.HORIZONTAL)) {
- double leadingPrefWidth = getAreaWidth(leading, -1, false);
- double trailingPrefWidth = getAreaWidth(trailing, -1, false);
- centerMinHeight = getAreaHeight(center, Math.max(0, width - leadingPrefWidth - trailingPrefWidth), true);
+ double leftPrefWidth = getAreaWidth(left, -1, false);
+ double rightPrefWidth = getAreaWidth(right, -1, false);
+ centerMinHeight = getAreaHeight(center, Math.max(0, width - leftPrefWidth - rightPrefWidth), true);
} else {
centerMinHeight = getAreaHeight(center, -1, true);
}
return insets.getTop()
+ insets.getBottom()
- + Math.max(centerMinHeight, Math.max(trailingMinHeight, leadingMinHeight));
+ + Math.max(centerMinHeight, Math.max(rightMinHeight, leftMinHeight));
}
@Override
protected double computePrefHeight(double width) {
- Node leading = getLeading();
+ Node left = getLeft();
Node center = getCenter();
- Node trailing = getTrailing();
+ Node right = getRight();
Insets insets = getInsets();
- double leadingPrefHeight = getAreaHeight(leading, -1, false);
- double trailingPrefHeight = getAreaHeight(trailing, -1, false);
+ double leftPrefHeight = getAreaHeight(left, -1, false);
+ double rightPrefHeight = getAreaHeight(right, -1, false);
double centerPrefHeight;
if (width != -1 && childHasContentBias(center, Orientation.HORIZONTAL)) {
- double leadingPrefWidth = getAreaWidth(leading, -1, false);
- double trailingPrefWidth = getAreaWidth(trailing, -1, false);
- centerPrefHeight = getAreaHeight(center, Math.max(0, width - leadingPrefWidth - trailingPrefWidth), false);
+ double leftPrefWidth = getAreaWidth(left, -1, false);
+ double rightPrefWidth = getAreaWidth(right, -1, false);
+ centerPrefHeight = getAreaHeight(center, Math.max(0, width - leftPrefWidth - rightPrefWidth), false);
} else {
centerPrefHeight = getAreaHeight(center, -1, false);
}
return insets.getTop()
+ insets.getBottom()
- + Math.max(centerPrefHeight, Math.max(trailingPrefHeight, leadingPrefHeight));
- }
-
- @Override
- public boolean usesMirroring() {
- return false;
+ + Math.max(centerPrefHeight, Math.max(rightPrefHeight, leftPrefHeight));
}
@Override
protected void layoutChildren() {
+ Node left = getLeft();
Node center = getCenter();
- Node left, right;
+ Node right = getRight();
Insets insets = getInsets();
- NodeOrientation nodeOrientation = getEffectiveNodeOrientation();
- boolean rtl = nodeOrientation == NodeOrientation.RIGHT_TO_LEFT;
double width = Math.max(getWidth(), minWidth(-1));
double height = Math.max(getHeight(), minHeight(-1));
double leftWidth = 0;
double rightWidth = 0;
double insideY = insets.getTop();
double insideHeight = height - insideY - insets.getBottom();
- double insideX, insideWidth;
- double leftSystemPaddingWidth = isLeftSystemPadding(nodeOrientation) ? getLeftSystemInset().getWidth() : 0;
- double rightSystemPaddingWidth = isRightSystemPadding(nodeOrientation) ? getRightSystemInset().getWidth() : 0;
-
- if (rtl) {
- left = getTrailing();
- right = getLeading();
- insideX = insets.getRight() + leftSystemPaddingWidth;
- insideWidth = width - insideX - insets.getLeft() - rightSystemPaddingWidth;
- } else {
- left = getLeading();
- right = getTrailing();
- insideX = insets.getLeft() + leftSystemPaddingWidth;
- insideWidth = width - insideX - insets.getRight() - rightSystemPaddingWidth;
- }
+ double leftSystemPaddingWidth = isLeftSystemPadding() ? getLeftSystemInset().getWidth() : 0;
+ double rightSystemPaddingWidth = isRightSystemPadding() ? getRightSystemInset().getWidth() : 0;
+ double insideX = insets.getLeft() + leftSystemPaddingWidth;
+ double insideWidth = width - insideX - insets.getRight() - rightSystemPaddingWidth;
if (left != null && left.isManaged()) {
- Insets leftMargin = adjustMarginForRTL(getNodeMargin(left), rtl);
+ Insets leftMargin = getNodeMargin(left);
double adjustedWidth = adjustWidthByMargin(insideWidth, leftMargin);
double childWidth = resizeChild(left, adjustedWidth, false, insideHeight, leftMargin);
leftWidth = snapSpaceX(leftMargin.getLeft()) + childWidth + snapSpaceX(leftMargin.getRight());
@@ -756,7 +724,7 @@ protected void layoutChildren() {
}
if (right != null && right.isManaged()) {
- Insets rightMargin = adjustMarginForRTL(getNodeMargin(right), rtl);
+ Insets rightMargin = getNodeMargin(right);
double adjustedWidth = adjustWidthByMargin(insideWidth - leftWidth, rightMargin);
double childWidth = resizeChild(right, adjustedWidth, false, insideHeight, rightMargin);
rightWidth = snapSpaceX(rightMargin.getLeft()) + childWidth + snapSpaceX(rightMargin.getRight());
@@ -772,7 +740,7 @@ protected void layoutChildren() {
}
if (center != null && center.isManaged()) {
- Insets centerMargin = adjustMarginForRTL(getNodeMargin(center), rtl);
+ Insets centerMargin = getNodeMargin(center);
Pos alignment = getAlignment(center);
if (alignment == null || alignment.getHpos() == HPos.CENTER) {
@@ -809,16 +777,6 @@ protected void layoutChildren() {
}
}
- private Insets adjustMarginForRTL(Insets margin, boolean rtl) {
- if (margin == null) {
- return null;
- }
-
- return rtl
- ? new Insets(margin.getTop(), margin.getLeft(), margin.getBottom(), margin.getRight())
- : margin;
- }
-
private boolean childHasContentBias(Node child, Orientation orientation) {
if (child != null && child.isManaged()) {
return child.getContentBias() == orientation;
diff --git a/modules/javafx.graphics/src/test/java/test/javafx/scene/layout/HeaderBarTest.java b/modules/javafx.graphics/src/test/java/test/javafx/scene/layout/HeaderBarTest.java
index 7732f6a58b7..d48b79a1d02 100644
--- a/modules/javafx.graphics/src/test/java/test/javafx/scene/layout/HeaderBarTest.java
+++ b/modules/javafx.graphics/src/test/java/test/javafx/scene/layout/HeaderBarTest.java
@@ -61,9 +61,9 @@ void setup() {
@Test
void emptyHeaderBar() {
- assertNull(headerBar.getLeading());
+ assertNull(headerBar.getLeft());
assertNull(headerBar.getCenter());
- assertNull(headerBar.getTrailing());
+ assertNull(headerBar.getRight());
}
@Test
@@ -91,11 +91,11 @@ class LayoutTest {
"BOTTOM_CENTER, 10, 10, 100, 80",
"BOTTOM_RIGHT, 10, 10, 100, 80"
})
- void alignmentOfLeadingChildOnly_resizable(Pos pos, double x, double y, double width, double height) {
+ void alignmentOfLeftChildOnly_resizable(Pos pos, double x, double y, double width, double height) {
var content = new MockResizable(100, 50);
HeaderBar.setAlignment(content, pos);
HeaderBar.setMargin(content, new Insets(10));
- headerBar.setLeading(content);
+ headerBar.setLeft(content);
headerBar.resize(1000, 100);
headerBar.layout();
@@ -114,11 +114,11 @@ void alignmentOfLeadingChildOnly_resizable(Pos pos, double x, double y, double w
"BOTTOM_CENTER, 10, 40, 100, 50",
"BOTTOM_RIGHT, 10, 40, 100, 50"
})
- void alignmentOfLeadingChildOnly_notResizable(Pos pos, double x, double y, double width, double height) {
+ void alignmentOfLeftChildOnly_notResizable(Pos pos, double x, double y, double width, double height) {
var content = new Rectangle(100, 50);
HeaderBar.setAlignment(content, pos);
HeaderBar.setMargin(content, new Insets(10));
- headerBar.setLeading(content);
+ headerBar.setLeft(content);
headerBar.resize(1000, 100);
headerBar.layout();
@@ -137,11 +137,11 @@ void alignmentOfLeadingChildOnly_notResizable(Pos pos, double x, double y, doubl
"BOTTOM_CENTER, 890, 10, 100, 80",
"BOTTOM_RIGHT, 890, 10, 100, 80"
})
- void alignmentOfTrailingChildOnly_resizable(Pos pos, double x, double y, double width, double height) {
+ void alignmentOfRightChildOnly_resizable(Pos pos, double x, double y, double width, double height) {
var content = new MockResizable(100, 50);
HeaderBar.setAlignment(content, pos);
HeaderBar.setMargin(content, new Insets(10));
- headerBar.setTrailing(content);
+ headerBar.setRight(content);
headerBar.resize(1000, 100);
headerBar.layout();
@@ -160,11 +160,11 @@ void alignmentOfTrailingChildOnly_resizable(Pos pos, double x, double y, double
"BOTTOM_CENTER, 890, 40, 100, 50",
"BOTTOM_RIGHT, 890, 40, 100, 50"
})
- void alignmentOfTrailingChildOnly_notResizable(Pos pos, double x, double y, double width, double height) {
+ void alignmentOfRightChildOnly_notResizable(Pos pos, double x, double y, double width, double height) {
var content = new Rectangle(100, 50);
HeaderBar.setAlignment(content, pos);
HeaderBar.setMargin(content, new Insets(10));
- headerBar.setTrailing(content);
+ headerBar.setRight(content);
headerBar.resize(1000, 100);
headerBar.layout();
@@ -230,16 +230,16 @@ void alignmentOfCenterChildOnly_notResizable(Pos pos, double x, double y, double
"BOTTOM_CENTER, 400, 10, 200, 80",
"BOTTOM_RIGHT, 640, 10, 200, 80"
})
- void alignmentOfCenterChild_resizable_withNonEmptyLeadingAndTrailingChild(
+ void alignmentOfCenterChild_resizable_withNonEmptyLeftAndRightChild(
Pos pos, double x, double y, double width, double height) {
- var leading = new MockResizable(50, 50);
+ var left = new MockResizable(50, 50);
var center = new MockResizable(0, 0, 100, 50, 200, 100);
- var trailing = new MockResizable(150, 50);
+ var right = new MockResizable(150, 50);
HeaderBar.setAlignment(center, pos);
HeaderBar.setMargin(center, new Insets(10));
- headerBar.setLeading(leading);
+ headerBar.setLeft(left);
headerBar.setCenter(center);
- headerBar.setTrailing(trailing);
+ headerBar.setRight(right);
headerBar.resize(1000, 100);
headerBar.layout();
@@ -258,16 +258,16 @@ void alignmentOfCenterChild_resizable_withNonEmptyLeadingAndTrailingChild(
"BOTTOM_CENTER, 450, 40, 100, 50",
"BOTTOM_RIGHT, 740, 40, 100, 50"
})
- void alignmentOfCenterChild_notResizable_withNonEmptyLeadingAndTrailingChild(
+ void alignmentOfCenterChild_notResizable_withNonEmptyLeftAndRightChild(
Pos pos, double x, double y, double width, double height) {
- var leading = new Rectangle(50, 50);
+ var left = new Rectangle(50, 50);
var center = new Rectangle(100, 50);
- var trailing = new Rectangle(150, 50);
+ var right = new Rectangle(150, 50);
HeaderBar.setAlignment(center, pos);
HeaderBar.setMargin(center, new Insets(10));
- headerBar.setLeading(leading);
+ headerBar.setLeft(left);
headerBar.setCenter(center);
- headerBar.setTrailing(trailing);
+ headerBar.setRight(right);
headerBar.resize(1000, 100);
headerBar.layout();
@@ -376,14 +376,14 @@ void alignmentOfCenterChild_withRightSystemInset_andOffsetCausedByInsufficientHo
private void alignmentOfCenterChildImpl(Pos pos, double headerBarWidth, double maxWidth,
double x, double y, double width, double height) {
- var leading = new MockResizable(50, 50);
+ var left = new MockResizable(50, 50);
var center = new MockResizable(0, 0, 100, 50, maxWidth, 100);
- var trailing = new MockResizable(150, 50);
+ var right = new MockResizable(150, 50);
HeaderBar.setAlignment(center, pos);
HeaderBar.setMargin(center, new Insets(10));
- headerBar.setLeading(leading);
+ headerBar.setLeft(left);
headerBar.setCenter(center);
- headerBar.setTrailing(trailing);
+ headerBar.setRight(right);
headerBar.resize(headerBarWidth, 100);
headerBar.layout();
@@ -396,19 +396,19 @@ private void alignmentOfCenterChildImpl(Pos pos, double headerBarWidth, double m
"CENTER, 10, 25, 50, 50",
"BOTTOM_LEFT, 10, 40, 50, 50"
})
- void alignmentOfLeadingChild_notResizable_withoutReservedArea(
+ void alignmentOfLeftChild_notResizable_withoutReservedArea(
Pos pos, double x, double y, double width, double height) {
ObjectProperty
+ * By default, {@code HeaderBar}.{@link #minHeightProperty() minHeight} is set to the value of
+ * {@code minSystemHeight}, unless {@code minHeight} is explicitly set by a stylesheet or application code.
+ *
+ * @param stage the {@code Stage}
+ * @return the {@code minSystemHeight} property
+ */
+ public static ReadOnlyDoubleProperty minSystemHeightProperty(Stage stage) {
+ return AttachedProperties.of(stage).minSystemHeight.getReadOnlyProperty();
+ }
+
+ /**
+ * Gets the value of the {@link #minSystemHeightProperty(Stage) minSystemHeight} property.
+ *
+ * @param stage the {@code Stage}
+ * @return the system-provided minimum recommended height for the {@code HeaderBar}
+ */
+ public static double getMinSystemHeight(Stage stage) {
+ return AttachedProperties.of(stage).minSystemHeight.get();
+ }
+
/**
* Sets the alignment for the child when contained in a {@code HeaderBar}.
* If set, will override the header bar's default alignment for the child's position.
@@ -320,9 +391,7 @@ public static Insets getMargin(Node child) {
return (Insets)Pane.getConstraint(child, MARGIN);
}
- private Subscription subscription = Subscription.EMPTY;
- private HeaderButtonMetrics currentMetrics;
- private boolean currentFullScreen;
+ private Subscription subscriptions = Subscription.EMPTY;
/**
* Creates a new {@code HeaderBar}.
@@ -334,17 +403,10 @@ public HeaderBar() {
// user code changes the property value before we set it to the height of the native title bar.
minHeightProperty();
- effectiveNodeOrientationProperty().subscribe(this::updateInsets);
-
- ObservableValue
- * By default, {@link #minHeightProperty() minHeight} is set to the value of {@code minSystemHeight},
- * unless {@code minHeight} is explicitly set by a stylesheet or application code.
- */
- private final ReadOnlyDoubleWrapper minSystemHeight =
- new ReadOnlyDoubleWrapper(this, "minSystemHeight") {
- @Override
- protected void invalidated() {
- double height = get();
- var minHeight = (StyleableDoubleProperty)minHeightProperty();
-
- // Only change minHeight if it was not set by a stylesheet or application code.
- if (minHeight.getStyleOrigin() == null) {
- minHeight.applyStyle(null, height);
- }
- }
- };
-
- public final ReadOnlyDoubleProperty minSystemHeightProperty() {
- return minSystemHeight.getReadOnlyProperty();
- }
-
- public final double getMinSystemHeight() {
- return minSystemHeight.get();
- }
-
/**
* The left area of the {@code HeaderBar}.
*
@@ -617,6 +573,8 @@ protected double computeMinWidth(double height) {
double leftPrefWidth;
double rightPrefWidth;
double centerMinWidth;
+ double leftSystemPaddingWidth = 0;
+ double rightSystemPaddingWidth = 0;
if (height != -1
&& (childHasContentBias(left, Orientation.VERTICAL) ||
@@ -632,8 +590,22 @@ protected double computeMinWidth(double height) {
centerMinWidth = getAreaWidth(center, -1, true);
}
- double leftSystemPaddingWidth = isLeftSystemPadding() ? getLeftSystemInset().getWidth() : 0;
- double rightSystemPaddingWidth = isRightSystemPadding() ? getRightSystemInset().getWidth() : 0;
+ Scene scene = getScene();
+ Stage stage = scene != null
+ ? scene.getWindow() instanceof Stage s ? s : null
+ : null;
+
+ if (stage != null) {
+ var attachedProperties = AttachedProperties.of(stage);
+
+ if (scene.getEffectiveNodeOrientation() != getEffectiveNodeOrientation()) {
+ leftSystemPaddingWidth = isLeftSystemPadding() ? attachedProperties.rightSystemInset.get().getWidth() : 0;
+ rightSystemPaddingWidth = isRightSystemPadding() ? attachedProperties.leftSystemInset.get().getWidth() : 0;
+ } else {
+ leftSystemPaddingWidth = isLeftSystemPadding() ? attachedProperties.leftSystemInset.get().getWidth() : 0;
+ rightSystemPaddingWidth = isRightSystemPadding() ? attachedProperties.rightSystemInset.get().getWidth() : 0;
+ }
+ }
return insets.getLeft()
+ leftPrefWidth
@@ -702,8 +674,26 @@ protected void layoutChildren() {
double rightWidth = 0;
double insideY = insets.getTop();
double insideHeight = height - insideY - insets.getBottom();
- double leftSystemPaddingWidth = isLeftSystemPadding() ? getLeftSystemInset().getWidth() : 0;
- double rightSystemPaddingWidth = isRightSystemPadding() ? getRightSystemInset().getWidth() : 0;
+ double rightSystemPaddingWidth = 0;
+ double leftSystemPaddingWidth = 0;
+
+ Scene scene = getScene();
+ Stage stage = scene != null
+ ? scene.getWindow() instanceof Stage s ? s : null
+ : null;
+
+ if (stage != null) {
+ AttachedProperties attachedProperties = AttachedProperties.of(stage);
+
+ if (scene.getEffectiveNodeOrientation() != getEffectiveNodeOrientation()) {
+ leftSystemPaddingWidth = isLeftSystemPadding() ? attachedProperties.rightSystemInset.get().getWidth() : 0;
+ rightSystemPaddingWidth = isRightSystemPadding() ? attachedProperties.leftSystemInset.get().getWidth() : 0;
+ } else {
+ leftSystemPaddingWidth = isLeftSystemPadding() ? attachedProperties.leftSystemInset.get().getWidth() : 0;
+ rightSystemPaddingWidth = isRightSystemPadding() ? attachedProperties.rightSystemInset.get().getWidth() : 0;
+ }
+ }
+
double insideX = insets.getLeft() + leftSystemPaddingWidth;
double insideWidth = width - insideX - insets.getRight() - rightSystemPaddingWidth;
@@ -822,6 +812,26 @@ private Insets getNodeMargin(Node child) {
return margin != null ? margin : Insets.EMPTY;
}
+ private void onStageChanged(Stage stage) {
+ subscriptions.unsubscribe();
+
+ if (stage != null) {
+ var attachedProperties = AttachedProperties.of(stage);
+
+ subscriptions = Subscription.combine(
+ attachedProperties.minSystemHeight.subscribe(height -> {
+ var minHeight = (StyleableDoubleProperty)minHeightProperty();
+
+ // Only change minHeight if it was not set by a stylesheet or application code.
+ if (minHeight.getStyleOrigin() == null) {
+ minHeight.applyStyle(null, height);
+ }
+ }),
+ attachedProperties.subscribeLayoutInvalidated(this::requestLayout)
+ );
+ }
+ }
+
private final class NodeProperty extends ObjectPropertyBaseSingle header bar
* Most applications should only add a single {@code HeaderBar} to the scene graph, placed at the top of the
* scene and extending its entire width. This ensures that the reported values for
- * {@link #leftSystemInsetProperty() leftSystemInset} and {@link #rightSystemInsetProperty() rightSystemInset},
+ * {@link #leftSystemInsetProperty(Stage) leftSystemInset} and {@link #rightSystemInsetProperty(Stage) rightSystemInset},
* which describe the area reserved for the system-provided window buttons, correctly align with the location
* of the {@code HeaderBar} and are taken into account when the contents of the {@code HeaderBar} are laid out.
*
@@ -276,6 +278,75 @@ public static double getPrefButtonHeight(Stage stage) {
return StageHelper.getPrefHeaderButtonHeight(stage);
}
+ /**
+ * Describes the size of the left system-reserved inset, which is an area reserved for the iconify, maximize,
+ * and close window buttons. If there are no window buttons on the left side of the window, the returned area
+ * is an empty {@code Dimension2D}.
+ *
+ * @param stage the {@code Stage}
+ * @return the {@code leftSystemInset} property
+ */
+ public static ReadOnlyObjectProperty