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
root.prefWidth(height); }
@Override protected double computePrefHeight(double width) { return
root.prefHeight(width); }
}
Note: this PR does not offer the `VBoxLayout` or `HBoxLayout`; to keep this PR
minimal, `StackPane` was chosen as an example layout.
## Changes made:
- Introduction of `Layoutable` interface.
- This interface extends a `Measurable` interface to cleanly segregate the
concerns of the measuring pass and the actual layout pass
- `Node` has been retrofitted to implement `Layoutable` (no new methods or API
changes)
- Introduction of `StackPaneLayout`, containing the `StackPane` layout
algorithm; this uses the `LayoutSupport` helper containing most of the (package
private) helper logic of `Region` with small adjustment to accept `Layoutable`s
instead of `Node`s
- `StackPane` has been adjusted to make use of the `StackPaneLayout`
- Bug fix included for https://bugs.openjdk.org/browse/JDK-8389585 (see the
`Scene` changes)
No test changes, all test pass as before, including the `StackPaneTest`.
### The `Snapper` system
In order to allow the layout helpers to do correct render scale aware
calculations, the `Snapper` type has been created. It holds the typical
`snapSizeX/Y` functions but without needing to a do a look-up of the render
scale on each call. As such it is likely a performance preserving change. There
is usually only one `Snapper` for an entire scene graph. The snapper with the
current render scale that is in use for a `Window` is accessible via the
`Region` `snapper()` method.
Because `Snapper`s are reusable, there are some optimizations here as well. For
render scale 1.0/1.0 there is a snapper that does no calculations, only
rounding or ceiling. For all other render scales, the division is avoided by
pre-calculating the reciprocal.
---------
- [x] I confirm that I make this contribution in accordance with the [OpenJDK
Interim AI Policy](https://openjdk.org/legal/ai).
-------------
Commit messages:
- Remove white space at end of line
- Add StackPaneLayout, move Region helpers to LayoutSupport
- Create new interfaces Layoutable and Measurable and use by Node
Changes: https://git.openjdk.org/jfx/pull/2241/files
Webrev: https://webrevs.openjdk.org/?repo=jfx&pr=2241&range=00
Issue: https://bugs.openjdk.org/browse/JDK-8389653
Stats: 2190 lines in 16 files changed: 1682 ins; 408 del; 100 mod
Patch: https://git.openjdk.org/jfx/pull/2241.diff
Fetch: git fetch https://git.openjdk.org/jfx.git pull/2241/head:pull/2241
PR: https://git.openjdk.org/jfx/pull/2241