On 15/07/2026 20:10, Andy Goryachev wrote:
> Right, static layouts will only work in simple cases, the more
> complicated ones will require an instance.
>
> My point is that if we are laying out Nodes, there is no need to
> invent another abstraction layer because Nodes contain all the
> required data.  This will eliminate the "Bonus" section which some
> seem to like.

The Bonus section is bonus, all else is still needed. 

The problem is: we're not laying out only Nodes.  We're also laying out
potentially light-weight layout containers (that purposely are not
Nodes).  So the list of things to lay out can contain a mix of Nodes and
Layouts.  A layout acts as a Node, but isn't one. 

Let's take my example: A TitleSubtileControl that can have a Graphic on
the left and on the right two lines of text one above the other (title
and subtitle)

- The TitleSubtileControl is a normal Node, that wants to avoid having a
nested HBox and VBox so it creates:
  - A HBoxLayout within it nested a VBoxLayout and a Graphic (a Layout
and a Node)
  - A VBoxLayout within it nested a Title and a Subtitle Text (two Nodes)
  - It adds only the Nodes to the scenegraph as its children (so:
titleSubtitleControl.getChildren().addAll(graphic, title, subtitle)

Now the problem is, HBoxLayout needs to accept a VBoxLayout (not a Node)
and a Graphic (a Node).  The only way to do that is to store them as
Objects since they don't share a common ancestor; VBoxLayout can't be a
Node because that would pull in a zillion private fields and properties
making it "heavy".

The solution I presented is to create this common ancestor, which I've
dubbed Layoutable. It contains methods that only layouts need (like
VBoxLayout or VBox itself).  These methods already exist on Node,
they're just not grouped as part of an interface it implements.  Doing
such a change is source and binary compatible.

So the end state is:

- VBoxLayout implements Layoutable (but is not a Node!)
- Node implements Layoutable

When VBoxLayout and a Node are nested in HBoxLayout, the HBoxLayout can
treat both as Layoutable's making Layouts clean (there would have to be
a million instanceof checks otherwise, or we'd need to wrap Nodes in a
LayoutableWrapper).

Sorry for the confusion with the bonus section, I hope this clarifies
why it would a good move to have a common ancestor for Nodes and Layouts.

--John


>
> I guess what I am trying to say is that code reuse (and removal of
> hard-to-maintain code replication) should be the primary goal, while
> adding new features (Canvas) should come last, if ever.
>
> -andy
>
>
> *From: *John Hendrikx <[email protected]>
> *Date: *Wednesday, July 15, 2026 at 10:49
> *To: *Andy Goryachev <[email protected]>;
> [email protected] <[email protected]>
> *Subject: *Re: [External] : Proposal to split off layout and layout
> metric methods from Node to interfaces it implements
>
> This Message Is From an External Sender
> This message came from outside your organization.
> Report Suspicious
> <https://us-phishalarm-ewt.proofpoint.com/EWT/v1/ACWV5N9M2RV99hQ!NB26ligkesgE1bPqfVnUuELFLOB1vmX7gUMnmgafz5PcT3tCIOQ6CH3Y_2TlHn6_oY4aATre-aOhU774w6HiWg4mLvHIFUYvM_SnXw$>
>  
>
>
> On 15/07/2026 19:32, Andy Goryachev wrote:
>
>      *
>         Yes, they don't need to be public immediately, although they
>         definitely can be as they're nothing more than a "copy" of the
>         layout panes we already have, but packaged without the Node
>         dependency.  We would need pretty quickly the Node
>         implementing the Layoutable interface (which opens the path
>         for people writing their own virtual layouts).
>
>
>
>     One thing I wanted to mention is that these layout classes can
>     probably be static (unless they need to keep some internal state
>     like HBox.tempArray).  If I understand the logic, there is no need
>     for the Layoutable interface either, the owner Node is merely
>     delegates layoutChildren() to the corresponding layout class,
>     passing all the necessary information (scale, snap, etc.)
>
> If you want virtual layouts to compose, you need to be able to point
> at something.  Let's say you have a simple layout:
>
>     HorizontalLayout[ Graphic + Text ]
>
> This can be relatively static, agreed.
>
> However, if you want something more complicated:
>
>     HorizontalLayout[ Graphic + VerticalLayout[Title + Subtitle] ]
>
> ...then how would the static call look like to HorizontalLayout?
>
> Furthermore, HorizontalLayout would need to accept both Node and
> Layout somehow if they don't implement a common interface (so Object[] ?)
>
> Also, layouts often have a ton of parameters to tweak: padding,
> alignment, spacing, margins, snapToPixel, etc... that's a lot of
> things to pass in to a static layout.  This quickly invites a
> "parameter" object, at which point you can just make the Layout an
> instance (which gives more flexibility for also caching things and
> other interal bookkeeping).
>
> The best you can do as a "static" solution is to have some helpers,
> like the SpaceDistributor class I once created, but the actual layouts
> are *far* more complicated, and I don't think you can easily get away
> with having them just be a static method call.
>
>
>     In other words, it might be possible to achieve the main goal of
>     code reuse without any changes to the public APIs.  The layout
>     classes can be made public later, once matured.
>
> Only if you accept the layouts would be extremely limited (no mixing
> of Layouts and Nodes).
>
> Regardless, there wouldn't be any changes to existing public API's by
> having Node implement Layoutable.  At most, there would be one or two
> methods to offer a better abstraction for just plainly exposing
> "getProperties()" on Layoutable.  Implementing an interface that
> exposes methods that Node already has is a source and binary
> compatible change.
>
> --John
>
>
>     What do you think?
>
>     -andy
>

Reply via email to