--- a/modules/javafx.graphics/src/main/java/javafx/scene/layout/HeaderBar.java +++ b/modules/javafx.graphics/src/main/java/javafx/scene/layout/HeaderBar.java + +/** + * A client-area header bar that is used as a replacement for the system-provided header bar in stages + * with the {@link StageStyle#EXTENDED} style. This class enables the click-and-drag to move and + * double-click to maximize behaviors that are usually afforded by system-provided header bars. + * The entire {@code HeaderBar} background is draggable by default, but its content is not. Applications + * can specify draggable content nodes of the {@code HeaderBar} with the {@link #setDragType(Node, HeaderDragType)} + * 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}. + * 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. + * + *

Single 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}, + * 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. + * + *

Multiple header bars

+ * 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 + * that is not needed. + * + *

Header button height

+ * Applications can specify the preferred height for system-provided header buttons by setting the static + * {@link #setPrefButtonHeight(Stage, double)} property on the {@code Stage} associated with the header bar. + * This can be used to achieve a more cohesive visual appearance by having the system-provided header buttons + * match the height of the client-area header bar. + * + *

Custom header buttons

+ * If more control over the header buttons is desired, applications can opt out of the system-provided header + * buttons by setting {@link #setPrefButtonHeight(Stage, double)} to zero and place custom header buttons in + * the JavaFX scene graph instead. Any JavaFX control can be used as a custom header button by setting its + * semantic type with the {@link #setButtonType(Node, HeaderButtonType)} method. + * + *

System menu

+ * Some platforms support a system menu that can be summoned by right-clicking the draggable area. + * The system menu will not be shown when: + *
    + *
  1. the {@code Stage} is in {@link Stage#fullScreenProperty() full-screen mode}, or + *
  2. the {@code HeaderBar} has {@link Event#consume() consumed} the + * {@link ContextMenuEvent#CONTEXT_MENU_REQUESTED} event. + *
+ * + *

Layout constraints

+ * The {@code leading} and {@code trailing} children will be resized to their preferred widths and extend the + * height of the {@code HeaderBar}. The {@code center} child will be resized to fill the available space. + * {@code HeaderBar} honors the minimum, preferred, and maximum sizes of its children. If a child's resizable + * range prevents it from be resized to fit within its position, it will be vertically centered relative to the + * available space; this alignment can be customized with a layout constraint. + *

+ * An application may set constraints on individual children to customize their layout. + * For each constraint, {@code HeaderBar} provides static getter and setter methods. + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Layout constraints of {@code HeaderBar}
ConstraintTypeDescription
alignment{@link Pos}The alignment of the child within its area of the {@code HeaderBar}.
margin{@link Insets}Margin space around the outside of the child.
+ * + *

Special layout of centered child

+ * If a child is configured to be centered in the {@link #centerProperty() center} area (i.e. its {@code alignment} + * constraint is either {@code null}, {@link Pos#CENTER}, {@link Pos#TOP_CENTER}, or {@link Pos#BOTTOM_CENTER}), + * it will be centered with respect to the entire header bar, and not with respect to the {@code center} area only. + * This means that, for a header bar that extends the entire width of the {@code Stage}, the child will appear to + * be horizontally centered within the {@code Stage}. + *

+ * If a child should instead be centered with respect to the {@code center} area only, a possible solution is to + * place another layout container like {@link BorderPane} in the {@code center} area, and then center the child + * within the other layout container. + * + *

Example

+ * Usually, {@code HeaderBar} is placed in a root container like {@code BorderPane} to align it + * with the top of the scene: + *
{@code
+ * public class MyApp extends Application {
+ *     @Override
+ *     public void start(Stage stage) {
+ *         var button = new Button("My button");
+ *         HeaderBar.setAlignment(button, Pos.CENTER_LEFT);
+ *         HeaderBar.setMargin(button, new Insets(5));
+ *
+ *         var headerBar = new HeaderBar();
+ *         headerBar.setCenter(button);
+ *
+ *         var root = new BorderPane();
+ *         root.setTop(headerBar);
+ *
+ *         stage.setScene(new Scene(root));
+ *         stage.initStyle(StageStyle.EXTENDED);
+ *         stage.show();
+ *     }
+ * }
+ * }
+ * + * @since 25 + * @deprecated This is a preview feature which may be changed or removed in a future release. + */ +@Deprecated(since = "25") +public class HeaderBar extends Region { + + /** + * Specifies the {@code HeaderDragType} of the child, indicating whether it is a draggable + * part of the {@code HeaderBar}. + *

+ * Setting the value to {@code null} will remove the flag. + * + * @param child the child node + * @param value the {@code HeaderDragType}, or {@code null} to remove the flag + */ + public static void setDragType(Node child, HeaderDragType value); + + /** + * Returns the {@code HeaderDragType} of the specified child. + * + * @param child the child node + * @return the {@code HeaderDragType}, or {@code null} if not set + */ + public static HeaderDragType getDragType(Node child); + + /** + * Specifies the {@code HeaderButtonType} of the child, indicating its semantic use in the header bar. + *

+ * This property can be set on any {@link Node}. Specifying a header button type also provides the behavior + * associated with the button type. If the default behavior is not desired, applications can register an + * event filter on the child node that consumes the {@link MouseEvent#MOUSE_RELEASED} event. + * + * @param child the child node + * @param value the {@code HeaderButtonType}, or {@code null} + */ + public static void setButtonType(Node child, HeaderButtonType value); + + /** + * Returns the {@code HeaderButtonType} of the specified child. + * + * @param child the child node + * @return the {@code HeaderButtonType}, or {@code null} + */ + public static HeaderButtonType getButtonType(Node child); + + /** + * Sentinel value that can be used for {@link #setPrefButtonHeight(Stage, double)} to indicate that + * the platform should choose the platform-specific default button height. + */ + public static final double USE_DEFAULT_SIZE = -1; + + /** + * Specifies the preferred height of the system-provided header buttons of the specified stage. + *

+ * Any value except zero and {@link #USE_DEFAULT_SIZE} is only a hint for the platform window toolkit. + * The platform might accommodate the preferred height in various ways, such as by stretching the header + * buttons (fully or partially) to fill the preferred height, or centering the header buttons (fully or + * partially) within the preferred height. Some platforms might only accommodate the preferred height + * within platform-specific constraints, or ignore it entirely. + *

+ * Setting the preferred height to zero hides the system-provided header buttons, allowing applications to + * use custom header buttons instead (see {@link #setButtonType(Node, HeaderButtonType)}). + *

+ * The default value {@code #USE_DEFAULT_SIZE} indicates that the platform should choose the button height. + * + * @param stage the {@code Stage} + * @param height the preferred height, or 0 to hide the system-provided header buttons + */ + public static void setPrefButtonHeight(Stage stage, double height); + + /** + * Returns the preferred height of the system-provided header buttons of the specified stage. + * + * @param stage the {@code Stage} + * @return the preferred height of the system-provided header buttons + */ + public static double getPrefButtonHeight(Stage stage); + + /** + * 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. + * Setting the value to {@code null} will remove the constraint. + * + * @param child the child node + * @param value the alignment position + */ + public static void setAlignment(Node child, Pos value); + + /** + * Returns the child's alignment in the {@code HeaderBar}. + * + * @param child the child node + * @return the alignment position for the child, or {@code null} if no alignment was set + */ + public static Pos getAlignment(Node child); + + /** + * Sets the margin for the child when contained in a {@code HeaderBar}. + * If set, the header bar will lay it out with the margin space around it. + * Setting the value to {@code null} will remove the constraint. + * + * @param child the child node + * @param value the margin of space around the child + */ + public static void setMargin(Node child, Insets value); + + /** + * Returns the child's margin. + * + * @param child the child node + * @return the margin for the child, or {@code null} if no margin was set + */ + public static Insets getMargin(Node child); + + /** + * Creates a new {@code HeaderBar}. + */ + public HeaderBar(); + + /** + * Creates a new {@code HeaderBar} with the specified children. + * + * @param leading the leading node + * @param center the center node + * @param trailing the trailing node + */ + public HeaderBar(Node leading, Node center, Node trailing); + + /** + * 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}. + *

+ * Note that the left system inset refers to the left side of the window, independent of layout orientation. + */ + private final ReadOnlyObjectWrapper leftSystemInset; + + public final ReadOnlyObjectProperty leftSystemInsetProperty(); + + public final Dimension2D getLeftSystemInset(); + + /** + * Describes the size of the right system-reserved inset, which is an area reserved for the iconify, maximize, + * and close window buttons. If there are no window buttons on the right side of the window, the returned area + * is an empty {@code Dimension2D}. + *

+ * Note that the right system inset refers to the right side of the window, independent of layout orientation. + */ + private final ReadOnlyObjectWrapper rightSystemInset; + + public final ReadOnlyObjectProperty rightSystemInsetProperty(); + + public final Dimension2D getRightSystemInset(); + + /** + * The system-provided minimum recommended height for the {@code HeaderBar}, which usually corresponds + * to the height of the default header buttons. Applications can use this value as a sensible lower limit + * for the height of the {@code HeaderBar}. + *

+ * 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; + + public final ReadOnlyDoubleProperty minSystemHeightProperty(); + + public final double getMinSystemHeight(); + + /** + * The leading area of the {@code HeaderBar}. + *

+ * 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. + * + * @defaultValue {@code null} + */ + private final ObjectProperty leading; + + public final ObjectProperty leadingProperty(); + + public final Node getLeading(); + + public final void setLeading(Node value); + + /** + * The center area of the {@code HeaderBar}. + * + * @defaultValue {@code null} + */ + private final ObjectProperty center; + + public final ObjectProperty centerProperty(); + + public final Node getCenter(); + + public final void setCenter(Node value); + + /** + * The trailing area of the {@code HeaderBar}. + *

+ * 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. + * + * @defaultValue {@code null} + */ + private final ObjectProperty trailing; + + public final ObjectProperty trailingProperty(); + + public final Node getTrailing(); + + public final void setTrailing(Node value); + + /** + * Specifies whether additional padding should be added to the leading 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 leading 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 #trailingSystemPaddingProperty() trailingSystemPadding + */ + private final BooleanProperty leadingSystemPadding; + + public final BooleanProperty leadingSystemPaddingProperty(); + + public final boolean isLeadingSystemPadding(); + + public final void setLeadingSystemPadding(boolean value); + + /** + * Specifies whether additional padding should be added to the trailing 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}. + *

+ * 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 + */ + private final BooleanProperty trailingSystemPadding; + + public final BooleanProperty trailingSystemPaddingProperty(); + + public final boolean isTrailingSystemPadding(); + + public final void setTrailingSystemPadding(boolean value); +} --- a/modules/javafx.graphics/src/main/java/javafx/scene/layout/HeaderButtonType.java +++ b/modules/javafx.graphics/src/main/java/javafx/scene/layout/HeaderButtonType.java + +/** + * Identifies the semantic type of a button in a custom {@link HeaderBar}, which enables integrations + * with the platform window manager. For example, hovering over a {@link #MAXIMIZE} button on Windows + * will summon snap layouts. + * + * @since 25 + * @deprecated This is a preview feature which may be changed or removed in a future release. + * @see HeaderBar#setButtonType(Node, HeaderButtonType) + */ +@Deprecated(since = "25") +public enum HeaderButtonType { + + /** + * Identifies the iconify button. + * + * @see Stage#isIconified() + * @see Stage#setIconified(boolean) + */ + ICONIFY, + + /** + * Identifies the maximize button. + *

+ * This button toggles the {@link Stage#isMaximized()} or {@link Stage#isFullScreen()} property, + * depending on platform-specific invocation semantics. For example, on macOS the button will + * put the window into full-screen mode by default, but maximize it to cover the desktop when + * the option key is pressed. + *

+ * If the window is maximized, the button will have the {@code maximized} pseudo-class. + * + * @see Stage#isMaximized() + * @see Stage#setMaximized(boolean) + * @see Stage#isFullScreen() + * @see Stage#setFullScreen(boolean) + */ + MAXIMIZE, + + /** + * Identifies the close button. + * + * @see Stage#close() + */ + CLOSE +} --- a/modules/javafx.graphics/src/main/java/javafx/scene/layout/HeaderDragType.java +++ b/modules/javafx.graphics/src/main/java/javafx/scene/layout/HeaderDragType.java + +/** + * Specifies whether a node is a draggable part of a {@link HeaderBar}. + * + * @since 25 + * @deprecated This is a preview feature which may be changed or removed in a future release. + * @see HeaderBar#setDragType(Node, HeaderDragType) + */ +@Deprecated(since = "25") +public enum HeaderDragType { + + /** + * The node is not a draggable part of the {@code HeaderBar}. + *

+ * If the node inherits {@link #DRAGGABLE_SUBTREE} from its parent, the inheritance stops and + * descendants of the node will not inherit {@code DRAGGABLE_SUBTREE}. + */ + NONE, + + /** + * The node is a draggable part of the {@code HeaderBar}. + *

+ * This drag type does not apply to descendants of the node. However, it does not stop an inherited + * {@link #DRAGGABLE_SUBTREE} drag type from being inherited by descendants of the node. + */ + DRAGGABLE, + + /** + * The node and its descendants are a draggable part of the {@code HeaderBar}. + *

+ * This drag type is inherited by descendants of the node until a descendant specifies {@link #NONE}. + */ + DRAGGABLE_SUBTREE +} --- a/modules/javafx.graphics/src/main/java/javafx/stage/StageStyle.java +++ b/modules/javafx.graphics/src/main/java/javafx/stage/StageStyle.java @@ -74,6 +82,60 @@ * NOTE: To see the effect, the {@code Scene} covering the {@code Stage} should have {@code Color.TRANSPARENT} * @since JavaFX 8.0 */ - UNIFIED + UNIFIED, + + /** + * Defines a {@code Stage} style in which the client area is extended into the header bar area, removing + * the separation between the two areas and allowing applications to place scene graph nodes in the header + * bar area of the stage. + *

+ * This is a conditional feature, to check if it is supported see {@link Platform#isSupported(ConditionalFeature)}. + * If the feature is not supported by the platform, this style downgrades to {@link StageStyle#DECORATED}. + * + *

Usage

+ * An extended window has the default header buttons (iconify, maximize, close), but no system-provided + * draggable header bar. Applications need to provide their own header bar by placing a {@link HeaderBar} + * control in the scene graph. The {@code HeaderBar} control should be positioned at the top of the window + * and its width should extend the entire width of the window, as otherwise the layout of the default window + * buttons and the header bar content might not be aligned correctly. Usually, {@code HeaderBar} is combined + * with a {@link BorderPane} root container: + *
{@code
+     * public class MyApp extends Application {
+     *     @Override
+     *     public void start(Stage stage) {
+     *         var headerBar = new HeaderBar();
+     *         var root = new BorderPane();
+     *         root.setTop(headerBar);
+     *
+     *         stage.setScene(new Scene(root));
+     *         stage.initStyle(StageStyle.EXTENDED);
+     *         stage.show();
+     *     }
+     * }
+     * }
+ * + *

Color scheme

+ * The color scheme of the default header buttons is automatically adjusted to remain easily recognizable + * by inspecting the {@link Scene#fillProperty() Scene.fill} property to gauge the brightness of the user + * interface. Applications should set the scene fill to a color that matches the user interface of the header + * bar area, even if the scene fill is not visible because it is obscured by other controls. + * + *

Custom header buttons

+ * If more control over the header buttons is desired, applications can opt out of the default header buttons + * by setting {@link HeaderBar#setPrefButtonHeight(Stage, double)} to zero and providing custom header buttons + * instead. Any JavaFX control can be used as a custom header button by setting its semantic type with the + * {@link HeaderBar#setButtonType(Node, HeaderButtonType)} method. + * + *

Title text

+ * An extended stage has no title text. Applications that require title text need to provide their own + * implementation by placing a {@code Label} or a similar control in the custom header bar. + * Note that the value of {@link Stage#titleProperty()} may still be used by the platform, for example + * in the title of miniaturized preview windows. + * + * @since 25 + * @deprecated This is a preview feature which may be changed or removed in a future release. + */ + @Deprecated(since = "25") + EXTENDED }