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
