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

Make it possible to read bevy-calculated ContentSize. #9112

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

nicopap
Copy link
Contributor

@nicopap nicopap commented Jul 11, 2023

Objective

Make it possible to read bevy-calculated ContentSize.

It can be useful to access the pre-layout content size. For example when integrating a different layout engine into bevy. It was previously possible, but #7779 made it impossible, it now requires ad-hoc redundant evaluation.

Although, maybe it's useful for other things as well? See bevyengine/bevy-website#701

Solution

  • Replace the private trait object measure_func in ContentSize by enum variants.
  • Centralize all bevy ui measurement code in ContentSize::measure method.
  • replace set usage with directly setting the enum

The tradeoff is that users can't implement themselves Measure anymore. Which might be a problem. An option is to provide a 4th variant with a trait object. It would make sense, since ContentSize ends up turned into a trait object on use in ui_layout_system in any case.


Migration Guide

  • bevy_ui's ContentSize::set and Measure doesn't exist anymore. Instead, set its value directly.

nicopap added 2 commits July 11, 2023 12:02
Objective
------

- `bevy_text/src/pipeline.rs` had some crufty code.

Solution
------

Remove the cruft.

- `&mut self` argument was unused by `TextPipeline::create_text_measure`, so we replace it with a constructor `TextMeasureInfo::from_text`.
- We also pass a `&Text` to `from_text` since there is no reason to split the struct before passing it as argument.
- from_text also checks beforehand that every Font exist in the Assets<Font>. This allows rust to skip the drop code on the Vecs we create in the method, since there is no early exit.
- We also remove the scaled_fonts field on `TextMeasureInfo`. This avoids an additional allocation. We can re-use the font on `fonts` instead in `compute_size`. Building a `ScaledFont` seems fairly cheap, when looking at the ab_glyph internals.
- We also implement ToSectionText on TextMeasureSection, this let us skip creating a whole new Vec each time we call compute_size.
- This let us remove compute_size_from_section_text, since its only purpose was to not have to allocate the Vec we just made redundant.
- Make some immutabe `Vec<T>` into `Box<[T]>` and `String` into `Box<str>`

The `ResMut<TextPipeline>` argument to  `measure_text_system` doesn't exist anymore. If you were calling this system manually, you should remove the argument.
@nicopap nicopap added A-UI Graphical user interfaces, styles, layouts, and widgets S-Blocked This cannot move forward until something else changes M-Needs-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide labels Jul 11, 2023
@ickshonpe
Copy link
Contributor

My thoughts:

  • The need to support other layout engines didn't occur to me at all when I implemented ContentSize 😓

  • In my first draft implementation, the measure funcs were publicly callable from the ContentSize components and I used some unsafe hacks to allow Taffy to access the components directly with a query. But I'm not an expert on unsafe rust, so I went with the move solution instead that I knew would work. If an approach using unsafe code is viable that might be better.

    Hopefully, Taffy will have better support for custom LayoutTree impls soon that will allow the layout algorithm to access our measure funcs without hacks or taking ownership.

  • I went with trait objects as the main focus of my PRs was fixing the existing bugs and I just wanted something simple and reliable that could be easily replaced later on by a better solution.

    The enum approach seems alright. Another option would be to have separate components like TextMeasure, ImageMeasure, etc instead of enum variants. I'm not sure what the tradeoffs are, but my guess is that an enum is probably the better option.

  • I think users definitely need to be able to implement Measure, a fourth variant wrapping a trait object seems like it would be fine. Custom measure funcs are also very useful for debugging.

  • ContentSize needs a better name. CalculatedSize was worse, but ContentSize still doesn't capture the right semantics. The name implies the component contains the size, not a function used to derive it. ContentShaper? ContentMeasure? Intrinsic-something?

@nicopap
Copy link
Contributor Author

nicopap commented Jul 14, 2023

So I also needed to expose a way to manipulate ContentSize in cuicui_layout. My solution involves using a SystemParam trait. I've used this style of API several times now (also in ui-navigation) but it's not established in bevy itself.

It's very onerous right now, it's probably possible to simplify it, but I spent a considerable amount of time trying to satisfy the rust type system already.

https://github.com/nicopap/cuicui_layout/blob/a90a40e9be934a8b01ca3271441b07acecb67a01/layout/src/content_sized.rs#L21-L35

@ickshonpe
Copy link
Contributor

ickshonpe commented Aug 3, 2023

Just been thinking about this again after working on #9341. Maybe there are advantages to Measure implementing Clone, and the layout system cloning a Measure instead of moving it. It's less efficient but probably not a big deal as measure funcs don't tend to get updated that often. The implementation of #9341 is way more complicated than it needs to be and cuicui_layout looks to be jumping through way too many hoops too.

@BenjaminBrienen BenjaminBrienen added D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged and removed S-Blocked This cannot move forward until something else changes labels Jan 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-UI Graphical user interfaces, styles, layouts, and widgets D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes M-Needs-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants