bevy/crates/bevy_ui/src/measurement.rs

78 lines
2.1 KiB
Rust
Raw Normal View History

`text_system` split (#7779) # Objective `text_system` runs before the UI layout is calculated and the size of the text node is determined, so it cannot correctly shape the text to fit the layout, and has no way of determining if the text needs to be wrapped. The function `text_constraint` attempts to determine the size of the node from the local size constraints in the `Style` component. It can't be made to work, you have to compute the whole layout to get the correct size. A simple example of where this fails completely is a text node set to stretch to fill the empty space adjacent to a node with size constraints set to `Val::Percent(50.)`. The text node will take up half the space, even though its size constraints are `Val::Auto` Also because the `text_system` queries for changes to the `Style` component, when a style value is changed that doesn't affect the node's geometry the text is recomputed unnecessarily. Querying on changes to `Node` is not much better. The UI layout is changed to fit the `CalculatedSize` of the text, so the size of the node is changed and so the text and UI layout get recalculated multiple times from a single change to a `Text`. Also, the `MeasureFunc` doesn't work at all, it doesn't have enough information to fit the text correctly and makes no attempt. Fixes #7663, #6717, #5834, #1490, ## Solution Split the `text_system` into two functions: * `measure_text_system` which calculates the size constraints for the text node and runs before `UiSystem::Flex` * `text_system` which runs after `UiSystem::Flex` and generates the actual text. * Fix the `MeasureFunc` calculations. --- Text wrapping in main: <img width="961" alt="Capturemain" src="https://user-images.githubusercontent.com/27962798/220425740-4fe4bf46-24fb-4685-a1cf-bc01e139e72d.PNG"> With this PR: <img width="961" alt="captured_wrap" src="https://user-images.githubusercontent.com/27962798/220425807-949996b0-f127-4637-9f33-56a6da944fb0.PNG"> ## Changelog * Removed the previous fields from `CalculatedSize`. `CalculatedSize` now contains a boxed `Measure`. * Added `measurement` module to `bevy_ui`. * Added the method `create_text_measure` to `TextPipeline`. * Added a new system `measure_text_system` that runs before `UiSystem::Flex` that creates a `MeasureFunc` for the text. * Rescheduled `text_system` to run after `UiSystem::Flex`. * Added a trait `Measure`. A `Measure` is used to compute the size of a UI node when the size of that node is based on its content. * Added `ImageMeasure` and `TextMeasure` which implement `Measure`. * Added a new component `UiImageSize` which is used by `update_image_calculated_size_system` to track image size changes. * Added a `UiImageSize` component to `ImageBundle`. ## Migration Guide `ImageBundle` has a new component `UiImageSize` which contains the size of the image bundle's texture and is updated automatically by `update_image_calculated_size_system` --------- Co-authored-by: François <mockersf@gmail.com>
2023-04-17 15:23:21 +00:00
use bevy_ecs::prelude::Component;
`MeasureFunc` improvements (#8402) # Objective fixes #8516 * Give `CalculatedSize` a more specific and intuitive name. * `MeasureFunc`s should only be updated when their `CalculatedSize` is modified by the systems managing their content. For example, suppose that you have a UI displaying an image using an `ImageNode`. When the window is resized, the node's `MeasureFunc` will be updated even though the dimensions of the texture contained by the node are unchanged. * Fix the `CalculatedSize` API so that it no longer requires the extra boxing and the `dyn_clone` method. ## Solution * Rename `CalculatedSize` to `ContentSize` * Only update `MeasureFunc`s on `CalculatedSize` changes. * Remove the `dyn_clone` method from `Measure` and move the `Measure` from the `ContentSize` component rather than cloning it. * Change the measure_func field of `ContentSize` to type `Option<taffy::node::MeasureFunc>`. Add a `set` method that wraps the given measure appropriately. --- ## Changelog * Renamed `CalculatedSize` to `ContentSize`. * Replaced `upsert_leaf` with a function `update_measure` that only updates the node's `MeasureFunc`. * `MeasureFunc`s are only updated when the `ContentSize` changes and not when the layout changes. * Scale factor is no longer applied to the size values passed to the `MeasureFunc`. * Remove the `ContentSize` scaling in `text_system`. * The `dyn_clone` method has been removed from the `Measure` trait. * `Measure`s are moved from the `ContentSize` component instead of cloning them. * Added `set` method to `ContentSize` that replaces the `new` function. ## Migration Guide * `CalculatedSize` has been renamed to `ContentSize`. * The `upsert_leaf` function has been removed from `UiSurface` and replaced with `update_measure` which updates the `MeasureFunc` without node insertion. * The `dyn_clone` method has been removed from the `Measure` trait. * The new function of `CalculatedSize` has been replaced with the method `set`.
2023-05-01 15:40:53 +00:00
use bevy_ecs::reflect::ReflectComponent;
`text_system` split (#7779) # Objective `text_system` runs before the UI layout is calculated and the size of the text node is determined, so it cannot correctly shape the text to fit the layout, and has no way of determining if the text needs to be wrapped. The function `text_constraint` attempts to determine the size of the node from the local size constraints in the `Style` component. It can't be made to work, you have to compute the whole layout to get the correct size. A simple example of where this fails completely is a text node set to stretch to fill the empty space adjacent to a node with size constraints set to `Val::Percent(50.)`. The text node will take up half the space, even though its size constraints are `Val::Auto` Also because the `text_system` queries for changes to the `Style` component, when a style value is changed that doesn't affect the node's geometry the text is recomputed unnecessarily. Querying on changes to `Node` is not much better. The UI layout is changed to fit the `CalculatedSize` of the text, so the size of the node is changed and so the text and UI layout get recalculated multiple times from a single change to a `Text`. Also, the `MeasureFunc` doesn't work at all, it doesn't have enough information to fit the text correctly and makes no attempt. Fixes #7663, #6717, #5834, #1490, ## Solution Split the `text_system` into two functions: * `measure_text_system` which calculates the size constraints for the text node and runs before `UiSystem::Flex` * `text_system` which runs after `UiSystem::Flex` and generates the actual text. * Fix the `MeasureFunc` calculations. --- Text wrapping in main: <img width="961" alt="Capturemain" src="https://user-images.githubusercontent.com/27962798/220425740-4fe4bf46-24fb-4685-a1cf-bc01e139e72d.PNG"> With this PR: <img width="961" alt="captured_wrap" src="https://user-images.githubusercontent.com/27962798/220425807-949996b0-f127-4637-9f33-56a6da944fb0.PNG"> ## Changelog * Removed the previous fields from `CalculatedSize`. `CalculatedSize` now contains a boxed `Measure`. * Added `measurement` module to `bevy_ui`. * Added the method `create_text_measure` to `TextPipeline`. * Added a new system `measure_text_system` that runs before `UiSystem::Flex` that creates a `MeasureFunc` for the text. * Rescheduled `text_system` to run after `UiSystem::Flex`. * Added a trait `Measure`. A `Measure` is used to compute the size of a UI node when the size of that node is based on its content. * Added `ImageMeasure` and `TextMeasure` which implement `Measure`. * Added a new component `UiImageSize` which is used by `update_image_calculated_size_system` to track image size changes. * Added a `UiImageSize` component to `ImageBundle`. ## Migration Guide `ImageBundle` has a new component `UiImageSize` which contains the size of the image bundle's texture and is updated automatically by `update_image_calculated_size_system` --------- Co-authored-by: François <mockersf@gmail.com>
2023-04-17 15:23:21 +00:00
use bevy_math::Vec2;
bevy_reflect: `FromReflect` Ergonomics Implementation (#6056) # Objective **This implementation is based on https://github.com/bevyengine/rfcs/pull/59.** --- Resolves #4597 Full details and motivation can be found in the RFC, but here's a brief summary. `FromReflect` is a very powerful and important trait within the reflection API. It allows Dynamic types (e.g., `DynamicList`, etc.) to be formed into Real ones (e.g., `Vec<i32>`, etc.). This mainly comes into play concerning deserialization, where the reflection deserializers both return a `Box<dyn Reflect>` that almost always contain one of these Dynamic representations of a Real type. To convert this to our Real type, we need to use `FromReflect`. It also sneaks up in other ways. For example, it's a required bound for `T` in `Vec<T>` so that `Vec<T>` as a whole can be made `FromReflect`. It's also required by all fields of an enum as it's used as part of the `Reflect::apply` implementation. So in other words, much like `GetTypeRegistration` and `Typed`, it is very much a core reflection trait. The problem is that it is not currently treated like a core trait and is not automatically derived alongside `Reflect`. This makes using it a bit cumbersome and easy to forget. ## Solution Automatically derive `FromReflect` when deriving `Reflect`. Users can then choose to opt-out if needed using the `#[reflect(from_reflect = false)]` attribute. ```rust #[derive(Reflect)] struct Foo; #[derive(Reflect)] #[reflect(from_reflect = false)] struct Bar; fn test<T: FromReflect>(value: T) {} test(Foo); // <-- OK test(Bar); // <-- Panic! Bar does not implement trait `FromReflect` ``` #### `ReflectFromReflect` This PR also automatically adds the `ReflectFromReflect` (introduced in #6245) registration to the derived `GetTypeRegistration` impl— if the type hasn't opted out of `FromReflect` of course. <details> <summary><h4>Improved Deserialization</h4></summary> > **Warning** > This section includes changes that have since been descoped from this PR. They will likely be implemented again in a followup PR. I am mainly leaving these details in for archival purposes, as well as for reference when implementing this logic again. And since we can do all the above, we might as well improve deserialization. We can now choose to deserialize into a Dynamic type or automatically convert it using `FromReflect` under the hood. `[Un]TypedReflectDeserializer::new` will now perform the conversion and return the `Box`'d Real type. `[Un]TypedReflectDeserializer::new_dynamic` will work like what we have now and simply return the `Box`'d Dynamic type. ```rust // Returns the Real type let reflect_deserializer = UntypedReflectDeserializer::new(&registry); let mut deserializer = ron::de::Deserializer::from_str(input)?; let output: SomeStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?; // Returns the Dynamic type let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(&registry); let mut deserializer = ron::de::Deserializer::from_str(input)?; let output: DynamicStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?; ``` </details> --- ## Changelog * `FromReflect` is now automatically derived within the `Reflect` derive macro * This includes auto-registering `ReflectFromReflect` in the derived `GetTypeRegistration` impl * ~~Renamed `TypedReflectDeserializer::new` and `UntypedReflectDeserializer::new` to `TypedReflectDeserializer::new_dynamic` and `UntypedReflectDeserializer::new_dynamic`, respectively~~ **Descoped** * ~~Changed `TypedReflectDeserializer::new` and `UntypedReflectDeserializer::new` to automatically convert the deserialized output using `FromReflect`~~ **Descoped** ## Migration Guide * `FromReflect` is now automatically derived within the `Reflect` derive macro. Items with both derives will need to remove the `FromReflect` one. ```rust // OLD #[derive(Reflect, FromReflect)] struct Foo; // NEW #[derive(Reflect)] struct Foo; ``` If using a manual implementation of `FromReflect` and the `Reflect` derive, users will need to opt-out of the automatic implementation. ```rust // OLD #[derive(Reflect)] struct Foo; impl FromReflect for Foo {/* ... */} // NEW #[derive(Reflect)] #[reflect(from_reflect = false)] struct Foo; impl FromReflect for Foo {/* ... */} ``` <details> <summary><h4>Removed Migrations</h4></summary> > **Warning** > This section includes changes that have since been descoped from this PR. They will likely be implemented again in a followup PR. I am mainly leaving these details in for archival purposes, as well as for reference when implementing this logic again. * The reflect deserializers now perform a `FromReflect` conversion internally. The expected output of `TypedReflectDeserializer::new` and `UntypedReflectDeserializer::new` is no longer a Dynamic (e.g., `DynamicList`), but its Real counterpart (e.g., `Vec<i32>`). ```rust let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(&registry); let mut deserializer = ron::de::Deserializer::from_str(input)?; // OLD let output: DynamicStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?; // NEW let output: SomeStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?; ``` Alternatively, if this behavior isn't desired, use the `TypedReflectDeserializer::new_dynamic` and `UntypedReflectDeserializer::new_dynamic` methods instead: ```rust // OLD let reflect_deserializer = UntypedReflectDeserializer::new(&registry); // NEW let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(&registry); ``` </details> --------- Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-06-29 01:31:34 +00:00
use bevy_reflect::Reflect;
`text_system` split (#7779) # Objective `text_system` runs before the UI layout is calculated and the size of the text node is determined, so it cannot correctly shape the text to fit the layout, and has no way of determining if the text needs to be wrapped. The function `text_constraint` attempts to determine the size of the node from the local size constraints in the `Style` component. It can't be made to work, you have to compute the whole layout to get the correct size. A simple example of where this fails completely is a text node set to stretch to fill the empty space adjacent to a node with size constraints set to `Val::Percent(50.)`. The text node will take up half the space, even though its size constraints are `Val::Auto` Also because the `text_system` queries for changes to the `Style` component, when a style value is changed that doesn't affect the node's geometry the text is recomputed unnecessarily. Querying on changes to `Node` is not much better. The UI layout is changed to fit the `CalculatedSize` of the text, so the size of the node is changed and so the text and UI layout get recalculated multiple times from a single change to a `Text`. Also, the `MeasureFunc` doesn't work at all, it doesn't have enough information to fit the text correctly and makes no attempt. Fixes #7663, #6717, #5834, #1490, ## Solution Split the `text_system` into two functions: * `measure_text_system` which calculates the size constraints for the text node and runs before `UiSystem::Flex` * `text_system` which runs after `UiSystem::Flex` and generates the actual text. * Fix the `MeasureFunc` calculations. --- Text wrapping in main: <img width="961" alt="Capturemain" src="https://user-images.githubusercontent.com/27962798/220425740-4fe4bf46-24fb-4685-a1cf-bc01e139e72d.PNG"> With this PR: <img width="961" alt="captured_wrap" src="https://user-images.githubusercontent.com/27962798/220425807-949996b0-f127-4637-9f33-56a6da944fb0.PNG"> ## Changelog * Removed the previous fields from `CalculatedSize`. `CalculatedSize` now contains a boxed `Measure`. * Added `measurement` module to `bevy_ui`. * Added the method `create_text_measure` to `TextPipeline`. * Added a new system `measure_text_system` that runs before `UiSystem::Flex` that creates a `MeasureFunc` for the text. * Rescheduled `text_system` to run after `UiSystem::Flex`. * Added a trait `Measure`. A `Measure` is used to compute the size of a UI node when the size of that node is based on its content. * Added `ImageMeasure` and `TextMeasure` which implement `Measure`. * Added a new component `UiImageSize` which is used by `update_image_calculated_size_system` to track image size changes. * Added a `UiImageSize` component to `ImageBundle`. ## Migration Guide `ImageBundle` has a new component `UiImageSize` which contains the size of the image bundle's texture and is updated automatically by `update_image_calculated_size_system` --------- Co-authored-by: François <mockersf@gmail.com>
2023-04-17 15:23:21 +00:00
use std::fmt::Formatter;
pub use taffy::style::AvailableSpace;
use taffy::{node::MeasureFunc, prelude::Size as TaffySize};
`text_system` split (#7779) # Objective `text_system` runs before the UI layout is calculated and the size of the text node is determined, so it cannot correctly shape the text to fit the layout, and has no way of determining if the text needs to be wrapped. The function `text_constraint` attempts to determine the size of the node from the local size constraints in the `Style` component. It can't be made to work, you have to compute the whole layout to get the correct size. A simple example of where this fails completely is a text node set to stretch to fill the empty space adjacent to a node with size constraints set to `Val::Percent(50.)`. The text node will take up half the space, even though its size constraints are `Val::Auto` Also because the `text_system` queries for changes to the `Style` component, when a style value is changed that doesn't affect the node's geometry the text is recomputed unnecessarily. Querying on changes to `Node` is not much better. The UI layout is changed to fit the `CalculatedSize` of the text, so the size of the node is changed and so the text and UI layout get recalculated multiple times from a single change to a `Text`. Also, the `MeasureFunc` doesn't work at all, it doesn't have enough information to fit the text correctly and makes no attempt. Fixes #7663, #6717, #5834, #1490, ## Solution Split the `text_system` into two functions: * `measure_text_system` which calculates the size constraints for the text node and runs before `UiSystem::Flex` * `text_system` which runs after `UiSystem::Flex` and generates the actual text. * Fix the `MeasureFunc` calculations. --- Text wrapping in main: <img width="961" alt="Capturemain" src="https://user-images.githubusercontent.com/27962798/220425740-4fe4bf46-24fb-4685-a1cf-bc01e139e72d.PNG"> With this PR: <img width="961" alt="captured_wrap" src="https://user-images.githubusercontent.com/27962798/220425807-949996b0-f127-4637-9f33-56a6da944fb0.PNG"> ## Changelog * Removed the previous fields from `CalculatedSize`. `CalculatedSize` now contains a boxed `Measure`. * Added `measurement` module to `bevy_ui`. * Added the method `create_text_measure` to `TextPipeline`. * Added a new system `measure_text_system` that runs before `UiSystem::Flex` that creates a `MeasureFunc` for the text. * Rescheduled `text_system` to run after `UiSystem::Flex`. * Added a trait `Measure`. A `Measure` is used to compute the size of a UI node when the size of that node is based on its content. * Added `ImageMeasure` and `TextMeasure` which implement `Measure`. * Added a new component `UiImageSize` which is used by `update_image_calculated_size_system` to track image size changes. * Added a `UiImageSize` component to `ImageBundle`. ## Migration Guide `ImageBundle` has a new component `UiImageSize` which contains the size of the image bundle's texture and is updated automatically by `update_image_calculated_size_system` --------- Co-authored-by: François <mockersf@gmail.com>
2023-04-17 15:23:21 +00:00
`MeasureFunc` improvements (#8402) # Objective fixes #8516 * Give `CalculatedSize` a more specific and intuitive name. * `MeasureFunc`s should only be updated when their `CalculatedSize` is modified by the systems managing their content. For example, suppose that you have a UI displaying an image using an `ImageNode`. When the window is resized, the node's `MeasureFunc` will be updated even though the dimensions of the texture contained by the node are unchanged. * Fix the `CalculatedSize` API so that it no longer requires the extra boxing and the `dyn_clone` method. ## Solution * Rename `CalculatedSize` to `ContentSize` * Only update `MeasureFunc`s on `CalculatedSize` changes. * Remove the `dyn_clone` method from `Measure` and move the `Measure` from the `ContentSize` component rather than cloning it. * Change the measure_func field of `ContentSize` to type `Option<taffy::node::MeasureFunc>`. Add a `set` method that wraps the given measure appropriately. --- ## Changelog * Renamed `CalculatedSize` to `ContentSize`. * Replaced `upsert_leaf` with a function `update_measure` that only updates the node's `MeasureFunc`. * `MeasureFunc`s are only updated when the `ContentSize` changes and not when the layout changes. * Scale factor is no longer applied to the size values passed to the `MeasureFunc`. * Remove the `ContentSize` scaling in `text_system`. * The `dyn_clone` method has been removed from the `Measure` trait. * `Measure`s are moved from the `ContentSize` component instead of cloning them. * Added `set` method to `ContentSize` that replaces the `new` function. ## Migration Guide * `CalculatedSize` has been renamed to `ContentSize`. * The `upsert_leaf` function has been removed from `UiSurface` and replaced with `update_measure` which updates the `MeasureFunc` without node insertion. * The `dyn_clone` method has been removed from the `Measure` trait. * The new function of `CalculatedSize` has been replaced with the method `set`.
2023-05-01 15:40:53 +00:00
impl std::fmt::Debug for ContentSize {
`text_system` split (#7779) # Objective `text_system` runs before the UI layout is calculated and the size of the text node is determined, so it cannot correctly shape the text to fit the layout, and has no way of determining if the text needs to be wrapped. The function `text_constraint` attempts to determine the size of the node from the local size constraints in the `Style` component. It can't be made to work, you have to compute the whole layout to get the correct size. A simple example of where this fails completely is a text node set to stretch to fill the empty space adjacent to a node with size constraints set to `Val::Percent(50.)`. The text node will take up half the space, even though its size constraints are `Val::Auto` Also because the `text_system` queries for changes to the `Style` component, when a style value is changed that doesn't affect the node's geometry the text is recomputed unnecessarily. Querying on changes to `Node` is not much better. The UI layout is changed to fit the `CalculatedSize` of the text, so the size of the node is changed and so the text and UI layout get recalculated multiple times from a single change to a `Text`. Also, the `MeasureFunc` doesn't work at all, it doesn't have enough information to fit the text correctly and makes no attempt. Fixes #7663, #6717, #5834, #1490, ## Solution Split the `text_system` into two functions: * `measure_text_system` which calculates the size constraints for the text node and runs before `UiSystem::Flex` * `text_system` which runs after `UiSystem::Flex` and generates the actual text. * Fix the `MeasureFunc` calculations. --- Text wrapping in main: <img width="961" alt="Capturemain" src="https://user-images.githubusercontent.com/27962798/220425740-4fe4bf46-24fb-4685-a1cf-bc01e139e72d.PNG"> With this PR: <img width="961" alt="captured_wrap" src="https://user-images.githubusercontent.com/27962798/220425807-949996b0-f127-4637-9f33-56a6da944fb0.PNG"> ## Changelog * Removed the previous fields from `CalculatedSize`. `CalculatedSize` now contains a boxed `Measure`. * Added `measurement` module to `bevy_ui`. * Added the method `create_text_measure` to `TextPipeline`. * Added a new system `measure_text_system` that runs before `UiSystem::Flex` that creates a `MeasureFunc` for the text. * Rescheduled `text_system` to run after `UiSystem::Flex`. * Added a trait `Measure`. A `Measure` is used to compute the size of a UI node when the size of that node is based on its content. * Added `ImageMeasure` and `TextMeasure` which implement `Measure`. * Added a new component `UiImageSize` which is used by `update_image_calculated_size_system` to track image size changes. * Added a `UiImageSize` component to `ImageBundle`. ## Migration Guide `ImageBundle` has a new component `UiImageSize` which contains the size of the image bundle's texture and is updated automatically by `update_image_calculated_size_system` --------- Co-authored-by: François <mockersf@gmail.com>
2023-04-17 15:23:21 +00:00
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
`MeasureFunc` improvements (#8402) # Objective fixes #8516 * Give `CalculatedSize` a more specific and intuitive name. * `MeasureFunc`s should only be updated when their `CalculatedSize` is modified by the systems managing their content. For example, suppose that you have a UI displaying an image using an `ImageNode`. When the window is resized, the node's `MeasureFunc` will be updated even though the dimensions of the texture contained by the node are unchanged. * Fix the `CalculatedSize` API so that it no longer requires the extra boxing and the `dyn_clone` method. ## Solution * Rename `CalculatedSize` to `ContentSize` * Only update `MeasureFunc`s on `CalculatedSize` changes. * Remove the `dyn_clone` method from `Measure` and move the `Measure` from the `ContentSize` component rather than cloning it. * Change the measure_func field of `ContentSize` to type `Option<taffy::node::MeasureFunc>`. Add a `set` method that wraps the given measure appropriately. --- ## Changelog * Renamed `CalculatedSize` to `ContentSize`. * Replaced `upsert_leaf` with a function `update_measure` that only updates the node's `MeasureFunc`. * `MeasureFunc`s are only updated when the `ContentSize` changes and not when the layout changes. * Scale factor is no longer applied to the size values passed to the `MeasureFunc`. * Remove the `ContentSize` scaling in `text_system`. * The `dyn_clone` method has been removed from the `Measure` trait. * `Measure`s are moved from the `ContentSize` component instead of cloning them. * Added `set` method to `ContentSize` that replaces the `new` function. ## Migration Guide * `CalculatedSize` has been renamed to `ContentSize`. * The `upsert_leaf` function has been removed from `UiSurface` and replaced with `update_measure` which updates the `MeasureFunc` without node insertion. * The `dyn_clone` method has been removed from the `Measure` trait. * The new function of `CalculatedSize` has been replaced with the method `set`.
2023-05-01 15:40:53 +00:00
f.debug_struct("ContentSize").finish()
`text_system` split (#7779) # Objective `text_system` runs before the UI layout is calculated and the size of the text node is determined, so it cannot correctly shape the text to fit the layout, and has no way of determining if the text needs to be wrapped. The function `text_constraint` attempts to determine the size of the node from the local size constraints in the `Style` component. It can't be made to work, you have to compute the whole layout to get the correct size. A simple example of where this fails completely is a text node set to stretch to fill the empty space adjacent to a node with size constraints set to `Val::Percent(50.)`. The text node will take up half the space, even though its size constraints are `Val::Auto` Also because the `text_system` queries for changes to the `Style` component, when a style value is changed that doesn't affect the node's geometry the text is recomputed unnecessarily. Querying on changes to `Node` is not much better. The UI layout is changed to fit the `CalculatedSize` of the text, so the size of the node is changed and so the text and UI layout get recalculated multiple times from a single change to a `Text`. Also, the `MeasureFunc` doesn't work at all, it doesn't have enough information to fit the text correctly and makes no attempt. Fixes #7663, #6717, #5834, #1490, ## Solution Split the `text_system` into two functions: * `measure_text_system` which calculates the size constraints for the text node and runs before `UiSystem::Flex` * `text_system` which runs after `UiSystem::Flex` and generates the actual text. * Fix the `MeasureFunc` calculations. --- Text wrapping in main: <img width="961" alt="Capturemain" src="https://user-images.githubusercontent.com/27962798/220425740-4fe4bf46-24fb-4685-a1cf-bc01e139e72d.PNG"> With this PR: <img width="961" alt="captured_wrap" src="https://user-images.githubusercontent.com/27962798/220425807-949996b0-f127-4637-9f33-56a6da944fb0.PNG"> ## Changelog * Removed the previous fields from `CalculatedSize`. `CalculatedSize` now contains a boxed `Measure`. * Added `measurement` module to `bevy_ui`. * Added the method `create_text_measure` to `TextPipeline`. * Added a new system `measure_text_system` that runs before `UiSystem::Flex` that creates a `MeasureFunc` for the text. * Rescheduled `text_system` to run after `UiSystem::Flex`. * Added a trait `Measure`. A `Measure` is used to compute the size of a UI node when the size of that node is based on its content. * Added `ImageMeasure` and `TextMeasure` which implement `Measure`. * Added a new component `UiImageSize` which is used by `update_image_calculated_size_system` to track image size changes. * Added a `UiImageSize` component to `ImageBundle`. ## Migration Guide `ImageBundle` has a new component `UiImageSize` which contains the size of the image bundle's texture and is updated automatically by `update_image_calculated_size_system` --------- Co-authored-by: François <mockersf@gmail.com>
2023-04-17 15:23:21 +00:00
}
}
/// A `Measure` is used to compute the size of a ui node
/// when the size of that node is based on its content.
pub trait Measure: Send + Sync + 'static {
/// Calculate the size of the node given the constraints.
fn measure(
&self,
width: Option<f32>,
height: Option<f32>,
available_width: AvailableSpace,
available_height: AvailableSpace,
) -> Vec2;
}
/// A `FixedMeasure` is a `Measure` that ignores all constraints and
/// always returns the same size.
#[derive(Default, Clone)]
pub struct FixedMeasure {
2023-06-26 16:23:00 +00:00
pub size: Vec2,
`text_system` split (#7779) # Objective `text_system` runs before the UI layout is calculated and the size of the text node is determined, so it cannot correctly shape the text to fit the layout, and has no way of determining if the text needs to be wrapped. The function `text_constraint` attempts to determine the size of the node from the local size constraints in the `Style` component. It can't be made to work, you have to compute the whole layout to get the correct size. A simple example of where this fails completely is a text node set to stretch to fill the empty space adjacent to a node with size constraints set to `Val::Percent(50.)`. The text node will take up half the space, even though its size constraints are `Val::Auto` Also because the `text_system` queries for changes to the `Style` component, when a style value is changed that doesn't affect the node's geometry the text is recomputed unnecessarily. Querying on changes to `Node` is not much better. The UI layout is changed to fit the `CalculatedSize` of the text, so the size of the node is changed and so the text and UI layout get recalculated multiple times from a single change to a `Text`. Also, the `MeasureFunc` doesn't work at all, it doesn't have enough information to fit the text correctly and makes no attempt. Fixes #7663, #6717, #5834, #1490, ## Solution Split the `text_system` into two functions: * `measure_text_system` which calculates the size constraints for the text node and runs before `UiSystem::Flex` * `text_system` which runs after `UiSystem::Flex` and generates the actual text. * Fix the `MeasureFunc` calculations. --- Text wrapping in main: <img width="961" alt="Capturemain" src="https://user-images.githubusercontent.com/27962798/220425740-4fe4bf46-24fb-4685-a1cf-bc01e139e72d.PNG"> With this PR: <img width="961" alt="captured_wrap" src="https://user-images.githubusercontent.com/27962798/220425807-949996b0-f127-4637-9f33-56a6da944fb0.PNG"> ## Changelog * Removed the previous fields from `CalculatedSize`. `CalculatedSize` now contains a boxed `Measure`. * Added `measurement` module to `bevy_ui`. * Added the method `create_text_measure` to `TextPipeline`. * Added a new system `measure_text_system` that runs before `UiSystem::Flex` that creates a `MeasureFunc` for the text. * Rescheduled `text_system` to run after `UiSystem::Flex`. * Added a trait `Measure`. A `Measure` is used to compute the size of a UI node when the size of that node is based on its content. * Added `ImageMeasure` and `TextMeasure` which implement `Measure`. * Added a new component `UiImageSize` which is used by `update_image_calculated_size_system` to track image size changes. * Added a `UiImageSize` component to `ImageBundle`. ## Migration Guide `ImageBundle` has a new component `UiImageSize` which contains the size of the image bundle's texture and is updated automatically by `update_image_calculated_size_system` --------- Co-authored-by: François <mockersf@gmail.com>
2023-04-17 15:23:21 +00:00
}
impl Measure for FixedMeasure {
fn measure(
&self,
_: Option<f32>,
_: Option<f32>,
_: AvailableSpace,
_: AvailableSpace,
) -> Vec2 {
self.size
}
}
`MeasureFunc` improvements (#8402) # Objective fixes #8516 * Give `CalculatedSize` a more specific and intuitive name. * `MeasureFunc`s should only be updated when their `CalculatedSize` is modified by the systems managing their content. For example, suppose that you have a UI displaying an image using an `ImageNode`. When the window is resized, the node's `MeasureFunc` will be updated even though the dimensions of the texture contained by the node are unchanged. * Fix the `CalculatedSize` API so that it no longer requires the extra boxing and the `dyn_clone` method. ## Solution * Rename `CalculatedSize` to `ContentSize` * Only update `MeasureFunc`s on `CalculatedSize` changes. * Remove the `dyn_clone` method from `Measure` and move the `Measure` from the `ContentSize` component rather than cloning it. * Change the measure_func field of `ContentSize` to type `Option<taffy::node::MeasureFunc>`. Add a `set` method that wraps the given measure appropriately. --- ## Changelog * Renamed `CalculatedSize` to `ContentSize`. * Replaced `upsert_leaf` with a function `update_measure` that only updates the node's `MeasureFunc`. * `MeasureFunc`s are only updated when the `ContentSize` changes and not when the layout changes. * Scale factor is no longer applied to the size values passed to the `MeasureFunc`. * Remove the `ContentSize` scaling in `text_system`. * The `dyn_clone` method has been removed from the `Measure` trait. * `Measure`s are moved from the `ContentSize` component instead of cloning them. * Added `set` method to `ContentSize` that replaces the `new` function. ## Migration Guide * `CalculatedSize` has been renamed to `ContentSize`. * The `upsert_leaf` function has been removed from `UiSurface` and replaced with `update_measure` which updates the `MeasureFunc` without node insertion. * The `dyn_clone` method has been removed from the `Measure` trait. * The new function of `CalculatedSize` has been replaced with the method `set`.
2023-05-01 15:40:53 +00:00
/// A node with a `ContentSize` component is a node where its size
`text_system` split (#7779) # Objective `text_system` runs before the UI layout is calculated and the size of the text node is determined, so it cannot correctly shape the text to fit the layout, and has no way of determining if the text needs to be wrapped. The function `text_constraint` attempts to determine the size of the node from the local size constraints in the `Style` component. It can't be made to work, you have to compute the whole layout to get the correct size. A simple example of where this fails completely is a text node set to stretch to fill the empty space adjacent to a node with size constraints set to `Val::Percent(50.)`. The text node will take up half the space, even though its size constraints are `Val::Auto` Also because the `text_system` queries for changes to the `Style` component, when a style value is changed that doesn't affect the node's geometry the text is recomputed unnecessarily. Querying on changes to `Node` is not much better. The UI layout is changed to fit the `CalculatedSize` of the text, so the size of the node is changed and so the text and UI layout get recalculated multiple times from a single change to a `Text`. Also, the `MeasureFunc` doesn't work at all, it doesn't have enough information to fit the text correctly and makes no attempt. Fixes #7663, #6717, #5834, #1490, ## Solution Split the `text_system` into two functions: * `measure_text_system` which calculates the size constraints for the text node and runs before `UiSystem::Flex` * `text_system` which runs after `UiSystem::Flex` and generates the actual text. * Fix the `MeasureFunc` calculations. --- Text wrapping in main: <img width="961" alt="Capturemain" src="https://user-images.githubusercontent.com/27962798/220425740-4fe4bf46-24fb-4685-a1cf-bc01e139e72d.PNG"> With this PR: <img width="961" alt="captured_wrap" src="https://user-images.githubusercontent.com/27962798/220425807-949996b0-f127-4637-9f33-56a6da944fb0.PNG"> ## Changelog * Removed the previous fields from `CalculatedSize`. `CalculatedSize` now contains a boxed `Measure`. * Added `measurement` module to `bevy_ui`. * Added the method `create_text_measure` to `TextPipeline`. * Added a new system `measure_text_system` that runs before `UiSystem::Flex` that creates a `MeasureFunc` for the text. * Rescheduled `text_system` to run after `UiSystem::Flex`. * Added a trait `Measure`. A `Measure` is used to compute the size of a UI node when the size of that node is based on its content. * Added `ImageMeasure` and `TextMeasure` which implement `Measure`. * Added a new component `UiImageSize` which is used by `update_image_calculated_size_system` to track image size changes. * Added a `UiImageSize` component to `ImageBundle`. ## Migration Guide `ImageBundle` has a new component `UiImageSize` which contains the size of the image bundle's texture and is updated automatically by `update_image_calculated_size_system` --------- Co-authored-by: François <mockersf@gmail.com>
2023-04-17 15:23:21 +00:00
/// is based on its content.
bevy_reflect: `FromReflect` Ergonomics Implementation (#6056) # Objective **This implementation is based on https://github.com/bevyengine/rfcs/pull/59.** --- Resolves #4597 Full details and motivation can be found in the RFC, but here's a brief summary. `FromReflect` is a very powerful and important trait within the reflection API. It allows Dynamic types (e.g., `DynamicList`, etc.) to be formed into Real ones (e.g., `Vec<i32>`, etc.). This mainly comes into play concerning deserialization, where the reflection deserializers both return a `Box<dyn Reflect>` that almost always contain one of these Dynamic representations of a Real type. To convert this to our Real type, we need to use `FromReflect`. It also sneaks up in other ways. For example, it's a required bound for `T` in `Vec<T>` so that `Vec<T>` as a whole can be made `FromReflect`. It's also required by all fields of an enum as it's used as part of the `Reflect::apply` implementation. So in other words, much like `GetTypeRegistration` and `Typed`, it is very much a core reflection trait. The problem is that it is not currently treated like a core trait and is not automatically derived alongside `Reflect`. This makes using it a bit cumbersome and easy to forget. ## Solution Automatically derive `FromReflect` when deriving `Reflect`. Users can then choose to opt-out if needed using the `#[reflect(from_reflect = false)]` attribute. ```rust #[derive(Reflect)] struct Foo; #[derive(Reflect)] #[reflect(from_reflect = false)] struct Bar; fn test<T: FromReflect>(value: T) {} test(Foo); // <-- OK test(Bar); // <-- Panic! Bar does not implement trait `FromReflect` ``` #### `ReflectFromReflect` This PR also automatically adds the `ReflectFromReflect` (introduced in #6245) registration to the derived `GetTypeRegistration` impl— if the type hasn't opted out of `FromReflect` of course. <details> <summary><h4>Improved Deserialization</h4></summary> > **Warning** > This section includes changes that have since been descoped from this PR. They will likely be implemented again in a followup PR. I am mainly leaving these details in for archival purposes, as well as for reference when implementing this logic again. And since we can do all the above, we might as well improve deserialization. We can now choose to deserialize into a Dynamic type or automatically convert it using `FromReflect` under the hood. `[Un]TypedReflectDeserializer::new` will now perform the conversion and return the `Box`'d Real type. `[Un]TypedReflectDeserializer::new_dynamic` will work like what we have now and simply return the `Box`'d Dynamic type. ```rust // Returns the Real type let reflect_deserializer = UntypedReflectDeserializer::new(&registry); let mut deserializer = ron::de::Deserializer::from_str(input)?; let output: SomeStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?; // Returns the Dynamic type let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(&registry); let mut deserializer = ron::de::Deserializer::from_str(input)?; let output: DynamicStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?; ``` </details> --- ## Changelog * `FromReflect` is now automatically derived within the `Reflect` derive macro * This includes auto-registering `ReflectFromReflect` in the derived `GetTypeRegistration` impl * ~~Renamed `TypedReflectDeserializer::new` and `UntypedReflectDeserializer::new` to `TypedReflectDeserializer::new_dynamic` and `UntypedReflectDeserializer::new_dynamic`, respectively~~ **Descoped** * ~~Changed `TypedReflectDeserializer::new` and `UntypedReflectDeserializer::new` to automatically convert the deserialized output using `FromReflect`~~ **Descoped** ## Migration Guide * `FromReflect` is now automatically derived within the `Reflect` derive macro. Items with both derives will need to remove the `FromReflect` one. ```rust // OLD #[derive(Reflect, FromReflect)] struct Foo; // NEW #[derive(Reflect)] struct Foo; ``` If using a manual implementation of `FromReflect` and the `Reflect` derive, users will need to opt-out of the automatic implementation. ```rust // OLD #[derive(Reflect)] struct Foo; impl FromReflect for Foo {/* ... */} // NEW #[derive(Reflect)] #[reflect(from_reflect = false)] struct Foo; impl FromReflect for Foo {/* ... */} ``` <details> <summary><h4>Removed Migrations</h4></summary> > **Warning** > This section includes changes that have since been descoped from this PR. They will likely be implemented again in a followup PR. I am mainly leaving these details in for archival purposes, as well as for reference when implementing this logic again. * The reflect deserializers now perform a `FromReflect` conversion internally. The expected output of `TypedReflectDeserializer::new` and `UntypedReflectDeserializer::new` is no longer a Dynamic (e.g., `DynamicList`), but its Real counterpart (e.g., `Vec<i32>`). ```rust let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(&registry); let mut deserializer = ron::de::Deserializer::from_str(input)?; // OLD let output: DynamicStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?; // NEW let output: SomeStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?; ``` Alternatively, if this behavior isn't desired, use the `TypedReflectDeserializer::new_dynamic` and `UntypedReflectDeserializer::new_dynamic` methods instead: ```rust // OLD let reflect_deserializer = UntypedReflectDeserializer::new(&registry); // NEW let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(&registry); ``` </details> --------- Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-06-29 01:31:34 +00:00
#[derive(Component, Reflect)]
#[reflect(Component)]
`MeasureFunc` improvements (#8402) # Objective fixes #8516 * Give `CalculatedSize` a more specific and intuitive name. * `MeasureFunc`s should only be updated when their `CalculatedSize` is modified by the systems managing their content. For example, suppose that you have a UI displaying an image using an `ImageNode`. When the window is resized, the node's `MeasureFunc` will be updated even though the dimensions of the texture contained by the node are unchanged. * Fix the `CalculatedSize` API so that it no longer requires the extra boxing and the `dyn_clone` method. ## Solution * Rename `CalculatedSize` to `ContentSize` * Only update `MeasureFunc`s on `CalculatedSize` changes. * Remove the `dyn_clone` method from `Measure` and move the `Measure` from the `ContentSize` component rather than cloning it. * Change the measure_func field of `ContentSize` to type `Option<taffy::node::MeasureFunc>`. Add a `set` method that wraps the given measure appropriately. --- ## Changelog * Renamed `CalculatedSize` to `ContentSize`. * Replaced `upsert_leaf` with a function `update_measure` that only updates the node's `MeasureFunc`. * `MeasureFunc`s are only updated when the `ContentSize` changes and not when the layout changes. * Scale factor is no longer applied to the size values passed to the `MeasureFunc`. * Remove the `ContentSize` scaling in `text_system`. * The `dyn_clone` method has been removed from the `Measure` trait. * `Measure`s are moved from the `ContentSize` component instead of cloning them. * Added `set` method to `ContentSize` that replaces the `new` function. ## Migration Guide * `CalculatedSize` has been renamed to `ContentSize`. * The `upsert_leaf` function has been removed from `UiSurface` and replaced with `update_measure` which updates the `MeasureFunc` without node insertion. * The `dyn_clone` method has been removed from the `Measure` trait. * The new function of `CalculatedSize` has been replaced with the method `set`.
2023-05-01 15:40:53 +00:00
pub struct ContentSize {
`text_system` split (#7779) # Objective `text_system` runs before the UI layout is calculated and the size of the text node is determined, so it cannot correctly shape the text to fit the layout, and has no way of determining if the text needs to be wrapped. The function `text_constraint` attempts to determine the size of the node from the local size constraints in the `Style` component. It can't be made to work, you have to compute the whole layout to get the correct size. A simple example of where this fails completely is a text node set to stretch to fill the empty space adjacent to a node with size constraints set to `Val::Percent(50.)`. The text node will take up half the space, even though its size constraints are `Val::Auto` Also because the `text_system` queries for changes to the `Style` component, when a style value is changed that doesn't affect the node's geometry the text is recomputed unnecessarily. Querying on changes to `Node` is not much better. The UI layout is changed to fit the `CalculatedSize` of the text, so the size of the node is changed and so the text and UI layout get recalculated multiple times from a single change to a `Text`. Also, the `MeasureFunc` doesn't work at all, it doesn't have enough information to fit the text correctly and makes no attempt. Fixes #7663, #6717, #5834, #1490, ## Solution Split the `text_system` into two functions: * `measure_text_system` which calculates the size constraints for the text node and runs before `UiSystem::Flex` * `text_system` which runs after `UiSystem::Flex` and generates the actual text. * Fix the `MeasureFunc` calculations. --- Text wrapping in main: <img width="961" alt="Capturemain" src="https://user-images.githubusercontent.com/27962798/220425740-4fe4bf46-24fb-4685-a1cf-bc01e139e72d.PNG"> With this PR: <img width="961" alt="captured_wrap" src="https://user-images.githubusercontent.com/27962798/220425807-949996b0-f127-4637-9f33-56a6da944fb0.PNG"> ## Changelog * Removed the previous fields from `CalculatedSize`. `CalculatedSize` now contains a boxed `Measure`. * Added `measurement` module to `bevy_ui`. * Added the method `create_text_measure` to `TextPipeline`. * Added a new system `measure_text_system` that runs before `UiSystem::Flex` that creates a `MeasureFunc` for the text. * Rescheduled `text_system` to run after `UiSystem::Flex`. * Added a trait `Measure`. A `Measure` is used to compute the size of a UI node when the size of that node is based on its content. * Added `ImageMeasure` and `TextMeasure` which implement `Measure`. * Added a new component `UiImageSize` which is used by `update_image_calculated_size_system` to track image size changes. * Added a `UiImageSize` component to `ImageBundle`. ## Migration Guide `ImageBundle` has a new component `UiImageSize` which contains the size of the image bundle's texture and is updated automatically by `update_image_calculated_size_system` --------- Co-authored-by: François <mockersf@gmail.com>
2023-04-17 15:23:21 +00:00
/// The `Measure` used to compute the intrinsic size
#[reflect(ignore)]
pub(crate) measure_func: Option<MeasureFunc>,
`text_system` split (#7779) # Objective `text_system` runs before the UI layout is calculated and the size of the text node is determined, so it cannot correctly shape the text to fit the layout, and has no way of determining if the text needs to be wrapped. The function `text_constraint` attempts to determine the size of the node from the local size constraints in the `Style` component. It can't be made to work, you have to compute the whole layout to get the correct size. A simple example of where this fails completely is a text node set to stretch to fill the empty space adjacent to a node with size constraints set to `Val::Percent(50.)`. The text node will take up half the space, even though its size constraints are `Val::Auto` Also because the `text_system` queries for changes to the `Style` component, when a style value is changed that doesn't affect the node's geometry the text is recomputed unnecessarily. Querying on changes to `Node` is not much better. The UI layout is changed to fit the `CalculatedSize` of the text, so the size of the node is changed and so the text and UI layout get recalculated multiple times from a single change to a `Text`. Also, the `MeasureFunc` doesn't work at all, it doesn't have enough information to fit the text correctly and makes no attempt. Fixes #7663, #6717, #5834, #1490, ## Solution Split the `text_system` into two functions: * `measure_text_system` which calculates the size constraints for the text node and runs before `UiSystem::Flex` * `text_system` which runs after `UiSystem::Flex` and generates the actual text. * Fix the `MeasureFunc` calculations. --- Text wrapping in main: <img width="961" alt="Capturemain" src="https://user-images.githubusercontent.com/27962798/220425740-4fe4bf46-24fb-4685-a1cf-bc01e139e72d.PNG"> With this PR: <img width="961" alt="captured_wrap" src="https://user-images.githubusercontent.com/27962798/220425807-949996b0-f127-4637-9f33-56a6da944fb0.PNG"> ## Changelog * Removed the previous fields from `CalculatedSize`. `CalculatedSize` now contains a boxed `Measure`. * Added `measurement` module to `bevy_ui`. * Added the method `create_text_measure` to `TextPipeline`. * Added a new system `measure_text_system` that runs before `UiSystem::Flex` that creates a `MeasureFunc` for the text. * Rescheduled `text_system` to run after `UiSystem::Flex`. * Added a trait `Measure`. A `Measure` is used to compute the size of a UI node when the size of that node is based on its content. * Added `ImageMeasure` and `TextMeasure` which implement `Measure`. * Added a new component `UiImageSize` which is used by `update_image_calculated_size_system` to track image size changes. * Added a `UiImageSize` component to `ImageBundle`. ## Migration Guide `ImageBundle` has a new component `UiImageSize` which contains the size of the image bundle's texture and is updated automatically by `update_image_calculated_size_system` --------- Co-authored-by: François <mockersf@gmail.com>
2023-04-17 15:23:21 +00:00
}
`MeasureFunc` improvements (#8402) # Objective fixes #8516 * Give `CalculatedSize` a more specific and intuitive name. * `MeasureFunc`s should only be updated when their `CalculatedSize` is modified by the systems managing their content. For example, suppose that you have a UI displaying an image using an `ImageNode`. When the window is resized, the node's `MeasureFunc` will be updated even though the dimensions of the texture contained by the node are unchanged. * Fix the `CalculatedSize` API so that it no longer requires the extra boxing and the `dyn_clone` method. ## Solution * Rename `CalculatedSize` to `ContentSize` * Only update `MeasureFunc`s on `CalculatedSize` changes. * Remove the `dyn_clone` method from `Measure` and move the `Measure` from the `ContentSize` component rather than cloning it. * Change the measure_func field of `ContentSize` to type `Option<taffy::node::MeasureFunc>`. Add a `set` method that wraps the given measure appropriately. --- ## Changelog * Renamed `CalculatedSize` to `ContentSize`. * Replaced `upsert_leaf` with a function `update_measure` that only updates the node's `MeasureFunc`. * `MeasureFunc`s are only updated when the `ContentSize` changes and not when the layout changes. * Scale factor is no longer applied to the size values passed to the `MeasureFunc`. * Remove the `ContentSize` scaling in `text_system`. * The `dyn_clone` method has been removed from the `Measure` trait. * `Measure`s are moved from the `ContentSize` component instead of cloning them. * Added `set` method to `ContentSize` that replaces the `new` function. ## Migration Guide * `CalculatedSize` has been renamed to `ContentSize`. * The `upsert_leaf` function has been removed from `UiSurface` and replaced with `update_measure` which updates the `MeasureFunc` without node insertion. * The `dyn_clone` method has been removed from the `Measure` trait. * The new function of `CalculatedSize` has been replaced with the method `set`.
2023-05-01 15:40:53 +00:00
impl ContentSize {
/// Set a `Measure` for this function
pub fn set(&mut self, measure: impl Measure) {
let measure_func = move |size: TaffySize<_>, available: TaffySize<_>| {
let size = measure.measure(size.width, size.height, available.width, available.height);
TaffySize {
width: size.x,
height: size.y,
}
};
self.measure_func = Some(MeasureFunc::Boxed(Box::new(measure_func)));
`text_system` split (#7779) # Objective `text_system` runs before the UI layout is calculated and the size of the text node is determined, so it cannot correctly shape the text to fit the layout, and has no way of determining if the text needs to be wrapped. The function `text_constraint` attempts to determine the size of the node from the local size constraints in the `Style` component. It can't be made to work, you have to compute the whole layout to get the correct size. A simple example of where this fails completely is a text node set to stretch to fill the empty space adjacent to a node with size constraints set to `Val::Percent(50.)`. The text node will take up half the space, even though its size constraints are `Val::Auto` Also because the `text_system` queries for changes to the `Style` component, when a style value is changed that doesn't affect the node's geometry the text is recomputed unnecessarily. Querying on changes to `Node` is not much better. The UI layout is changed to fit the `CalculatedSize` of the text, so the size of the node is changed and so the text and UI layout get recalculated multiple times from a single change to a `Text`. Also, the `MeasureFunc` doesn't work at all, it doesn't have enough information to fit the text correctly and makes no attempt. Fixes #7663, #6717, #5834, #1490, ## Solution Split the `text_system` into two functions: * `measure_text_system` which calculates the size constraints for the text node and runs before `UiSystem::Flex` * `text_system` which runs after `UiSystem::Flex` and generates the actual text. * Fix the `MeasureFunc` calculations. --- Text wrapping in main: <img width="961" alt="Capturemain" src="https://user-images.githubusercontent.com/27962798/220425740-4fe4bf46-24fb-4685-a1cf-bc01e139e72d.PNG"> With this PR: <img width="961" alt="captured_wrap" src="https://user-images.githubusercontent.com/27962798/220425807-949996b0-f127-4637-9f33-56a6da944fb0.PNG"> ## Changelog * Removed the previous fields from `CalculatedSize`. `CalculatedSize` now contains a boxed `Measure`. * Added `measurement` module to `bevy_ui`. * Added the method `create_text_measure` to `TextPipeline`. * Added a new system `measure_text_system` that runs before `UiSystem::Flex` that creates a `MeasureFunc` for the text. * Rescheduled `text_system` to run after `UiSystem::Flex`. * Added a trait `Measure`. A `Measure` is used to compute the size of a UI node when the size of that node is based on its content. * Added `ImageMeasure` and `TextMeasure` which implement `Measure`. * Added a new component `UiImageSize` which is used by `update_image_calculated_size_system` to track image size changes. * Added a `UiImageSize` component to `ImageBundle`. ## Migration Guide `ImageBundle` has a new component `UiImageSize` which contains the size of the image bundle's texture and is updated automatically by `update_image_calculated_size_system` --------- Co-authored-by: François <mockersf@gmail.com>
2023-04-17 15:23:21 +00:00
}
}
`MeasureFunc` improvements (#8402) # Objective fixes #8516 * Give `CalculatedSize` a more specific and intuitive name. * `MeasureFunc`s should only be updated when their `CalculatedSize` is modified by the systems managing their content. For example, suppose that you have a UI displaying an image using an `ImageNode`. When the window is resized, the node's `MeasureFunc` will be updated even though the dimensions of the texture contained by the node are unchanged. * Fix the `CalculatedSize` API so that it no longer requires the extra boxing and the `dyn_clone` method. ## Solution * Rename `CalculatedSize` to `ContentSize` * Only update `MeasureFunc`s on `CalculatedSize` changes. * Remove the `dyn_clone` method from `Measure` and move the `Measure` from the `ContentSize` component rather than cloning it. * Change the measure_func field of `ContentSize` to type `Option<taffy::node::MeasureFunc>`. Add a `set` method that wraps the given measure appropriately. --- ## Changelog * Renamed `CalculatedSize` to `ContentSize`. * Replaced `upsert_leaf` with a function `update_measure` that only updates the node's `MeasureFunc`. * `MeasureFunc`s are only updated when the `ContentSize` changes and not when the layout changes. * Scale factor is no longer applied to the size values passed to the `MeasureFunc`. * Remove the `ContentSize` scaling in `text_system`. * The `dyn_clone` method has been removed from the `Measure` trait. * `Measure`s are moved from the `ContentSize` component instead of cloning them. * Added `set` method to `ContentSize` that replaces the `new` function. ## Migration Guide * `CalculatedSize` has been renamed to `ContentSize`. * The `upsert_leaf` function has been removed from `UiSurface` and replaced with `update_measure` which updates the `MeasureFunc` without node insertion. * The `dyn_clone` method has been removed from the `Measure` trait. * The new function of `CalculatedSize` has been replaced with the method `set`.
2023-05-01 15:40:53 +00:00
impl Default for ContentSize {
fn default() -> Self {
`text_system` split (#7779) # Objective `text_system` runs before the UI layout is calculated and the size of the text node is determined, so it cannot correctly shape the text to fit the layout, and has no way of determining if the text needs to be wrapped. The function `text_constraint` attempts to determine the size of the node from the local size constraints in the `Style` component. It can't be made to work, you have to compute the whole layout to get the correct size. A simple example of where this fails completely is a text node set to stretch to fill the empty space adjacent to a node with size constraints set to `Val::Percent(50.)`. The text node will take up half the space, even though its size constraints are `Val::Auto` Also because the `text_system` queries for changes to the `Style` component, when a style value is changed that doesn't affect the node's geometry the text is recomputed unnecessarily. Querying on changes to `Node` is not much better. The UI layout is changed to fit the `CalculatedSize` of the text, so the size of the node is changed and so the text and UI layout get recalculated multiple times from a single change to a `Text`. Also, the `MeasureFunc` doesn't work at all, it doesn't have enough information to fit the text correctly and makes no attempt. Fixes #7663, #6717, #5834, #1490, ## Solution Split the `text_system` into two functions: * `measure_text_system` which calculates the size constraints for the text node and runs before `UiSystem::Flex` * `text_system` which runs after `UiSystem::Flex` and generates the actual text. * Fix the `MeasureFunc` calculations. --- Text wrapping in main: <img width="961" alt="Capturemain" src="https://user-images.githubusercontent.com/27962798/220425740-4fe4bf46-24fb-4685-a1cf-bc01e139e72d.PNG"> With this PR: <img width="961" alt="captured_wrap" src="https://user-images.githubusercontent.com/27962798/220425807-949996b0-f127-4637-9f33-56a6da944fb0.PNG"> ## Changelog * Removed the previous fields from `CalculatedSize`. `CalculatedSize` now contains a boxed `Measure`. * Added `measurement` module to `bevy_ui`. * Added the method `create_text_measure` to `TextPipeline`. * Added a new system `measure_text_system` that runs before `UiSystem::Flex` that creates a `MeasureFunc` for the text. * Rescheduled `text_system` to run after `UiSystem::Flex`. * Added a trait `Measure`. A `Measure` is used to compute the size of a UI node when the size of that node is based on its content. * Added `ImageMeasure` and `TextMeasure` which implement `Measure`. * Added a new component `UiImageSize` which is used by `update_image_calculated_size_system` to track image size changes. * Added a `UiImageSize` component to `ImageBundle`. ## Migration Guide `ImageBundle` has a new component `UiImageSize` which contains the size of the image bundle's texture and is updated automatically by `update_image_calculated_size_system` --------- Co-authored-by: François <mockersf@gmail.com>
2023-04-17 15:23:21 +00:00
Self {
measure_func: Some(MeasureFunc::Raw(|_, _| TaffySize::ZERO)),
`text_system` split (#7779) # Objective `text_system` runs before the UI layout is calculated and the size of the text node is determined, so it cannot correctly shape the text to fit the layout, and has no way of determining if the text needs to be wrapped. The function `text_constraint` attempts to determine the size of the node from the local size constraints in the `Style` component. It can't be made to work, you have to compute the whole layout to get the correct size. A simple example of where this fails completely is a text node set to stretch to fill the empty space adjacent to a node with size constraints set to `Val::Percent(50.)`. The text node will take up half the space, even though its size constraints are `Val::Auto` Also because the `text_system` queries for changes to the `Style` component, when a style value is changed that doesn't affect the node's geometry the text is recomputed unnecessarily. Querying on changes to `Node` is not much better. The UI layout is changed to fit the `CalculatedSize` of the text, so the size of the node is changed and so the text and UI layout get recalculated multiple times from a single change to a `Text`. Also, the `MeasureFunc` doesn't work at all, it doesn't have enough information to fit the text correctly and makes no attempt. Fixes #7663, #6717, #5834, #1490, ## Solution Split the `text_system` into two functions: * `measure_text_system` which calculates the size constraints for the text node and runs before `UiSystem::Flex` * `text_system` which runs after `UiSystem::Flex` and generates the actual text. * Fix the `MeasureFunc` calculations. --- Text wrapping in main: <img width="961" alt="Capturemain" src="https://user-images.githubusercontent.com/27962798/220425740-4fe4bf46-24fb-4685-a1cf-bc01e139e72d.PNG"> With this PR: <img width="961" alt="captured_wrap" src="https://user-images.githubusercontent.com/27962798/220425807-949996b0-f127-4637-9f33-56a6da944fb0.PNG"> ## Changelog * Removed the previous fields from `CalculatedSize`. `CalculatedSize` now contains a boxed `Measure`. * Added `measurement` module to `bevy_ui`. * Added the method `create_text_measure` to `TextPipeline`. * Added a new system `measure_text_system` that runs before `UiSystem::Flex` that creates a `MeasureFunc` for the text. * Rescheduled `text_system` to run after `UiSystem::Flex`. * Added a trait `Measure`. A `Measure` is used to compute the size of a UI node when the size of that node is based on its content. * Added `ImageMeasure` and `TextMeasure` which implement `Measure`. * Added a new component `UiImageSize` which is used by `update_image_calculated_size_system` to track image size changes. * Added a `UiImageSize` component to `ImageBundle`. ## Migration Guide `ImageBundle` has a new component `UiImageSize` which contains the size of the image bundle's texture and is updated automatically by `update_image_calculated_size_system` --------- Co-authored-by: François <mockersf@gmail.com>
2023-04-17 15:23:21 +00:00
}
}
}