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

Custom layout engine #52

Merged
merged 8 commits into from
Nov 14, 2019
Merged

Custom layout engine #52

merged 8 commits into from
Nov 14, 2019

Conversation

hecrj
Copy link
Member

@hecrj hecrj commented Nov 11, 2019

This PR drops the stretch dependency and implements a custom layout engine based on the druid codebase, which is in turn inspired by Flutter. The main reasons for this change are simplicity, intuitiveness, and performance.

Flexbox, while powerful, is hard to use properly. Many of the styling properties of a flex node are tied to the parent flex-direction. This makes specific constraints very hard to encode (fill width/height, horizontal/vertical alignment, etc.). I think specific constraints like these are the ones users care about in the end.

Additionally, stretch forced us to turn every single node of the layout system into a flex node. This meant that even very simple nodes that did not have complex layout needs would still be seen as complex flex nodes by the layout algorithm.

Furthermore, we were using an old version of stretch and upgrading was not straightforward (#4). The upgrade would have entailed keeping a Stretch type around and mutating it as layout changes.

Moreover, computing layout with stretch was very slow. On my system, computing the layout of the "Text" screen in the tour example took around 4 ms. I think this could be related to using an old version and some odd behavior that I had to work around.


The new layout engine is very straightforward: each Widget is in charge of computing its boundaries inside the provided layout::Limits.

This way, complex widgets like Column and Row can distribute contents in a flex-like way, while simpler widgets like Button perform simple computations.

The new system is way faster. During my testing I have noticed a speedup of around 2 orders of magnitude in the best case (text measure cache hits) and 1 order of magnitude in the worst case (text measure cache misses). For instance, the "Text" screen I mentioned before now takes around 40 μs in the best case and 100 μs in the worst case. Debug mode is actually usable now! 🎉

In addition, a new Container widget has been added, allowing us to perform both horizontal and vertical alignment without the need of a "direction". Because of this, the Justify type has been dropped. Align will most likely change too.

Finally, the changes have been mostly internal. All the examples should be working as before!

Closes #4.

Changelog

Added

  • Container widget which allows easy alignment with methods like center_x and center_y
  • Widget::width and Widget::height, which should be implemented properly by widgets.

Changed

  • The flexbox layout engine has been replaced with a simpler, more intuitive alternative.
  • Widget::node has been changed to Widget::layout and it now computes the boundaries directly.
  • max_width and max_height methods now take a u32 instead of a Length.

Removed

  • stretch dependency
  • Justify type, justify_content and align_self methods

@hecrj hecrj added improvement An internal improvement feature New feature or request labels Nov 11, 2019
@hecrj hecrj added this to the 0.1.0 milestone Nov 11, 2019
@hecrj hecrj self-assigned this Nov 11, 2019
@Matthias-Fauconneau
Copy link
Contributor

Nice work !
Maybe it might be a good opportunity to clarify the difference between iced and druid ?
I chose iced because it seemed more ready, based on the tour demo and native rusty backends (winit/wgpu) while druid seems to be still an early experiment (and gtk backend :().
What would the front-end difference be between 'Elm-inspired' and 'data-oriented' ?
Maybe also other design philosophies ?

@hecrj hecrj mentioned this pull request Nov 13, 2019
@hecrj
Copy link
Member Author

hecrj commented Nov 14, 2019

@Matthias-Fauconneau Thanks!

Maybe it might be a good opportunity to clarify the difference between iced and druid ?
I chose iced because it seemed more ready, based on the tour demo and native rusty backends (winit/wgpu) while druid seems to be still an early experiment (and gtk backend :().
What would the front-end difference be between 'Elm-inspired' and 'data-oriented' ?

Have you read both the READMEs of iced and druid? I think they both explain their particular approach to GUI design quite well! I also recommend you to check the examples, which can help you get an idea of how different things are done in each library.

@hecrj hecrj merged commit bc8d347 into master Nov 14, 2019
@hecrj hecrj deleted the custom-layout-engine branch November 14, 2019 05:53
@Matthias-Fauconneau
Copy link
Contributor

Matthias-Fauconneau commented Nov 14, 2019 via email

@hecrj
Copy link
Member Author

hecrj commented Nov 20, 2019

I am suggesting presenting the contrasts more explicitly could be useful to newcomers who need help deciding before knowing the difference between Elm and data-orientied.

I agree. However, I think both druid and iced (and most Rust GUI libraries) are currently in an exploration stage. We are basically trying to figure out what can and cannot work. This makes it hard to present contrasts: the ecosystem is constantly evolving and shifting.

Moreover, I don't think I am familiar enough with druid's internals to talk about it. For instance, I don't know how they plan to tackle dynamic layouts exactly.

In any case, I plan to build some bridges for collaboration soon!

@Matthias-Fauconneau
Copy link
Contributor

Maybe expand on https://raphlinus.github.io/ui/druid/2019/11/22/reactive-ui.html explaining how iced currently fits in that framework ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature or request improvement An internal improvement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Upgrade stretch
2 participants