# Objective - Fixes https://github.com/bevyengine/bevy/issues/13155 - fixes https://github.com/bevyengine/bevy/issues/13517 - Supercedes https://github.com/bevyengine/bevy/pull/13381 - Requires https://github.com/DioxusLabs/taffy/pull/661 ## Solution - Taffy has been updated to: - Apply size styles to absolutely positioned children - Pass the node's `Style` through to the measure function - Bevy's image measure function has been updated to make use of this style information ## Notes - This is currently using a git version of Taffy. If this is tested as fixing the issue then we can turn that into a Taffy 0.5 release (this would be the only change between Taffy 0.4 and Taffy 0.5 so upgrading is not expected to be an issue) - This implementation may not be completely correct. I would have preferred to extend Taffy's gentest infrastructure to handle images and used that to nail down the correct behaviour. But I don't have time for that atm so we'll have to iterate on this in future. This PR at least puts that under Bevy's control. ## Testing - I manually tested the game_menu_example (from https://github.com/bevyengine/bevy/issues/13155) - More testing is probably merited --- ## Changelog No changelog should be required as it fixes a regression on `main` that was not present in bevy 0.13. The changelog for "Taffy upgrade" may want to be changed from 0.4 to 0.5 if this change gets merged. --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: François Mockers <francois.mockers@vleue.com>
115 lines
3.5 KiB
Rust
115 lines
3.5 KiB
Rust
use bevy_ecs::prelude::Component;
|
|
use bevy_ecs::reflect::ReflectComponent;
|
|
use bevy_math::Vec2;
|
|
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
|
|
use std::fmt::Formatter;
|
|
pub use taffy::style::AvailableSpace;
|
|
|
|
use crate::widget::ImageMeasure;
|
|
|
|
#[cfg(feature = "bevy_text")]
|
|
use crate::widget::TextMeasure;
|
|
|
|
impl std::fmt::Debug for ContentSize {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
f.debug_struct("ContentSize").finish()
|
|
}
|
|
}
|
|
|
|
/// 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,
|
|
style: &taffy::Style,
|
|
) -> Vec2;
|
|
}
|
|
|
|
/// A type to serve as Taffy's node context (which allows the content size of leaf nodes to be computed)
|
|
///
|
|
/// It has specific variants for common built-in types to avoid making them opaque and needing to box them
|
|
/// by wrapping them in a closure and a Custom variant that allows arbitrary measurement closures if required.
|
|
pub enum NodeMeasure {
|
|
Fixed(FixedMeasure),
|
|
#[cfg(feature = "bevy_text")]
|
|
Text(TextMeasure),
|
|
Image(ImageMeasure),
|
|
Custom(Box<dyn Measure>),
|
|
}
|
|
|
|
impl Measure for NodeMeasure {
|
|
fn measure(
|
|
&self,
|
|
width: Option<f32>,
|
|
height: Option<f32>,
|
|
available_width: AvailableSpace,
|
|
available_height: AvailableSpace,
|
|
style: &taffy::Style,
|
|
) -> Vec2 {
|
|
match self {
|
|
NodeMeasure::Fixed(fixed) => {
|
|
fixed.measure(width, height, available_width, available_height, style)
|
|
}
|
|
#[cfg(feature = "bevy_text")]
|
|
NodeMeasure::Text(text) => {
|
|
text.measure(width, height, available_width, available_height, style)
|
|
}
|
|
NodeMeasure::Image(image) => {
|
|
image.measure(width, height, available_width, available_height, style)
|
|
}
|
|
NodeMeasure::Custom(custom) => {
|
|
custom.measure(width, height, available_width, available_height, style)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// A `FixedMeasure` is a `Measure` that ignores all constraints and
|
|
/// always returns the same size.
|
|
#[derive(Default, Clone)]
|
|
pub struct FixedMeasure {
|
|
pub size: Vec2,
|
|
}
|
|
|
|
impl Measure for FixedMeasure {
|
|
fn measure(
|
|
&self,
|
|
_: Option<f32>,
|
|
_: Option<f32>,
|
|
_: AvailableSpace,
|
|
_: AvailableSpace,
|
|
_: &taffy::Style,
|
|
) -> Vec2 {
|
|
self.size
|
|
}
|
|
}
|
|
|
|
/// A node with a `ContentSize` component is a node where its size
|
|
/// is based on its content.
|
|
#[derive(Component, Reflect, Default)]
|
|
#[reflect(Component, Default)]
|
|
pub struct ContentSize {
|
|
/// The `Measure` used to compute the intrinsic size
|
|
#[reflect(ignore)]
|
|
pub(crate) measure: Option<NodeMeasure>,
|
|
}
|
|
|
|
impl ContentSize {
|
|
/// Set a `Measure` for the UI node entity with this component
|
|
pub fn set(&mut self, measure: NodeMeasure) {
|
|
self.measure = Some(measure);
|
|
}
|
|
|
|
/// Creates a `ContentSize` with a `Measure` that always returns given `size` argument, regardless of the UI layout's constraints.
|
|
pub fn fixed_size(size: Vec2) -> ContentSize {
|
|
let mut content_size = Self::default();
|
|
content_size.set(NodeMeasure::Fixed(FixedMeasure { size }));
|
|
content_size
|
|
}
|
|
}
|