Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Normalize containers' handling of children/content #3168

Open
HalfWhitt opened this issue Feb 7, 2025 · 5 comments
Open

Normalize containers' handling of children/content #3168

HalfWhitt opened this issue Feb 7, 2025 · 5 comments
Labels
enhancement New features, or improvements to existing features.

Comments

@HalfWhitt
Copy link
Contributor

What is the problem or limitation you are having?

Box works like a div or other box in CSS, which is a node which can contain children that continue the hierarchy downward.

By contrast, ScrollContainer, SplitContainer, and OptionContainer each count as an opaque leaf node, and their content starts over again as a new root node.

Describe the solution you'd like

I don't yet have much of an idea how feasible it would be, or how it would be accomplished under the hood, but things would be much more consistent if these containers could truly be containers in the node/style context.

From a CSS standpoint, at least once we eventually arrive at some version of Colosseum, one would expect to be able to set overflow: scroll on a Box to turn it into what would currently have to be a ScrollContainer with a box in it. (I haven't really looked at the backend implementations yet, but I imagine this would be difficult to translate, at least on OSes where a box/section and a scrolling pane are separate widgets. Making every box two native widgets is probably highly inefficient, but hot-swapping a native widget for two native widgets also seems fraught.)

Describe alternatives you've considered

Leave things as they are, potentially special-casing content to receive similar treatment to children in places that need to walk the tree downward.

Additional context

The current arrangement complicates things for:

@HalfWhitt HalfWhitt added the enhancement New features, or improvements to existing features. label Feb 7, 2025
@freakboy3742
Copy link
Member

I think I understand what you're describing... I think it reduces to handling the content of a Container using the children handling of Node.

I can't say I have a clear recollection of why the split was made... it's entirely possible it's an accident of history and bad planning. I can't think of any reasonable interpretation of a Container having children independent of the content it contains; so maybe we can simplify the two concepts, and simplify a bunch of other handling in the process.

There's always going to be a discontinuity between the native widget hierarchy and the Toga widget heirarchy - in addition to the scrolling issue you've identified, there's issues with CSS details like negative margins. However, that should be a platform detail.

@freakboy3742
Copy link
Member

Thinking about this a little more - I can think of at least two reasons for a distinction: OptionContainer children, and layout constraints.

Firstly, on a SplitContainer or a ScrollContainer, any
Content can be a child (although there's some fairly significant limitations if the child can't have arbitrary sizing).

However, an OptionContainer child must be an OptionItem; and OptionItem isn't a node itself (at least, not as currently designed) - it's an object that has a root content node.

It might be possible to make the OptionItem's content a direct DOM child of the OptionContainer - but there's definitely complications inherent in that.

Secondly, the introduction of a Container is effectively a "breakpoint" in layout calculations - the container gets a size as a part of the layout it's a part of; and then the children of that container gets layouts that are constrained by the properties of the layout container - either "no constraints" in the case of ScrollContainer, or constraints based on widget decoration for OptionContainer and SplitContainer.

It might be possible to reconcile this "breakpoint" into a layout; but it's definitely a complication that having a clear separation helps with.

@HalfWhitt
Copy link
Contributor Author

Secondly, the introduction of a Container is effectively a "breakpoint" in layout calculations - the container gets a size as a part of the layout it's a part of; and then the children of that container gets layouts that are constrained by the properties of the layout container - either "no constraints" in the case of ScrollContainer, or constraints based on widget decoration for OptionContainer and SplitContainer.

Yeah, exactly. Each scroll/option/split container is an opaque leaf to the tree it's in, and its content is the root of its own tree. I do get the reasoning there.

And at least in theory, it should be entirely possible to do #2938 by laying out each tree separately, making sure to handle them in "downward" order. Just need to figure out how to properly check roots to see which trees contain which, and then apply them all in the right order once per event loop. The mechanism for cascading style properties downward could also check of if a child node has a content, and then handle passing on the cascade down to it. But it would be nice to not have to do either of those, if avoiding them doesn't add even more complexity elsewhere.

I haven't tried any of this yet, so this is just grain-of-salt spitballing, but... what if the Toga hierarchy contained a hidden "link" widget? For instance, what if an end user continues to use SplitContainer as usual, assigning to content. But the content setter sets it up so that SplitContainer contains two child boxes, and each of those boxes has the relevant content in them? It might be possible to give the two boxes explicit sizes (intrinsic or style-based, I'm not sure) that are set and updated based on the ScrollContainer's computed size, and the user's dragging of the divider. In theory, that should let layout calculations and style cascading pass through transparently.

Of course, we'd probably need setter and/or getter overrides to prevent users from inadvertently adding or removing children manually...

Maybe some of this could even be accomplished within a custom children getter, with a disabled setter? Hmm.

@freakboy3742
Copy link
Member

And at least in theory, it should be entirely possible to do #2938 by laying out each tree separately, making sure to handle them in "downward" order. Just need to figure out how to properly check roots to see which trees contain which, and then apply them all in the right order once per event loop. The mechanism for cascading style properties downward could also check of if a child node has a content, and then handle passing on the cascade down to it. But it would be nice to not have to do either of those, if avoiding them doesn't add even more complexity elsewhere.

Yes... ish. The added complication is that the layout actually needs to be completely broken at the breakpoints - or, at least, the intrinsic size needs to be evaluated differently depending on whether you're computing the size of the Container itself, or the layout of the content in the container.

Maybe some of this could even be accomplished within a custom children getter, with a disabled setter? Hmm.

That was my initial thought... but I'll completely defer to someone actually looking at the code :-)

@HalfWhitt
Copy link
Contributor Author

That was my initial thought... but I'll completely defer to someone actually looking at the code :-)

Point taken. 😄

Initial vibe check accomplished, I'll report back if/when I come back from spelunking with a more concrete proposal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New features, or improvements to existing features.
Projects
None yet
Development

No branches or pull requests

2 participants