SecondHalfGames / yakui

yakui is a declarative Rust UI library for games
Apache License 2.0
237 stars 21 forks source link

Implement Intrinsic Sizing #45

Open LPGhatguy opened 2 years ago

LPGhatguy commented 2 years ago

A lesser-known part of the Flutter layout algorithm is that objects can report their intrinsic size as opposed to just computing their actual size when performing layout.

This would simplify a lot of widgets and open a lot of doors for us, like being able to implement IntrinsicSize.

Here's some interesting code in Flutter about this: https://github.com/flutter/flutter/blob/f1875d570e39de09040c8f79aa13cc56baab8db1/packages/flutter/lib/src/rendering/box.dart#L1449

as well as in the flex layout code: https://github.com/flutter/flutter/blob/47035a0102339c0464b1866a09cd6a25e86922d7/packages/flutter/lib/src/rendering/flex.dart#L664

API Additions

As part of this, we'll add two new methods to Widget:

    /// Tells the intrinsic width of the object, which is its width if the
    /// widget were given unbounded constraints.
    fn intrinsic_width(&self) -> f32 {
        0.0
    }

    /// Tells the intrinsic height of the object, which is its height if the
    /// widget were given unbounded constraints.
    fn intrinsic_height(&self) -> f32 {
        0.0
    }
johann2 commented 1 month ago

Once I finally wrapped my head around the flutter layout approach, I realized I really need this.

I did a crude implementation, currently only for width and for a limited set of widgets that covers my needs: https://github.com/SecondHalfGames/yakui/commit/4ed0e7023f27971e96e01ec40c3590812264cf6c

I'm not sure how to calculate intrinsic height without access to the DOM, so I added the DOM and the current node as an argument to the trait methods.

Ideally, I'd like to see this functionality in the mainline, so let me know if you're interested in a pull request and if this approach fits with the general design of the library.

LPGhatguy commented 1 month ago

@johann2 Thank you for taking a stab at this! Was your implementation able to solve the problem you ran into that made you think about intrinsic sizing?

We've run into a couple cases where this would be very useful, like making panels for our editor or sizing a container for a list of objects according to the largest item's cross-axis size.

I'd like to try implementing this feature this week based on your implementation. There's a bunch of stuff banked up that needs to be completed and merged with the library and my focus has been elsewhere.

johann2 commented 1 month ago

@johann2 Thank you for taking a stab at this! Was your implementation able to solve the problem you ran into that made you think about intrinsic sizing?

Yeah, this implementation is enough for my use case. The main reason was that I needed to create columns where every child has the width of the widest element, without manually specifying the width. The most notable omission is that the text widget's implementation returns 0.0 as it seemed a bit more complex and I didn't really need it.

I'd like to try implementing this feature this week based on your implementation. There's a bunch of stuff banked up that needs to be completed and merged with the library and my focus has been elsewhere.

That would be nice. Note that I found a bug in the commit I posted, so please use the latest commit in my fork instead