iced-rs / iced

A cross-platform GUI library for Rust, inspired by Elm
https://iced.rs
MIT License
24.23k stars 1.13k forks source link

Advanced layout strategies (grid, floating text, etc.) #34

Open hecrj opened 4 years ago

hecrj commented 4 years ago

Currently, iced_native only supports flexbox items. For instance, it is not possible to create a grid of items or make text float around an image.

We will need to enhance the layouting engine to support different strategies and improve the way we measure text to lay it out in a more flexible way.

virtualritz commented 4 years ago

I like to mention elm-ui for inspiration – as an alternative to CSS concepts. There is also a talk from its author on youtube.

virtualritz commented 4 years ago

A, kindly ignore. I just saw that elm-ui is already on your radar. :)

nicoburns commented 4 years ago

~You may wish to consider using https://github.com/vislyhq/stretch for layout It's a full flexbox implementation, with support for absolute positioning. CSS grid support is stated goal, although it's not currently implemented.~

EDIT: Stretch has become unmaintained, but has a well maintained fork in Taffy (https://github.com/DioxusLabs/taffy) EDIT2: I ended up implementing CSS Grid support myself. It's available as of Taffy 0.3.0.

nicoburns commented 1 year ago

@hecrj I've been looking into what it would take to implement Taffy's layout modes (Flexbox and CSS Grid) as an Iced widget. I have a working prototype of a Grid widget at https://github.com/nicoburns/iced_taffy (checkout the nested example if you are interested).

Based on the experience of making this prototype I have a bit of a laundry list of changes to Iced that I'd like in order to make such an integration easier and more efficient:

  1. Add a measure method to Widget trait This would be similar to layout, but only returns a size rather than recursively returning child layouts. Taffy's layout modes often require measuring children multiple times so it's important that this is as cheap as possible. And it is often much cheaper to merely compute the size of widget than it is to recursively layout the widget and all of it's descendants.

    This method should take &mut self rather than &self to enable caching of the results. The caching is useful even within a single frame (/relayout) and is crucial for performance (in our benchmarks it turns the time complexity of layout from "exponential with respect to the depth of the tree" to "linear with respect to the total number of nodes" leading to wall time improvements of several orders of magnitude for trees even a few nodes (e.g. 7) deep).

  2. Have the layout method on Widget trait take &mut self instead of &self (possibly not currently useful) Same reason (caching) as above. Although I'm not quite sure what Iced's story on change detection is. I think I read somewhere that Iced currently unconditionally rerenders everything on each frame, in which case this may not be useful yet.

  3. Add setters for fill property of layout::Limits I need precise control of the Limits beyond what is provided by the current methods. I'm currently working around this by carefully calling multiple methods, but this is quite awkwards.

  4. Ability to move children out of layout::Node I need to obtain the recursive child layouts out of layout::Node but override the bounds with my own computations. I am currently able to workaround this by cloning the children Vec, but this introduces an unncessary clone.

There are other things I'd potentially like in future such as:

But I believe the above (particularly the measure method) would be sufficient to get to the point where I could sensibly release a generally usable version of iced_taffy with acceptable performance for large trees.

Would you be open to PR's that made these changes?

nicoburns commented 1 year ago

Update: Just saw https://github.com/iced-rs/iced/pull/52 and wanted to add that:

videni commented 1 month ago

@hecrj how is this going ? I'd like to implement a dynamic rows and columns layout, what is the right way to do at the moment please?

sauntheninja2 commented 3 weeks ago

Hi @videni Did you manage to achieve this? I also need to implement this in my project

videni commented 3 weeks ago

@sauntheninja2 , I integrated taffy for the grid feature, it works as expected, but still in early age, demo only , it is lack of critical features:

if you like , here is the gist about the naive implemention