On Mon, 3 Aug 2026 16:34:14 GMT, John Hendrikx <[email protected]> wrote:

> This PR shows how virtual layouts could be implemented, as discussed on the 
> mailinglist: 
> https://mail.openjdk.org/archives/list/[email protected]/thread/PLNSQ3ZI63AVKEFKNT5GT6WHAD2GYMPC/
> 
> It would work by making new non-Node containers called Layouts which can 
> contain a mix of either Nodes or other Layouts. Allowing Layouts to nest 
> makes it possible to create a substructure similar to how nesting 
> StackPane/HBox/VBox etc works today. An example is a simple control that has 
> a graphic with a title and subtitle stacked vertically next to it:
> 
> 
> +-------------+-----------------------------------------+
> |             |                                         |
> |             |                 Title                   |
> |             |                                         |
> |   Graphic   +-----------------------------------------+
> |             |                                         |
> |             |                Subtitle                 |
> |             |                                         |
> +-------------+-----------------------------------------+
> 
> For a control to model this, it would need a VBox containing the Title and 
> Subtitle, and an HBox containing the Graphic and the VBox.  The two 
> containers are heavy-weight Nodes and this incurs sufficiently large memory 
> and performance penalties that most standard JavaFX controls will opt to 
> instead roll their own layout code to avoid paying the cost for these.
> 
> With virtual layouts, the control could make use of non-Node containers. The 
> control would add its three children (Graphic, Title and Subtitle) as direct 
> children for display in the scene graph, but would offload their positioning 
> to a virtual layout.  This roughly looks like this:
> 
> 
>   public class TitledGraphic extends Region {
>       private final HBoxLayout root;
> 
>       public TitledGraphic(Node graphic, String titleText, String 
> subtitleText) {
>           // Flat scene graph:
>           getChildren().addAll(graphic, title, subtitle);
> 
>           // Create virtual layout:
>           root = HBoxLayout.of(graphic, VBoxLayout.of(title, subtitle));
>       }
> 
>       @Override
>       protected void layoutChildren() {
>           root.resizeRelocate(0, 0, getWidth(), getHeight());
>       }
> 
>       @Override protected double computeMinWidth(double height)   { return 
> root.minWidth(height); }
>       @Override protected double computeMinHeight(double width)   { return 
> root.minHeight(width); }
>       @Override protected double computePrefWidth(double height)  { return ...

some initial comments, for now.

modules/javafx.graphics/src/main/java/com/sun/javafx/scene/layout/Snapper.java 
line 42:

> 40:      * A default snapper for 1.0 scaling.
> 41:      */
> 42:     static final Snapper DEFAULT = new Snapper() {

DEFAULT might be too generic.  IDENTITY_SNAPPED or something like that?

modules/javafx.graphics/src/main/java/javafx/scene/Node.java line 3276:

> 3274:      * @return offset of text baseline from layoutBounds.minY for 
> non-resizable Nodes or {@link #BASELINE_OFFSET_SAME_AS_HEIGHT} otherwise
> 3275:      */
> 3276:     @Override

L3556: `getLayoutBounds()` needs an `@Override`

modules/javafx.graphics/src/main/java/javafx/scene/Scene.java line 522:

> 520: 
> 521:                         @Override
> 522:                         public RenderScaleContext 
> getRenderScaleContext(Scene scene) {

minor: would it make sense to combine `Snapper` and `RenderScaleContext` -> 
`RenderContext`?

modules/javafx.graphics/src/main/java/javafx/scene/layout/LayoutSupport.java 
line 43:

> 41:  * Layout math shared between Region and Layoutable-based layouts.
> 42:  */
> 43: final class LayoutSupport {

minor: rename `LayoutUtils` maybe?   "support" reads like some data object.

modules/javafx.graphics/src/main/java/javafx/scene/layout/Layoutable.java line 
56:

> 54:  * reposition an element to specific dimensions and coordinates.
> 55:  *
> 56:  * @see Measurable

all new public classes need `@since 28` (or `@since TBD`, depending on how long 
this thing will marinade)

modules/javafx.graphics/src/main/java/javafx/scene/layout/Measurable.java line 
45:

> 43:  *       than {@code pref}, the {@code max} value must be used.
> 44:  * </ul>
> 45:  * The preferred size should therefore be clamped within the range {@code 
> [min, max]}.

+1!

modules/javafx.graphics/src/main/java/javafx/scene/layout/Measurable.java line 
202:

> 200:      * The 'alphabetic' (or 'roman') baseline offset from the element's 
> top boundary
> 201:      * that should be used when this element is being vertically aligned 
> by baseline with
> 202:      * other elements. By default this returns {@link 
> #BASELINE_OFFSET_SAME_AS_HEIGHT} for resizable elements

-> "By default, ..."

modules/javafx.graphics/src/main/java/javafx/scene/layout/RenderScaleContext.java
 line 37:

> 35:  *        ratio of device pixels to logical pixels on the Y axis
> 36:  */
> 37: public record RenderScaleContext(double snapScaleX, double snapScaleY) {

minor: just `RenderScale` maybe?  or do you plan to add more context?

modules/javafx.graphics/src/main/java/javafx/scene/layout/StackPane.java line 
141:

> 139:     private static final Callback<Layoutable, Pos> ALIGNMENT_LOOKUP = 
> child -> StackPane.getAlignment((Node) child);
> 140: 
> 141:     private final StackPaneLayout stackPaneLayout = new 
> StackPaneLayout(MARGIN_LOOKUP, ALIGNMENT_LOOKUP);

would it make more sense to make StackPaneLayout an abstract class instead of 
using callbacks?

modules/javafx.graphics/src/main/java/javafx/scene/layout/StackPaneLayout.java 
line 75:

> 73:  * to it.
> 74:  */
> 75: class StackPaneLayout implements Layoutable {

the intent is to make it public eventually, right?

modules/javafx.graphics/src/main/java/javafx/scene/layout/StackPaneLayout.java 
line 164:

> 162:     @Override
> 163:     public double minWidth(double height) {
> 164:         // TODO pre-existing bug, insets not snapped anywhere

probably not a bug: these methods should not return snapped values (as they 
might come from properties).  the snapping should be done by the caller.

-------------

PR Review: https://git.openjdk.org/jfx/pull/2241#pullrequestreview-4858400466
PR Review Comment: https://git.openjdk.org/jfx/pull/2241#discussion_r3715724224
PR Review Comment: https://git.openjdk.org/jfx/pull/2241#discussion_r3715780603
PR Review Comment: https://git.openjdk.org/jfx/pull/2241#discussion_r3716543508
PR Review Comment: https://git.openjdk.org/jfx/pull/2241#discussion_r3716213943
PR Review Comment: https://git.openjdk.org/jfx/pull/2241#discussion_r3716119744
PR Review Comment: https://git.openjdk.org/jfx/pull/2241#discussion_r3716106968
PR Review Comment: https://git.openjdk.org/jfx/pull/2241#discussion_r3716141052
PR Review Comment: https://git.openjdk.org/jfx/pull/2241#discussion_r3716387278
PR Review Comment: https://git.openjdk.org/jfx/pull/2241#discussion_r3716513836
PR Review Comment: https://git.openjdk.org/jfx/pull/2241#discussion_r3716508500
PR Review Comment: https://git.openjdk.org/jfx/pull/2241#discussion_r3716525695

Reply via email to