Skip to content

Conversation

livtanong
Copy link
Contributor

Description

Implements an ExpandedComponent, which takes up as much space as possible along the main axis within a LinearLayoutComponent. With more than one ExpandedComponent, this expansion is divided equally.

Checklist

  • I have followed the Contributor Guide when preparing my PR.
  • I have updated/added tests for ALL new/updated/fixed functionality.
  • I have updated/added relevant documentation in docs and added dartdoc comments with ///.
  • I have updated/added relevant examples in examples or docs.

Breaking Change?

  • Yes, this PR is a breaking change.
  • No, this PR is not a breaking change.

Migration instructions

If the PR is breaking, uncomment this header and add instructions for how to migrate from the
currently released version in-between the two following tags:

PaddingComponent now inherits from SingleLayoutComponent.

Related Issues

Closes #3656

@livtanong
Copy link
Contributor Author

Closing to clean up commit history

@livtanong livtanong closed this Jul 30, 2025
@livtanong
Copy link
Contributor Author

Actually, I'll just reopen this. I think you guys squash the commits anyway before merging

@livtanong livtanong reopened this Jul 30, 2025
@spydon
Copy link
Member

spydon commented Jul 30, 2025

Actually, I'll just reopen this. I think you guys squash the commits anyway before merging

We do indeed!

Copy link
Member

@spydon spydon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Over all it looks good, just one comment.

@livtanong
Copy link
Contributor Author

Discovered a infinite loop new issue involving nested LinearLayoutComponents (a row inside a column, and the column using CrossAxisAlignment.stretch)

These listener interactions are messing with my head T_T

@livtanong
Copy link
Contributor Author

@spydon i think I may have to do another refactor:

One of the bigger challenges I have right now is the fact that a LayoutComponent may want to shrink wrap in one axis, while being explicit in another.

For example:

ColumnComponent(
  key: ComponentKey.named("alice"),
  size: Vector2(600, 400),
  crossAxisAlignment: CrossAxisAlignment.stretch,
  children: [
    ExpandedComponent(
      key: ComponentKey.named("bob"),
      // child omitted for brevity
    ),
    RowComponent(
      key: ComponentKey.named("charlie"),
      mainAxisAlignment: MainAxisAlignment.end,
      children: [
        TextComponent(text: "text")
      ],
    ),
  ],
);
  • alice has crossAxisAlignment = stretch
  • charlie is a child of alice and therefore its width is set to 600 (explicit setting)
  • charlie was originally intended to shrinkwrap down to its child's size (say, 24).

The intent is for charlie to shrinkwrap along the y axis, but have explicit sizing along the x axis.

Because a lot of the logic around adding and removing listeners centers around the value of shrinkWrapMode, this particular case is troublesome.

@spydon
Copy link
Member

spydon commented Jul 31, 2025

Sounds good @livtanong
Since these components luckily are marked as experimental, don't be afraid to do breaking changes if it helps to clean them up.

@livtanong
Copy link
Contributor Author

@spydon this is a significant departure, and I'm almost sure you won't be very happy with this.

I introduce layoutWidth and layoutHeight. These are both nullable doubles, and this is the key to solving the layout infinite loop problem. This allows us to both set height/width and track shrinkwrapping behavior in an axis-independent way.

Because these are scalars, and aren't notifiers, a lot of logic is moved to the setters of these values.
We still have listeners on size in general, but these layout components no longer listen to their own size.

We make a distinction between the size that a layout component is, and the size that a layout component intends to be. The latter is captured by the nullable doubles: layoutWidth and layoutHeight. And a component never needs to listen to the former. It only needs to set the former in reaction to the latter.

I have also toyed with the idea of making a NullableVector2, where its components can be nullable doubles, but I realize that I should make it work with scalars first. I don't even know if making an entirely new data structure just for this is even sane.

So with all this ugliness out and explained--I think this is the only way we can get to properly implementing ExpandedComponent.

@spydon
Copy link
Member

spydon commented Aug 2, 2025

I introduce layoutWidth and layoutHeight. These are both nullable doubles, and this is the key to solving the layout infinite loop problem. This allows us to both set height/width and track shrinkwrapping behavior in an axis-independent way.

Hmm, it feels a bit dirty... I'd hope there is another way we can solve this without creating new arguments. Would it help if the NotifyingVector2 had a way of setting the values without calling the registered listeners?

@livtanong
Copy link
Contributor Author

I think the bigger issue right now is a nullable vector 2. Anticipating your discomfort, I've already started working on a NullableVector2. Then after i'll see if I run into any trouble extending it into a NotifyingNullableVector2 with ChangeNotifier.

livtanong and others added 29 commits October 1, 2025 09:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ExpandedComponent

5 participants