From 3a09af915c7d37d7cf667bcddf8bc83273029e9d Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Fri, 17 Feb 2023 19:49:53 +0000 Subject: [PATCH 01/38] changes: * Added a new trait `MeasureNode`. * Added new structs `ImageMeasure` and `BasicMeasure` that implement `MeasureNode`. * Add a field to `CalculatedSize` called `measure` that takes a boxed `MeasureNode`. * `upsert_leaf` uses the `measure` of `CalculatedSize` to create a `MeasureFunc` for the node. --- crates/bevy_ui/src/flex/mod.rs | 45 +++++++++++++----------------- crates/bevy_ui/src/lib.rs | 5 ++-- crates/bevy_ui/src/measurement.rs | 29 +++++++++++++++++++ crates/bevy_ui/src/node_bundles.rs | 4 +-- crates/bevy_ui/src/ui_node.rs | 22 +++++++-------- crates/bevy_ui/src/widget/image.rs | 38 +++++++++++++++++++++++-- crates/bevy_ui/src/widget/text.rs | 5 +++- 7 files changed, 104 insertions(+), 44 deletions(-) create mode 100644 crates/bevy_ui/src/measurement.rs diff --git a/crates/bevy_ui/src/flex/mod.rs b/crates/bevy_ui/src/flex/mod.rs index d48d6a0f3b5b9..341b58220edf9 100644 --- a/crates/bevy_ui/src/flex/mod.rs +++ b/crates/bevy_ui/src/flex/mod.rs @@ -79,37 +79,30 @@ impl FlexSurface { &mut self, entity: Entity, style: &Style, - calculated_size: CalculatedSize, + calculated_size: &CalculatedSize, scale_factor: f64, ) { let taffy = &mut self.taffy; let taffy_style = convert::from_style(scale_factor, style); + let m = calculated_size.measure.box_clone(); let measure = taffy::node::MeasureFunc::Boxed(Box::new( - move |constraints: Size>, _available: Size| { - let mut size = Size { - width: (scale_factor * calculated_size.size.x as f64) as f32, - height: (scale_factor * calculated_size.size.y as f64) as f32, - }; - match (constraints.width, constraints.height) { - (None, None) => {} - (Some(width), None) => { - if calculated_size.preserve_aspect_ratio { - size.height = width * size.height / size.width; - } - size.width = width; - } - (None, Some(height)) => { - if calculated_size.preserve_aspect_ratio { - size.width = height * size.width / size.height; - } - size.height = height; - } - (Some(width), Some(height)) => { - size.width = width; - size.height = height; + move |constraints: Size>, available_space: Size| { + let size = m.measure( + constraints.width.map(|w| (w as f64 / scale_factor) as f32), + constraints.height.map(|h| (h as f64 / scale_factor) as f32), + match available_space.width { + AvailableSpace::Definite(w) => AvailableSpace::Definite((w as f64 / scale_factor as f64) as f32), + s => s, + }, + match available_space.height { + AvailableSpace::Definite(h) => AvailableSpace::Definite((h as f64 / scale_factor as f64) as f32), + s => s, } + ); + taffy::geometry::Size { + width: (size.x as f64 * scale_factor) as f32, + height: (size.y as f64 * scale_factor) as f32, } - size }, )); if let Some(taffy_node) = self.entity_to_taffy.get(&entity) { @@ -266,7 +259,7 @@ pub fn flex_node_system( for (entity, style, calculated_size) in &query { // TODO: remove node from old hierarchy if its root has changed if let Some(calculated_size) = calculated_size { - flex_surface.upsert_leaf(entity, style, *calculated_size, scaling_factor); + flex_surface.upsert_leaf(entity, style, calculated_size, scaling_factor); } else { flex_surface.upsert_node(entity, style, scaling_factor); } @@ -281,7 +274,7 @@ pub fn flex_node_system( } for (entity, style, calculated_size) in &changed_size_query { - flex_surface.upsert_leaf(entity, style, *calculated_size, scale_factor); + flex_surface.upsert_leaf(entity, style, calculated_size, scale_factor); } // clean up removed nodes diff --git a/crates/bevy_ui/src/lib.rs b/crates/bevy_ui/src/lib.rs index 8ea3b454108d8..e0aee0c79d39c 100644 --- a/crates/bevy_ui/src/lib.rs +++ b/crates/bevy_ui/src/lib.rs @@ -13,6 +13,7 @@ pub mod camera_config; pub mod node_bundles; pub mod update; pub mod widget; +pub mod measurement; use bevy_render::{camera::CameraUpdateSystem, extract_component::ExtractComponentPlugin}; pub use flex::*; @@ -20,13 +21,14 @@ pub use focus::*; pub use geometry::*; pub use render::*; pub use ui_node::*; +pub use measurement::*; #[doc(hidden)] pub mod prelude { #[doc(hidden)] pub use crate::{ camera_config::*, geometry::*, node_bundles::*, ui_node::*, widget::Button, Interaction, - UiScale, + UiScale, measurement::* }; } @@ -80,7 +82,6 @@ impl Plugin for UiPlugin { .register_type::() .register_type::() .register_type::() - .register_type::() .register_type::() .register_type::() .register_type::() diff --git a/crates/bevy_ui/src/measurement.rs b/crates/bevy_ui/src/measurement.rs new file mode 100644 index 0000000000000..b45ed7a6de647 --- /dev/null +++ b/crates/bevy_ui/src/measurement.rs @@ -0,0 +1,29 @@ +use bevy_math::Vec2; +pub use taffy::layout::AvailableSpace; + +pub trait MeasureNode: Send + Sync + 'static { + /// Calculate the size of the node given the constraints. + fn measure(&self, max_width: Option, max_height: Option, available_width: AvailableSpace, available_height: AvailableSpace) -> Vec2; + /// Clone and box self. + fn box_clone(&self) -> Box; +} + +#[derive(Clone)] +pub struct BasicMeasure { + /// Prefered size + pub size: Vec2, +} + +impl MeasureNode for BasicMeasure { + fn measure(&self, width: Option, height: Option, _: AvailableSpace, _: AvailableSpace) -> Vec2 { + match (width, height) { + (Some(width), Some(height)) => Vec2::new(width, height), + (Some(width), None) => Vec2::new(width, self.size.y), + (None, Some(height)) => Vec2::new(self.size.x, height), + (None, None) => self.size, + } + } + fn box_clone(&self) -> Box { + Box::new(self.clone()) + } +} \ No newline at end of file diff --git a/crates/bevy_ui/src/node_bundles.rs b/crates/bevy_ui/src/node_bundles.rs index 8369b33bfe0b0..4e00fc07b2dd8 100644 --- a/crates/bevy_ui/src/node_bundles.rs +++ b/crates/bevy_ui/src/node_bundles.rs @@ -61,7 +61,7 @@ impl Default for NodeBundle { } /// A UI node that is an image -#[derive(Bundle, Clone, Debug, Default)] +#[derive(Bundle, Debug, Default)] pub struct ImageBundle { /// Describes the size of the node pub node: Node, @@ -96,7 +96,7 @@ pub struct ImageBundle { } /// A UI node that is text -#[derive(Bundle, Clone, Debug, Default)] +#[derive(Bundle, Debug, Default)] pub struct TextBundle { /// Describes the size of the node pub node: Node, diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index 588cb141d3f38..23c1f5c9b8d7d 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -1,4 +1,4 @@ -use crate::{Size, UiRect}; +use crate::{Size, UiRect, MeasureNode, BasicMeasure}; use bevy_asset::Handle; use bevy_ecs::{prelude::Component, reflect::ReflectComponent}; use bevy_math::{Rect, Vec2}; @@ -562,25 +562,25 @@ impl Default for FlexWrap { } /// The calculated size of the node -#[derive(Component, Copy, Clone, Debug, Reflect)] -#[reflect(Component)] +#[derive(Component)] pub struct CalculatedSize { /// The size of the node in logical pixels pub size: Vec2, - /// Whether to attempt to preserve the aspect ratio when determining the layout for this item - pub preserve_aspect_ratio: bool, + /// The measure function used to calculate the size + pub measure: Box + } -impl CalculatedSize { - const DEFAULT: Self = Self { - size: Vec2::ZERO, - preserve_aspect_ratio: false, - }; +impl std::fmt::Debug for CalculatedSize { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("CalculatedSize") + .finish() + } } impl Default for CalculatedSize { fn default() -> Self { - Self::DEFAULT + Self { size: Default::default(), measure: Box::new(BasicMeasure { size: Default::default() }) } } } diff --git a/crates/bevy_ui/src/widget/image.rs b/crates/bevy_ui/src/widget/image.rs index 232be96eb4047..f59adaa7875be 100644 --- a/crates/bevy_ui/src/widget/image.rs +++ b/crates/bevy_ui/src/widget/image.rs @@ -1,4 +1,4 @@ -use crate::{CalculatedSize, UiImage}; +use crate::{CalculatedSize, UiImage, MeasureNode}; use bevy_asset::Assets; use bevy_ecs::{ query::Without, @@ -7,6 +7,40 @@ use bevy_ecs::{ use bevy_math::Vec2; use bevy_render::texture::Image; use bevy_text::Text; +use taffy::prelude::AvailableSpace; + +#[derive(Clone)] +pub struct ImageMeasure { + size: Vec2, +} + +impl MeasureNode for ImageMeasure { + fn measure(&self, width: Option, height: Option, _: AvailableSpace, _: AvailableSpace) -> Vec2 { + let mut size = self.size; + match (width, height) { + (None, None) => {} + (Some(width), None) => { + size.y = width * size.y / size.x; + size.x = width; + + } + (None, Some(height)) => { + size.x = height * size.x / size.y; + size.y = height; + } + (Some(width), Some(height)) => { + size.x = width; + size.y = height; + } + } + size + } + + fn box_clone(&self) -> Box { + Box::new(self.clone()) + } +} + /// Updates calculated size of the node based on the image provided pub fn update_image_calculated_size_system( @@ -22,7 +56,7 @@ pub fn update_image_calculated_size_system( // Update only if size has changed to avoid needless layout calculations if size != calculated_size.size { calculated_size.size = size; - calculated_size.preserve_aspect_ratio = true; + calculated_size.measure = Box::new(ImageMeasure { size }); } } } diff --git a/crates/bevy_ui/src/widget/text.rs b/crates/bevy_ui/src/widget/text.rs index a4464701fdcee..ad9bcbedd547a 100644 --- a/crates/bevy_ui/src/widget/text.rs +++ b/crates/bevy_ui/src/widget/text.rs @@ -1,4 +1,4 @@ -use crate::{CalculatedSize, Node, Style, UiScale, Val}; +use crate::{CalculatedSize, Node, Style, UiScale, Val, MeasureNode, BasicMeasure}; use bevy_asset::Assets; use bevy_ecs::{ entity::Entity, @@ -139,6 +139,9 @@ pub fn text_system( scale_value(info.size.x, inv_scale_factor), scale_value(info.size.y, inv_scale_factor), ); + calculated_size.measure = Box::new(BasicMeasure { + size: calculated_size.size, + }); match text_layout_info { Some(mut t) => *t = info, None => { From b1712b8a9629044ab39719364f88a1bddd0b6426 Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Fri, 17 Feb 2023 20:08:14 +0000 Subject: [PATCH 02/38] cargo fmt --- crates/bevy_ui/src/flex/mod.rs | 12 ++++++++---- crates/bevy_ui/src/lib.rs | 8 ++++---- crates/bevy_ui/src/measurement.rs | 19 ++++++++++++++++--- crates/bevy_ui/src/ui_node.rs | 15 +++++++++------ crates/bevy_ui/src/widget/image.rs | 18 +++++++++++------- crates/bevy_ui/src/widget/text.rs | 2 +- 6 files changed, 49 insertions(+), 25 deletions(-) diff --git a/crates/bevy_ui/src/flex/mod.rs b/crates/bevy_ui/src/flex/mod.rs index 341b58220edf9..c4810de62adc0 100644 --- a/crates/bevy_ui/src/flex/mod.rs +++ b/crates/bevy_ui/src/flex/mod.rs @@ -84,20 +84,24 @@ impl FlexSurface { ) { let taffy = &mut self.taffy; let taffy_style = convert::from_style(scale_factor, style); - let m = calculated_size.measure.box_clone(); + let m = calculated_size.measure.box_clone(); let measure = taffy::node::MeasureFunc::Boxed(Box::new( move |constraints: Size>, available_space: Size| { let size = m.measure( constraints.width.map(|w| (w as f64 / scale_factor) as f32), constraints.height.map(|h| (h as f64 / scale_factor) as f32), match available_space.width { - AvailableSpace::Definite(w) => AvailableSpace::Definite((w as f64 / scale_factor as f64) as f32), + AvailableSpace::Definite(w) => { + AvailableSpace::Definite((w as f64 / scale_factor as f64) as f32) + } s => s, }, match available_space.height { - AvailableSpace::Definite(h) => AvailableSpace::Definite((h as f64 / scale_factor as f64) as f32), + AvailableSpace::Definite(h) => { + AvailableSpace::Definite((h as f64 / scale_factor as f64) as f32) + } s => s, - } + }, ); taffy::geometry::Size { width: (size.x as f64 * scale_factor) as f32, diff --git a/crates/bevy_ui/src/lib.rs b/crates/bevy_ui/src/lib.rs index e0aee0c79d39c..1be2bdf49e14a 100644 --- a/crates/bevy_ui/src/lib.rs +++ b/crates/bevy_ui/src/lib.rs @@ -10,25 +10,25 @@ mod stack; mod ui_node; pub mod camera_config; +pub mod measurement; pub mod node_bundles; pub mod update; pub mod widget; -pub mod measurement; use bevy_render::{camera::CameraUpdateSystem, extract_component::ExtractComponentPlugin}; pub use flex::*; pub use focus::*; pub use geometry::*; +pub use measurement::*; pub use render::*; pub use ui_node::*; -pub use measurement::*; #[doc(hidden)] pub mod prelude { #[doc(hidden)] pub use crate::{ - camera_config::*, geometry::*, node_bundles::*, ui_node::*, widget::Button, Interaction, - UiScale, measurement::* + camera_config::*, geometry::*, measurement::*, node_bundles::*, ui_node::*, widget::Button, + Interaction, UiScale, }; } diff --git a/crates/bevy_ui/src/measurement.rs b/crates/bevy_ui/src/measurement.rs index b45ed7a6de647..e93602d064197 100644 --- a/crates/bevy_ui/src/measurement.rs +++ b/crates/bevy_ui/src/measurement.rs @@ -3,7 +3,13 @@ pub use taffy::layout::AvailableSpace; pub trait MeasureNode: Send + Sync + 'static { /// Calculate the size of the node given the constraints. - fn measure(&self, max_width: Option, max_height: Option, available_width: AvailableSpace, available_height: AvailableSpace) -> Vec2; + fn measure( + &self, + max_width: Option, + max_height: Option, + available_width: AvailableSpace, + available_height: AvailableSpace, + ) -> Vec2; /// Clone and box self. fn box_clone(&self) -> Box; } @@ -15,7 +21,13 @@ pub struct BasicMeasure { } impl MeasureNode for BasicMeasure { - fn measure(&self, width: Option, height: Option, _: AvailableSpace, _: AvailableSpace) -> Vec2 { + fn measure( + &self, + width: Option, + height: Option, + _: AvailableSpace, + _: AvailableSpace, + ) -> Vec2 { match (width, height) { (Some(width), Some(height)) => Vec2::new(width, height), (Some(width), None) => Vec2::new(width, self.size.y), @@ -23,7 +35,8 @@ impl MeasureNode for BasicMeasure { (None, None) => self.size, } } + fn box_clone(&self) -> Box { Box::new(self.clone()) } -} \ No newline at end of file +} diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index 23c1f5c9b8d7d..43dd1568f5a88 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -1,4 +1,4 @@ -use crate::{Size, UiRect, MeasureNode, BasicMeasure}; +use crate::{BasicMeasure, MeasureNode, Size, UiRect}; use bevy_asset::Handle; use bevy_ecs::{prelude::Component, reflect::ReflectComponent}; use bevy_math::{Rect, Vec2}; @@ -567,20 +567,23 @@ pub struct CalculatedSize { /// The size of the node in logical pixels pub size: Vec2, /// The measure function used to calculate the size - pub measure: Box - + pub measure: Box, } impl std::fmt::Debug for CalculatedSize { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("CalculatedSize") - .finish() + f.debug_struct("CalculatedSize").finish() } } impl Default for CalculatedSize { fn default() -> Self { - Self { size: Default::default(), measure: Box::new(BasicMeasure { size: Default::default() }) } + Self { + size: Default::default(), + measure: Box::new(BasicMeasure { + size: Default::default(), + }), + } } } diff --git a/crates/bevy_ui/src/widget/image.rs b/crates/bevy_ui/src/widget/image.rs index f59adaa7875be..f3f1b6a68732e 100644 --- a/crates/bevy_ui/src/widget/image.rs +++ b/crates/bevy_ui/src/widget/image.rs @@ -1,4 +1,4 @@ -use crate::{CalculatedSize, UiImage, MeasureNode}; +use crate::{CalculatedSize, MeasureNode, UiImage}; use bevy_asset::Assets; use bevy_ecs::{ query::Without, @@ -9,20 +9,25 @@ use bevy_render::texture::Image; use bevy_text::Text; use taffy::prelude::AvailableSpace; -#[derive(Clone)] +#[derive(Clone)] pub struct ImageMeasure { size: Vec2, } impl MeasureNode for ImageMeasure { - fn measure(&self, width: Option, height: Option, _: AvailableSpace, _: AvailableSpace) -> Vec2 { + fn measure( + &self, + width: Option, + height: Option, + _: AvailableSpace, + _: AvailableSpace, + ) -> Vec2 { let mut size = self.size; match (width, height) { (None, None) => {} - (Some(width), None) => { + (Some(width), None) => { size.y = width * size.y / size.x; - size.x = width; - + size.x = width; } (None, Some(height)) => { size.x = height * size.x / size.y; @@ -41,7 +46,6 @@ impl MeasureNode for ImageMeasure { } } - /// Updates calculated size of the node based on the image provided pub fn update_image_calculated_size_system( textures: Res>, diff --git a/crates/bevy_ui/src/widget/text.rs b/crates/bevy_ui/src/widget/text.rs index ad9bcbedd547a..7926773636672 100644 --- a/crates/bevy_ui/src/widget/text.rs +++ b/crates/bevy_ui/src/widget/text.rs @@ -1,4 +1,4 @@ -use crate::{CalculatedSize, Node, Style, UiScale, Val, MeasureNode, BasicMeasure}; +use crate::{BasicMeasure, CalculatedSize, MeasureNode, Node, Style, UiScale, Val}; use bevy_asset::Assets; use bevy_ecs::{ entity::Entity, From 080aae75a20e9b94332c51f1f3c1df7c9162b249 Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Fri, 17 Feb 2023 22:18:00 +0000 Subject: [PATCH 03/38] fix lints --- crates/bevy_ui/src/flex/mod.rs | 4 ++-- crates/bevy_ui/src/measurement.rs | 1 + crates/bevy_ui/src/widget/text.rs | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/crates/bevy_ui/src/flex/mod.rs b/crates/bevy_ui/src/flex/mod.rs index c4810de62adc0..50726fa87f413 100644 --- a/crates/bevy_ui/src/flex/mod.rs +++ b/crates/bevy_ui/src/flex/mod.rs @@ -92,13 +92,13 @@ impl FlexSurface { constraints.height.map(|h| (h as f64 / scale_factor) as f32), match available_space.width { AvailableSpace::Definite(w) => { - AvailableSpace::Definite((w as f64 / scale_factor as f64) as f32) + AvailableSpace::Definite((w as f64 / scale_factor) as f32) } s => s, }, match available_space.height { AvailableSpace::Definite(h) => { - AvailableSpace::Definite((h as f64 / scale_factor as f64) as f32) + AvailableSpace::Definite((h as f64 / scale_factor) as f32) } s => s, }, diff --git a/crates/bevy_ui/src/measurement.rs b/crates/bevy_ui/src/measurement.rs index e93602d064197..ef397ab5f9295 100644 --- a/crates/bevy_ui/src/measurement.rs +++ b/crates/bevy_ui/src/measurement.rs @@ -14,6 +14,7 @@ pub trait MeasureNode: Send + Sync + 'static { fn box_clone(&self) -> Box; } + #[derive(Clone)] pub struct BasicMeasure { /// Prefered size diff --git a/crates/bevy_ui/src/widget/text.rs b/crates/bevy_ui/src/widget/text.rs index 7926773636672..de77506d504d4 100644 --- a/crates/bevy_ui/src/widget/text.rs +++ b/crates/bevy_ui/src/widget/text.rs @@ -1,4 +1,4 @@ -use crate::{BasicMeasure, CalculatedSize, MeasureNode, Node, Style, UiScale, Val}; +use crate::{BasicMeasure, CalculatedSize, Node, Style, UiScale, Val}; use bevy_asset::Assets; use bevy_ecs::{ entity::Entity, From 9c4c01d00b3181d9c056e9743006362c15aba948 Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Fri, 17 Feb 2023 23:08:43 +0000 Subject: [PATCH 04/38] cargo fmt --- crates/bevy_ui/src/measurement.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/bevy_ui/src/measurement.rs b/crates/bevy_ui/src/measurement.rs index ef397ab5f9295..e93602d064197 100644 --- a/crates/bevy_ui/src/measurement.rs +++ b/crates/bevy_ui/src/measurement.rs @@ -14,7 +14,6 @@ pub trait MeasureNode: Send + Sync + 'static { fn box_clone(&self) -> Box; } - #[derive(Clone)] pub struct BasicMeasure { /// Prefered size From 8934a6f71fb7fddc7312ee3bca17da635534785d Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Sat, 18 Feb 2023 10:00:18 +0000 Subject: [PATCH 05/38] impl Measure for Fn --- crates/bevy_ui/src/flex/mod.rs | 2 +- crates/bevy_ui/src/measurement.rs | 61 ++++++++++++++++++++++++++++-- crates/bevy_ui/src/ui_node.rs | 28 +------------- crates/bevy_ui/src/widget/image.rs | 6 +-- crates/bevy_ui/src/widget/text.rs | 9 ++--- 5 files changed, 66 insertions(+), 40 deletions(-) diff --git a/crates/bevy_ui/src/flex/mod.rs b/crates/bevy_ui/src/flex/mod.rs index 50726fa87f413..6ed4e0bc6d5f4 100644 --- a/crates/bevy_ui/src/flex/mod.rs +++ b/crates/bevy_ui/src/flex/mod.rs @@ -84,7 +84,7 @@ impl FlexSurface { ) { let taffy = &mut self.taffy; let taffy_style = convert::from_style(scale_factor, style); - let m = calculated_size.measure.box_clone(); + let m = calculated_size.measure.dyn_clone(); let measure = taffy::node::MeasureFunc::Boxed(Box::new( move |constraints: Size>, available_space: Size| { let size = m.measure( diff --git a/crates/bevy_ui/src/measurement.rs b/crates/bevy_ui/src/measurement.rs index e93602d064197..a9430cac0a855 100644 --- a/crates/bevy_ui/src/measurement.rs +++ b/crates/bevy_ui/src/measurement.rs @@ -1,7 +1,36 @@ +use bevy_ecs::prelude::Component; use bevy_math::Vec2; +use std::fmt::Formatter; pub use taffy::layout::AvailableSpace; -pub trait MeasureNode: Send + Sync + 'static { +/// The calculated size of the node +#[derive(Component)] +pub struct CalculatedSize { + pub size: Vec2, + /// The measure function used to calculate the size + pub measure: Box, +} + +impl Default for CalculatedSize { + fn default() -> Self { + Self { + size: Default::default(), + measure: Box::new(|w: Option, h: Option, _, _| { + Vec2::new(w.unwrap_or(0.), h.unwrap_or(0.)) + }), + } + } +} + +impl std::fmt::Debug for CalculatedSize { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("CalculatedSize") + .field("size", &self.size) + .finish() + } +} + +pub trait Measure: Send + Sync + 'static { /// Calculate the size of the node given the constraints. fn measure( &self, @@ -10,8 +39,9 @@ pub trait MeasureNode: Send + Sync + 'static { available_width: AvailableSpace, available_height: AvailableSpace, ) -> Vec2; + /// Clone and box self. - fn box_clone(&self) -> Box; + fn dyn_clone(&self) -> Box; } #[derive(Clone)] @@ -20,7 +50,7 @@ pub struct BasicMeasure { pub size: Vec2, } -impl MeasureNode for BasicMeasure { +impl Measure for BasicMeasure { fn measure( &self, width: Option, @@ -36,7 +66,30 @@ impl MeasureNode for BasicMeasure { } } - fn box_clone(&self) -> Box { + fn dyn_clone(&self) -> Box { + Box::new(self.clone()) + } +} + +impl Measure for F +where + F: Fn(Option, Option, AvailableSpace, AvailableSpace) -> Vec2 + + Send + + Sync + + 'static + + Clone, +{ + fn measure( + &self, + max_width: Option, + max_height: Option, + available_width: AvailableSpace, + available_height: AvailableSpace, + ) -> Vec2 { + self(max_width, max_height, available_width, available_height) + } + + fn dyn_clone(&self) -> Box { Box::new(self.clone()) } } diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index 43dd1568f5a88..0fb5f34413035 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -1,4 +1,4 @@ -use crate::{BasicMeasure, MeasureNode, Size, UiRect}; +use crate::{Size, UiRect}; use bevy_asset::Handle; use bevy_ecs::{prelude::Component, reflect::ReflectComponent}; use bevy_math::{Rect, Vec2}; @@ -561,32 +561,6 @@ impl Default for FlexWrap { } } -/// The calculated size of the node -#[derive(Component)] -pub struct CalculatedSize { - /// The size of the node in logical pixels - pub size: Vec2, - /// The measure function used to calculate the size - pub measure: Box, -} - -impl std::fmt::Debug for CalculatedSize { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("CalculatedSize").finish() - } -} - -impl Default for CalculatedSize { - fn default() -> Self { - Self { - size: Default::default(), - measure: Box::new(BasicMeasure { - size: Default::default(), - }), - } - } -} - /// The background color of the node /// /// This serves as the "fill" color. diff --git a/crates/bevy_ui/src/widget/image.rs b/crates/bevy_ui/src/widget/image.rs index f3f1b6a68732e..875b1d3e915c1 100644 --- a/crates/bevy_ui/src/widget/image.rs +++ b/crates/bevy_ui/src/widget/image.rs @@ -1,4 +1,4 @@ -use crate::{CalculatedSize, MeasureNode, UiImage}; +use crate::{CalculatedSize, Measure, UiImage}; use bevy_asset::Assets; use bevy_ecs::{ query::Without, @@ -14,7 +14,7 @@ pub struct ImageMeasure { size: Vec2, } -impl MeasureNode for ImageMeasure { +impl Measure for ImageMeasure { fn measure( &self, width: Option, @@ -41,7 +41,7 @@ impl MeasureNode for ImageMeasure { size } - fn box_clone(&self) -> Box { + fn dyn_clone(&self) -> Box { Box::new(self.clone()) } } diff --git a/crates/bevy_ui/src/widget/text.rs b/crates/bevy_ui/src/widget/text.rs index de77506d504d4..b66ea1f0e2cf0 100644 --- a/crates/bevy_ui/src/widget/text.rs +++ b/crates/bevy_ui/src/widget/text.rs @@ -135,12 +135,11 @@ pub fn text_system( panic!("Fatal error when processing text: {e}."); } Ok(info) => { - calculated_size.size = Vec2::new( - scale_value(info.size.x, inv_scale_factor), - scale_value(info.size.y, inv_scale_factor), - ); calculated_size.measure = Box::new(BasicMeasure { - size: calculated_size.size, + size: Vec2::new( + scale_value(info.size.x, inv_scale_factor), + scale_value(info.size.y, inv_scale_factor), + ), }); match text_layout_info { Some(mut t) => *t = info, From fc9b2d9afa90d0f2fe29ed495af8c6ab7cf5e578 Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Sun, 19 Feb 2023 21:43:55 +0000 Subject: [PATCH 06/38] Changes: * Added the `TextLayoutInfo` component to `TextBundle`. * Added the `TextLayoutInfo` component to `Text2dBundle`. * Changed `TextLayoutInfo` queries to be non-optional. --- crates/bevy_text/src/text2d.rs | 15 +++++---------- crates/bevy_ui/src/node_bundles.rs | 4 +++- crates/bevy_ui/src/widget/text.rs | 14 ++++---------- 3 files changed, 12 insertions(+), 21 deletions(-) diff --git a/crates/bevy_text/src/text2d.rs b/crates/bevy_text/src/text2d.rs index 56da32ade4e8b..e4907c24df8c7 100644 --- a/crates/bevy_text/src/text2d.rs +++ b/crates/bevy_text/src/text2d.rs @@ -7,7 +7,7 @@ use bevy_ecs::{ event::EventReader, prelude::With, reflect::ReflectComponent, - system::{Commands, Local, Query, Res, ResMut}, + system::{Local, Query, Res, ResMut}, }; use bevy_math::{Vec2, Vec3}; use bevy_reflect::Reflect; @@ -65,6 +65,7 @@ pub struct Text2dBundle { pub text_2d_bounds: Text2dBounds, pub visibility: Visibility, pub computed_visibility: ComputedVisibility, + pub text_layout_info: TextLayoutInfo, } pub fn extract_text2d_sprite( @@ -146,7 +147,6 @@ pub fn extract_text2d_sprite( /// It does not modify or observe existing ones. #[allow(clippy::too_many_arguments)] pub fn update_text2d_layout( - mut commands: Commands, // Text items which should be reprocessed again, generally when the font hasn't loaded yet. mut queue: Local>, mut textures: ResMut>, @@ -162,7 +162,7 @@ pub fn update_text2d_layout( Entity, Ref, &Text2dBounds, - Option<&mut TextLayoutInfo>, + &mut TextLayoutInfo, )>, ) { // We need to consume the entire iterator, hence `last` @@ -174,7 +174,7 @@ pub fn update_text2d_layout( .map(|window| window.resolution.scale_factor()) .unwrap_or(1.0); - for (entity, text, bounds, text_layout_info) in &mut text_query { + for (entity, text, bounds, mut text_layout_info) in &mut text_query { if factor_changed || text.is_changed() || queue.remove(&entity) { let text_bounds = Vec2::new( scale_value(bounds.size.x, scale_factor), @@ -203,12 +203,7 @@ pub fn update_text2d_layout( Err(e @ TextError::FailedToAddGlyph(_)) => { panic!("Fatal error when processing text: {e}."); } - Ok(info) => match text_layout_info { - Some(mut t) => *t = info, - None => { - commands.entity(entity).insert(info); - } - }, + Ok(info) => *text_layout_info = info, } } } diff --git a/crates/bevy_ui/src/node_bundles.rs b/crates/bevy_ui/src/node_bundles.rs index 8369b33bfe0b0..bd0dac6cc1c25 100644 --- a/crates/bevy_ui/src/node_bundles.rs +++ b/crates/bevy_ui/src/node_bundles.rs @@ -9,7 +9,7 @@ use bevy_render::{ prelude::{Color, ComputedVisibility}, view::Visibility, }; -use bevy_text::{Text, TextAlignment, TextSection, TextStyle}; +use bevy_text::{Text, TextAlignment, TextSection, TextStyle, TextLayoutInfo}; use bevy_transform::prelude::{GlobalTransform, Transform}; /// The basic UI node @@ -104,6 +104,8 @@ pub struct TextBundle { pub style: Style, /// Contains the text of the node pub text: Text, + /// Text layout information + pub text_layout_info: TextLayoutInfo, /// The calculated size based on the given image pub calculated_size: CalculatedSize, /// Whether this node should block interaction with lower nodes diff --git a/crates/bevy_ui/src/widget/text.rs b/crates/bevy_ui/src/widget/text.rs index a4464701fdcee..7ca24fff631c2 100644 --- a/crates/bevy_ui/src/widget/text.rs +++ b/crates/bevy_ui/src/widget/text.rs @@ -3,7 +3,7 @@ use bevy_asset::Assets; use bevy_ecs::{ entity::Entity, query::{Changed, Or, With}, - system::{Commands, Local, ParamSet, Query, Res, ResMut}, + system::{Local, ParamSet, Query, Res, ResMut}, }; use bevy_math::Vec2; use bevy_render::texture::Image; @@ -41,7 +41,6 @@ pub fn text_constraint(min_size: Val, size: Val, max_size: Val, scale_factor: f6 /// It does not modify or observe existing ones. #[allow(clippy::too_many_arguments)] pub fn text_system( - mut commands: Commands, mut queued_text_ids: Local>, mut last_scale_factor: Local, mut textures: ResMut>, @@ -60,7 +59,7 @@ pub fn text_system( &Text, &Style, &mut CalculatedSize, - Option<&mut TextLayoutInfo>, + &mut TextLayoutInfo, )>, )>, ) { @@ -96,7 +95,7 @@ pub fn text_system( let mut new_queue = Vec::new(); let mut query = text_queries.p2(); for entity in queued_text_ids.drain(..) { - if let Ok((text, style, mut calculated_size, text_layout_info)) = query.get_mut(entity) { + if let Ok((text, style, mut calculated_size, mut text_layout_info)) = query.get_mut(entity) { let node_size = Vec2::new( text_constraint( style.min_size.width, @@ -139,12 +138,7 @@ pub fn text_system( scale_value(info.size.x, inv_scale_factor), scale_value(info.size.y, inv_scale_factor), ); - match text_layout_info { - Some(mut t) => *t = info, - None => { - commands.entity(entity).insert(info); - } - } + *text_layout_info = info; } } } From f7d20ea6ba7a0fb162267ea23d0bf505066f98f7 Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Sun, 19 Feb 2023 22:17:20 +0000 Subject: [PATCH 07/38] cargo fmt --all --- crates/bevy_text/src/text2d.rs | 7 +------ crates/bevy_ui/src/node_bundles.rs | 2 +- crates/bevy_ui/src/widget/text.rs | 10 +++------- 3 files changed, 5 insertions(+), 14 deletions(-) diff --git a/crates/bevy_text/src/text2d.rs b/crates/bevy_text/src/text2d.rs index e4907c24df8c7..e79ac4f5b219f 100644 --- a/crates/bevy_text/src/text2d.rs +++ b/crates/bevy_text/src/text2d.rs @@ -158,12 +158,7 @@ pub fn update_text2d_layout( mut texture_atlases: ResMut>, mut font_atlas_set_storage: ResMut>, mut text_pipeline: ResMut, - mut text_query: Query<( - Entity, - Ref, - &Text2dBounds, - &mut TextLayoutInfo, - )>, + mut text_query: Query<(Entity, Ref, &Text2dBounds, &mut TextLayoutInfo)>, ) { // We need to consume the entire iterator, hence `last` let factor_changed = scale_factor_changed.iter().last().is_some(); diff --git a/crates/bevy_ui/src/node_bundles.rs b/crates/bevy_ui/src/node_bundles.rs index bd0dac6cc1c25..d5b7ca41dd109 100644 --- a/crates/bevy_ui/src/node_bundles.rs +++ b/crates/bevy_ui/src/node_bundles.rs @@ -9,7 +9,7 @@ use bevy_render::{ prelude::{Color, ComputedVisibility}, view::Visibility, }; -use bevy_text::{Text, TextAlignment, TextSection, TextStyle, TextLayoutInfo}; +use bevy_text::{Text, TextAlignment, TextLayoutInfo, TextSection, TextStyle}; use bevy_transform::prelude::{GlobalTransform, Transform}; /// The basic UI node diff --git a/crates/bevy_ui/src/widget/text.rs b/crates/bevy_ui/src/widget/text.rs index 7ca24fff631c2..80590fb7f5c9b 100644 --- a/crates/bevy_ui/src/widget/text.rs +++ b/crates/bevy_ui/src/widget/text.rs @@ -55,12 +55,7 @@ pub fn text_system( mut text_queries: ParamSet<( Query, Changed, Changed