From 07aad3bb4070dfa48145908e2fcac2307757928b Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Fri, 10 Mar 2023 15:50:03 +0000 Subject: [PATCH 01/65] Enable Taffy grid feature --- crates/bevy_ui/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_ui/Cargo.toml b/crates/bevy_ui/Cargo.toml index cfe142b088ebf..dc02893ba21bb 100644 --- a/crates/bevy_ui/Cargo.toml +++ b/crates/bevy_ui/Cargo.toml @@ -31,7 +31,7 @@ bevy_window = { path = "../bevy_window", version = "0.11.0-dev" } bevy_utils = { path = "../bevy_utils", version = "0.11.0-dev" } # other -taffy = { version = "0.3.5", default-features = false, features = ["std"] } +taffy = { version = "0.3.7" } serde = { version = "1", features = ["derive"] } smallvec = { version = "1.6", features = ["union", "const_generics"] } bytemuck = { version = "1.5", features = ["derive"] } From ff6f5af8d89833ecf6faa1ecb839485f4f5fa675 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Fri, 10 Mar 2023 15:50:17 +0000 Subject: [PATCH 02/65] CSS Grid WIP (update alignment types) --- crates/bevy_ui/src/flex/convert.rs | 117 ++++++++++++++-------- crates/bevy_ui/src/ui_node.rs | 151 ++++++++++++++++++++++------- 2 files changed, 196 insertions(+), 72 deletions(-) diff --git a/crates/bevy_ui/src/flex/convert.rs b/crates/bevy_ui/src/flex/convert.rs index 7ebc0fd0cd30e..6822567404752 100644 --- a/crates/bevy_ui/src/flex/convert.rs +++ b/crates/bevy_ui/src/flex/convert.rs @@ -2,7 +2,7 @@ use taffy::style::LengthPercentageAuto; use crate::{ AlignContent, AlignItems, AlignSelf, Display, FlexDirection, FlexWrap, JustifyContent, - PositionType, Size, Style, UiRect, Val, + JustifyItems, JustifySelf, PositionType, Size, Style, UiRect, Val, }; impl Val { @@ -101,10 +101,12 @@ pub fn from_style(scale_factor: f64, style: &Style) -> taffy::style::Style { position: style.position_type.into(), flex_direction: style.flex_direction.into(), flex_wrap: style.flex_wrap.into(), - align_items: Some(style.align_items.into()), + align_items: style.align_items.into(), + justify_items: style.justify_items.into(), align_self: style.align_self.into(), - align_content: Some(style.align_content.into()), - justify_content: Some(style.justify_content.into()), + justify_self: style.justify_self.into(), + align_content: style.align_content.into(), + justify_content: style.justify_content.into(), inset: taffy::prelude::Rect { left: style.position.left.scaled(scale_factor).to_inset(), right: style.position.right.scaled(scale_factor).to_inset(), @@ -122,20 +124,42 @@ pub fn from_style(scale_factor: f64, style: &Style) -> taffy::style::Style { max_size: style.max_size.scaled(scale_factor).into(), aspect_ratio: style.aspect_ratio, gap: style.gap.scaled(scale_factor).into(), - justify_self: None, + grid_template_rows: todo!(), + grid_template_columns: todo!(), + grid_auto_rows: todo!(), + grid_auto_columns: todo!(), + grid_auto_flow: todo!(), + grid_row: todo!(), + grid_column: todo!(), } } -impl From for taffy::style::AlignItems { +impl From for Option { fn from(value: AlignItems) -> Self { match value { - AlignItems::Start => taffy::style::AlignItems::Start, - AlignItems::End => taffy::style::AlignItems::End, - AlignItems::FlexStart => taffy::style::AlignItems::FlexStart, - AlignItems::FlexEnd => taffy::style::AlignItems::FlexEnd, - AlignItems::Center => taffy::style::AlignItems::Center, - AlignItems::Baseline => taffy::style::AlignItems::Baseline, - AlignItems::Stretch => taffy::style::AlignItems::Stretch, + AlignItems::Normal => None, + AlignItems::Start => taffy::style::AlignItems::Start.into(), + AlignItems::End => taffy::style::AlignItems::End.into(), + AlignItems::FlexStart => taffy::style::AlignItems::FlexStart.into(), + AlignItems::FlexEnd => taffy::style::AlignItems::FlexEnd.into(), + AlignItems::Center => taffy::style::AlignItems::Center.into(), + AlignItems::Baseline => taffy::style::AlignItems::Baseline.into(), + AlignItems::Stretch => taffy::style::AlignItems::Stretch.into(), + } + } +} + +impl From for Option { + fn from(value: JustifyItems) -> Self { + match value { + JustifyItems::Normal => None, + JustifyItems::Start => taffy::style::JustifyItems::Start.into(), + JustifyItems::End => taffy::style::JustifyItems::End.into(), + JustifyItems::FlexStart => taffy::style::JustifyItems::FlexStart.into(), + JustifyItems::FlexEnd => taffy::style::JustifyItems::FlexEnd.into(), + JustifyItems::Center => taffy::style::JustifyItems::Center.into(), + JustifyItems::Baseline => taffy::style::JustifyItems::Baseline.into(), + JustifyItems::Stretch => taffy::style::JustifyItems::Stretch.into(), } } } @@ -155,18 +179,50 @@ impl From for Option { } } -impl From for taffy::style::AlignContent { +impl From for Option { + fn from(value: JustifySelf) -> Self { + match value { + JustifySelf::Auto => None, + JustifySelf::Start => taffy::style::JustifySelf::Start.into(), + JustifySelf::End => taffy::style::JustifySelf::End.into(), + JustifySelf::FlexStart => taffy::style::JustifySelf::FlexStart.into(), + JustifySelf::FlexEnd => taffy::style::JustifySelf::FlexEnd.into(), + JustifySelf::Center => taffy::style::JustifySelf::Center.into(), + JustifySelf::Baseline => taffy::style::JustifySelf::Baseline.into(), + JustifySelf::Stretch => taffy::style::JustifySelf::Stretch.into(), + } + } +} + +impl From for Option { fn from(value: AlignContent) -> Self { match value { - AlignContent::Start => taffy::style::AlignContent::Start, - AlignContent::End => taffy::style::AlignContent::End, - AlignContent::FlexStart => taffy::style::AlignContent::FlexStart, - AlignContent::FlexEnd => taffy::style::AlignContent::FlexEnd, - AlignContent::Center => taffy::style::AlignContent::Center, - AlignContent::Stretch => taffy::style::AlignContent::Stretch, - AlignContent::SpaceBetween => taffy::style::AlignContent::SpaceBetween, - AlignContent::SpaceAround => taffy::style::AlignContent::SpaceAround, - AlignContent::SpaceEvenly => taffy::style::AlignContent::SpaceEvenly, + AlignContent::Normal => None, + AlignContent::Start => taffy::style::AlignContent::Start.into(), + AlignContent::End => taffy::style::AlignContent::End.into(), + AlignContent::FlexStart => taffy::style::AlignContent::FlexStart.into(), + AlignContent::FlexEnd => taffy::style::AlignContent::FlexEnd.into(), + AlignContent::Center => taffy::style::AlignContent::Center.into(), + AlignContent::Stretch => taffy::style::AlignContent::Stretch.into(), + AlignContent::SpaceBetween => taffy::style::AlignContent::SpaceBetween.into(), + AlignContent::SpaceAround => taffy::style::AlignContent::SpaceAround.into(), + AlignContent::SpaceEvenly => taffy::style::AlignContent::SpaceEvenly.into(), + } + } +} + +impl From for Option { + fn from(value: JustifyContent) -> Self { + match value { + JustifyContent::Normal => None, + JustifyContent::Start => taffy::style::JustifyContent::Start.into(), + JustifyContent::End => taffy::style::JustifyContent::End.into(), + JustifyContent::FlexStart => taffy::style::JustifyContent::FlexStart.into(), + JustifyContent::FlexEnd => taffy::style::JustifyContent::FlexEnd.into(), + JustifyContent::Center => taffy::style::JustifyContent::Center.into(), + JustifyContent::SpaceBetween => taffy::style::JustifyContent::SpaceBetween.into(), + JustifyContent::SpaceAround => taffy::style::JustifyContent::SpaceAround.into(), + JustifyContent::SpaceEvenly => taffy::style::JustifyContent::SpaceEvenly.into(), } } } @@ -191,21 +247,6 @@ impl From for taffy::style::FlexDirection { } } -impl From for taffy::style::JustifyContent { - fn from(value: JustifyContent) -> Self { - match value { - JustifyContent::Start => taffy::style::JustifyContent::Start, - JustifyContent::End => taffy::style::JustifyContent::End, - JustifyContent::FlexStart => taffy::style::JustifyContent::FlexStart, - JustifyContent::FlexEnd => taffy::style::JustifyContent::FlexEnd, - JustifyContent::Center => taffy::style::JustifyContent::Center, - JustifyContent::SpaceBetween => taffy::style::JustifyContent::SpaceBetween, - JustifyContent::SpaceAround => taffy::style::JustifyContent::SpaceAround, - JustifyContent::SpaceEvenly => taffy::style::JustifyContent::SpaceEvenly, - } - } -} - impl From for taffy::style::Position { fn from(value: PositionType) -> Self { match value { diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index 52290aa3a5f56..69c1956b0ad65 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -244,9 +244,14 @@ pub struct Style { pub flex_wrap: FlexWrap, /// How items are aligned according to the cross axis pub align_items: AlignItems, + /// How items are aligned according to the inline axis + pub justify_items: JustifyItems, /// How this item is aligned according to the cross axis. /// Overrides [`AlignItems`]. pub align_self: AlignSelf, + /// How this item is aligned according to the inline axis. + /// Overrides [`JustifyItems`]. + pub justify_self: JustifySelf, /// How to align each line, only applies if flex_wrap is set to /// [`FlexWrap::Wrap`] and there are multiple lines of items pub align_content: AlignContent, @@ -341,7 +346,9 @@ impl Style { flex_direction: FlexDirection::DEFAULT, flex_wrap: FlexWrap::DEFAULT, align_items: AlignItems::DEFAULT, + justify_items: JustifyItems::DEFAULT, align_self: AlignSelf::DEFAULT, + justify_self: JustifySelf::DEFAULT, align_content: AlignContent::DEFAULT, justify_content: JustifyContent::DEFAULT, position: UiRect::DEFAULT, @@ -370,6 +377,8 @@ impl Default for Style { #[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)] #[reflect(PartialEq, Serialize, Deserialize)] pub enum AlignItems { + /// The items are packed in their default position as is no alignment was applied + Normal, /// Items are packed towards the start of the axis. Start, /// Items are packed towards the end of the axis. @@ -389,7 +398,7 @@ pub enum AlignItems { } impl AlignItems { - pub const DEFAULT: Self = Self::Stretch; + pub const DEFAULT: Self = Self::Normal; } impl Default for AlignItems { @@ -398,6 +407,40 @@ impl Default for AlignItems { } } +/// How items are aligned according to the cross axis +#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)] +#[reflect(PartialEq, Serialize, Deserialize)] +pub enum JustifyItems { + /// The items are packed in their default position as is no alignment was applied + Normal, + /// Items are packed towards the start of the axis. + Start, + /// Items are packed towards the end of the axis. + End, + /// Items are packed towards the start of the axis, unless the flex direction is reversed; + /// then they are packed towards the end of the axis. + FlexStart, + /// Items are packed towards the end of the axis, unless the flex direction is reversed; + /// then they are packed towards the end of the axis. + FlexEnd, + /// Items are aligned at the center. + Center, + /// Items are aligned at the baseline. + Baseline, + /// Items are stretched across the whole cross axis. + Stretch, +} + +impl JustifyItems { + pub const DEFAULT: Self = Self::Normal; +} + +impl Default for JustifyItems { + fn default() -> Self { + Self::DEFAULT + } +} + /// How this item is aligned according to the cross axis. /// Overrides [`AlignItems`]. #[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)] @@ -433,12 +476,50 @@ impl Default for AlignSelf { } } +/// How this item is aligned according to the cross axis. +/// Overrides [`AlignItems`]. +#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)] +#[reflect(PartialEq, Serialize, Deserialize)] +pub enum JustifySelf { + /// Use the parent node's [`AlignItems`] value to determine how this item should be aligned. + Auto, + /// This item will be aligned with the start of the axis. + Start, + /// This item will be aligned with the end of the axis. + End, + /// This item will be aligned with the start of the axis, unless the flex direction is reversed; + /// then it will be aligned with the end of the axis. + FlexStart, + /// This item will be aligned with the start of the axis, unless the flex direction is reversed; + /// then it will be aligned with the end of the axis. + FlexEnd, + /// This item will be aligned at the center. + Center, + /// This item will be aligned at the baseline. + Baseline, + /// This item will be stretched across the whole cross axis. + Stretch, +} + +impl JustifySelf { + pub const DEFAULT: Self = Self::Auto; +} + +impl Default for JustifySelf { + fn default() -> Self { + Self::DEFAULT + } +} + + /// Defines how each line is aligned within the flexbox. /// /// It only applies if [`FlexWrap::Wrap`] is present and if there are multiple lines of items. #[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)] #[reflect(PartialEq, Serialize, Deserialize)] pub enum AlignContent { + /// The items are packed in their default position as is no alignment was applied + Normal, /// Each line moves towards the start of the cross axis. Start, /// Each line moves towards the end of the cross axis. @@ -463,7 +544,7 @@ pub enum AlignContent { } impl AlignContent { - pub const DEFAULT: Self = Self::Stretch; + pub const DEFAULT: Self = Self::Normal; } impl Default for AlignContent { @@ -472,6 +553,40 @@ impl Default for AlignContent { } } +/// Defines how items are aligned according to the main axis +#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)] +#[reflect(PartialEq, Serialize, Deserialize)] +pub enum JustifyContent { + /// The items are packed in their default position as is no alignment was applied + Normal, + /// Items are packed toward the start of the axis. + Start, + /// Items are packed toward the end of the axis. + End, + /// Pushed towards the start, unless the flex direction is reversed; then pushed towards the end. + FlexStart, + /// Pushed towards the end, unless the flex direction is reversed; then pushed towards the start. + FlexEnd, + /// Centered along the main axis. + Center, + /// Remaining space is distributed between the items. + SpaceBetween, + /// Remaining space is distributed around the items. + SpaceAround, + /// Like [`JustifyContent::SpaceAround`] but with even spacing between items. + SpaceEvenly, +} + +impl JustifyContent { + pub const DEFAULT: Self = Self::Normal; +} + +impl Default for JustifyContent { + fn default() -> Self { + Self::DEFAULT + } +} + /// Defines the text direction /// /// For example English is written LTR (left-to-right) while Arabic is written RTL (right-to-left). @@ -545,38 +660,6 @@ impl Default for FlexDirection { } } -/// Defines how items are aligned according to the main axis -#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)] -#[reflect(PartialEq, Serialize, Deserialize)] -pub enum JustifyContent { - /// Items are packed toward the start of the axis. - Start, - /// Items are packed toward the end of the axis. - End, - /// Pushed towards the start, unless the flex direction is reversed; then pushed towards the end. - FlexStart, - /// Pushed towards the end, unless the flex direction is reversed; then pushed towards the start. - FlexEnd, - /// Centered along the main axis. - Center, - /// Remaining space is distributed between the items. - SpaceBetween, - /// Remaining space is distributed around the items. - SpaceAround, - /// Like [`JustifyContent::SpaceAround`] but with even spacing between items. - SpaceEvenly, -} - -impl JustifyContent { - pub const DEFAULT: Self = Self::FlexStart; -} - -impl Default for JustifyContent { - fn default() -> Self { - Self::DEFAULT - } -} - /// Whether to show or hide overflowing items #[derive(Copy, Clone, PartialEq, Eq, Debug, Reflect, Serialize, Deserialize)] #[reflect(PartialEq, Serialize, Deserialize)] From 26e0803ee66ab9faebaf791326d28c8f512c6bc8 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Fri, 10 Mar 2023 15:56:58 +0000 Subject: [PATCH 03/65] Add GridAutoFlow style --- crates/bevy_ui/src/flex/convert.rs | 15 +++++++++++-- crates/bevy_ui/src/ui_node.rs | 35 ++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ui/src/flex/convert.rs b/crates/bevy_ui/src/flex/convert.rs index 6822567404752..e09609015fd0c 100644 --- a/crates/bevy_ui/src/flex/convert.rs +++ b/crates/bevy_ui/src/flex/convert.rs @@ -2,7 +2,7 @@ use taffy::style::LengthPercentageAuto; use crate::{ AlignContent, AlignItems, AlignSelf, Display, FlexDirection, FlexWrap, JustifyContent, - JustifyItems, JustifySelf, PositionType, Size, Style, UiRect, Val, + JustifyItems, JustifySelf, PositionType, Size, Style, UiRect, Val, GridAutoFlow, }; impl Val { @@ -124,11 +124,11 @@ pub fn from_style(scale_factor: f64, style: &Style) -> taffy::style::Style { max_size: style.max_size.scaled(scale_factor).into(), aspect_ratio: style.aspect_ratio, gap: style.gap.scaled(scale_factor).into(), + grid_auto_flow: style.grid_auto_flow.into(), grid_template_rows: todo!(), grid_template_columns: todo!(), grid_auto_rows: todo!(), grid_auto_columns: todo!(), - grid_auto_flow: todo!(), grid_row: todo!(), grid_column: todo!(), } @@ -265,3 +265,14 @@ impl From for taffy::style::FlexWrap { } } } + +impl From for taffy::style::GridAutoFlow { + fn from(value: GridAutoFlow) -> Self { + match value { + GridAutoFlow::Row => taffy::style::GridAutoFlow::Row, + GridAutoFlow::RowDense => taffy::style::GridAutoFlow::RowDense, + GridAutoFlow::Column => taffy::style::GridAutoFlow::Column, + GridAutoFlow::ColumnDense => taffy::style::GridAutoFlow::ColumnDense, + } + } +} diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index 69c1956b0ad65..4794e679dcbe9 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -336,6 +336,10 @@ pub struct Style { /// /// Values of `Size::UNDEFINED` and `Size::AUTO` are treated as zero. pub gap: Size, + /// Controls whether grid items are placed row-wise or column-wise. And whether the sparse or dense packing algorithm is used. + /// + /// Only affect Grid layouts + pub grid_auto_flow: GridAutoFlow } impl Style { @@ -364,6 +368,7 @@ impl Style { aspect_ratio: None, overflow: Overflow::DEFAULT, gap: Size::UNDEFINED, + grid_auto_flow: GridAutoFlow::DEFAULT, }; } @@ -724,6 +729,36 @@ impl Default for FlexWrap { } } +/// Controls whether grid items are placed row-wise or column-wise. And whether the sparse or dense packing algorithm is used. +/// +/// The "dense" packing algorithm attempts to fill in holes earlier in the grid, if smaller items come up later. This may cause items to appear out-of-order, when doing so would fill in holes left by larger items. +/// +/// Defaults to [`GridAutoFlow::Row`] +/// +/// [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/grid-auto-flow) +#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)] +#[reflect(PartialEq, Serialize, Deserialize)] +pub enum GridAutoFlow { + /// Items are placed by filling each row in turn, adding new rows as necessary + Row, + /// Items are placed by filling each column in turn, adding new columns as necessary. + Column, + /// Combines `Row` with the dense packing algorithm. + RowDense, + /// Combines `Column` with the dense packing algorithm. + ColumnDense, +} + +impl GridAutoFlow { + const DEFAULT: Self = Self::Row; +} + +impl Default for GridAutoFlow { + fn default() -> Self { + Self::DEFAULT + } +} + /// The calculated size of the node #[derive(Component, Copy, Clone, Debug, Reflect)] #[reflect(Component)] From 8c2c345b2a00fe5188deb2e49325a4c7c229e964 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Fri, 10 Mar 2023 15:57:59 +0000 Subject: [PATCH 04/65] Add Grid variant to Display enum --- crates/bevy_ui/src/flex/convert.rs | 1 + crates/bevy_ui/src/ui_node.rs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/crates/bevy_ui/src/flex/convert.rs b/crates/bevy_ui/src/flex/convert.rs index e09609015fd0c..c729995b1dea5 100644 --- a/crates/bevy_ui/src/flex/convert.rs +++ b/crates/bevy_ui/src/flex/convert.rs @@ -231,6 +231,7 @@ impl From for taffy::style::Display { fn from(value: Display) -> Self { match value { Display::Flex => taffy::style::Display::Flex, + Display::Grid => taffy::style::Display::Grid, Display::None => taffy::style::Display::None, } } diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index 4794e679dcbe9..a46efa5ca05a1 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -624,6 +624,8 @@ impl Default for Direction { pub enum Display { /// Use Flexbox layout model to determine the position of this [`Node`]. Flex, + /// Use CSS Grid layout model to determine the position of this [`Node`]. + Grid, /// Use no layout, don't render this node and its children. /// /// If you want to hide a node and its children, From 8f4f276a2622b5807119da711de8a505152185fd Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Fri, 10 Mar 2023 16:17:28 +0000 Subject: [PATCH 05/65] Implement GridPlacement properties --- crates/bevy_ui/src/flex/convert.rs | 18 +++++++-- crates/bevy_ui/src/ui_node.rs | 59 +++++++++++++++++++++++++++++- 2 files changed, 72 insertions(+), 5 deletions(-) diff --git a/crates/bevy_ui/src/flex/convert.rs b/crates/bevy_ui/src/flex/convert.rs index c729995b1dea5..b3d3c32d126af 100644 --- a/crates/bevy_ui/src/flex/convert.rs +++ b/crates/bevy_ui/src/flex/convert.rs @@ -1,8 +1,9 @@ use taffy::style::LengthPercentageAuto; +use taffy::style_helpers; use crate::{ AlignContent, AlignItems, AlignSelf, Display, FlexDirection, FlexWrap, JustifyContent, - JustifyItems, JustifySelf, PositionType, Size, Style, UiRect, Val, GridAutoFlow, + JustifyItems, JustifySelf, PositionType, Size, Style, UiRect, Val, GridAutoFlow, GridPlacement, }; impl Val { @@ -129,8 +130,8 @@ pub fn from_style(scale_factor: f64, style: &Style) -> taffy::style::Style { grid_template_columns: todo!(), grid_auto_rows: todo!(), grid_auto_columns: todo!(), - grid_row: todo!(), - grid_column: todo!(), + grid_row: style.grid_row.into(), + grid_column: style.grid_column.into(), } } @@ -277,3 +278,14 @@ impl From for taffy::style::GridAutoFlow { } } } + +impl From for taffy::geometry::Line { + fn from(value: GridPlacement) -> Self { + let start = match value.start { + None => taffy::style::GridPlacement::Auto, + Some(start) => style_helpers::line(start as i16) + }; + let span = taffy::style::GridPlacement::Span(value.span); + taffy::geometry::Line { start, end: span } + } +} diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index a46efa5ca05a1..d81572f9ac9ef 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -339,7 +339,11 @@ pub struct Style { /// Controls whether grid items are placed row-wise or column-wise. And whether the sparse or dense packing algorithm is used. /// /// Only affect Grid layouts - pub grid_auto_flow: GridAutoFlow + pub grid_auto_flow: GridAutoFlow, + /// The column in which a grid item starts and how many columns it span + pub grid_column: GridPlacement, + /// The row in which a grid item starts and how many rows it span + pub grid_row: GridPlacement, } impl Style { @@ -369,6 +373,8 @@ impl Style { overflow: Overflow::DEFAULT, gap: Size::UNDEFINED, grid_auto_flow: GridAutoFlow::DEFAULT, + grid_column: GridPlacement::DEFAULT, + grid_row: GridPlacement::DEFAULT, }; } @@ -516,7 +522,6 @@ impl Default for JustifySelf { } } - /// Defines how each line is aligned within the flexbox. /// /// It only applies if [`FlexWrap::Wrap`] is present and if there are multiple lines of items. @@ -761,6 +766,56 @@ impl Default for GridAutoFlow { } } +#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)] +#[reflect(PartialEq, Serialize, Deserialize)] +pub struct GridPlacement { + /// The grid line at which the node should start. Lines are 1-indexed. + /// None indicates automatic placement. + pub start: Option, + /// How many grid tracks the node should span. Defaults to 1. + pub span: u16, +} + +impl GridPlacement { + const DEFAULT: Self = Self { + start: None, + span: 1, + }; + + /// Place the grid item automatically and make it span 1 track + pub fn auto() -> Self { + Self { start: None, span: 1} + } + + /// Place the grid item starting in the specified track + pub fn start(start: u16) -> Self { + Self { start: Some(start), span: 1} + } + + /// Place the grid item automatically and make it span the specified number of tracks + pub fn span(span: u16) -> Self { + Self { start: None, span } + } + + /// Place the grid item starting in the specified track + pub fn set_start(mut self, start: u16) -> Self { + self.start = Some(start); + self + } + + /// Place the grid item automatically and make it span the specified number of tracks + pub fn set_span(mut self, span: u16) -> Self { + self.span = span; + self + } +} + +impl Default for GridPlacement { + fn default() -> Self { + Self::DEFAULT + } +} + /// The calculated size of the node #[derive(Component, Copy, Clone, Debug, Reflect)] #[reflect(Component)] From b4f7b9a47930b44448f4ea015ef0eedde5aa85a0 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Fri, 10 Mar 2023 16:43:34 +0000 Subject: [PATCH 06/65] Implement GridTrack type --- crates/bevy_ui/src/flex/convert.rs | 63 +++++++++++++++-- crates/bevy_ui/src/ui_node.rs | 106 +++++++++++++++++++++++++++++ 2 files changed, 162 insertions(+), 7 deletions(-) diff --git a/crates/bevy_ui/src/flex/convert.rs b/crates/bevy_ui/src/flex/convert.rs index b3d3c32d126af..1d34dd6639809 100644 --- a/crates/bevy_ui/src/flex/convert.rs +++ b/crates/bevy_ui/src/flex/convert.rs @@ -2,8 +2,9 @@ use taffy::style::LengthPercentageAuto; use taffy::style_helpers; use crate::{ - AlignContent, AlignItems, AlignSelf, Display, FlexDirection, FlexWrap, JustifyContent, - JustifyItems, JustifySelf, PositionType, Size, Style, UiRect, Val, GridAutoFlow, GridPlacement, + AlignContent, AlignItems, AlignSelf, Display, FlexDirection, FlexWrap, GridAutoFlow, + GridPlacement, GridTrack, JustifyContent, JustifyItems, JustifySelf, MaxTrackSizingFunction, + MinTrackSizingFunction, PositionType, Size, Style, UiRect, Val, }; impl Val { @@ -126,10 +127,10 @@ pub fn from_style(scale_factor: f64, style: &Style) -> taffy::style::Style { aspect_ratio: style.aspect_ratio, gap: style.gap.scaled(scale_factor).into(), grid_auto_flow: style.grid_auto_flow.into(), - grid_template_rows: todo!(), - grid_template_columns: todo!(), - grid_auto_rows: todo!(), - grid_auto_columns: todo!(), + grid_template_rows: style.grid_template_rows.into(), + grid_template_columns: style.grid_template_columns.into(), + grid_auto_rows: style.grid_auto_rows.into(), + grid_auto_columns: style.grid_auto_columns.into(), grid_row: style.grid_row.into(), grid_column: style.grid_column.into(), } @@ -283,9 +284,57 @@ impl From for taffy::geometry::Line fn from(value: GridPlacement) -> Self { let start = match value.start { None => taffy::style::GridPlacement::Auto, - Some(start) => style_helpers::line(start as i16) + Some(start) => style_helpers::line(start as i16), }; let span = taffy::style::GridPlacement::Span(value.span); taffy::geometry::Line { start, end: span } } } + +impl From for taffy::style::MinTrackSizingFunction { + fn from(value: MinTrackSizingFunction) -> Self { + match value { + MinTrackSizingFunction::Fixed(val) => { + taffy::style::MinTrackSizingFunction::Fixed(val.into()) + } + MinTrackSizingFunction::Auto => taffy::style::MinTrackSizingFunction::Auto, + MinTrackSizingFunction::MinContent => taffy::style::MinTrackSizingFunction::MinContent, + MinTrackSizingFunction::MaxContent => taffy::style::MinTrackSizingFunction::MaxContent, + } + } +} + +impl From for taffy::style::MaxTrackSizingFunction { + fn from(value: MaxTrackSizingFunction) -> Self { + match value { + MaxTrackSizingFunction::Fixed(val) => { + taffy::style::MaxTrackSizingFunction::Fixed(val.into()) + } + MaxTrackSizingFunction::Auto => taffy::style::MaxTrackSizingFunction::Auto, + MaxTrackSizingFunction::MinContent => taffy::style::MaxTrackSizingFunction::MinContent, + MaxTrackSizingFunction::MaxContent => taffy::style::MaxTrackSizingFunction::MaxContent, + MaxTrackSizingFunction::FitContent(val) => { + taffy::style::MaxTrackSizingFunction::FitContent(val.into()) + } + MaxTrackSizingFunction::Fraction(fraction) => { + taffy::style::MaxTrackSizingFunction::Fraction(fraction) + } + } + } +} + +impl From for taffy::style::NonRepeatedTrackSizingFunction { + fn from(value: GridTrack) -> Self { + let min = value.min_sizing_function.into(); + let max = value.max_sizing_function.into(); + taffy::style_helpers::minmax(min, max) + } +} + +impl From for taffy::style::TrackSizingFunction { + fn from(value: GridTrack) -> Self { + let min = value.min_sizing_function.into(); + let max = value.max_sizing_function.into(); + taffy::style_helpers::minmax(min, max) + } +} diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index d81572f9ac9ef..f7752114ba29b 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -340,6 +340,14 @@ pub struct Style { /// /// Only affect Grid layouts pub grid_auto_flow: GridAutoFlow, + /// Defines the track sizing functions (widths) of the grid rows + pub grid_template_rows: Vec, + /// Defines the track sizing functions (heights) of the grid columns + pub grid_template_columns: Vec, + /// Defines the size of implicitly created rows + pub grid_auto_rows: Vec, + /// Defined the size of implicitly created columns + pub grid_auto_columns: Vec, /// The column in which a grid item starts and how many columns it span pub grid_column: GridPlacement, /// The row in which a grid item starts and how many rows it span @@ -373,6 +381,10 @@ impl Style { overflow: Overflow::DEFAULT, gap: Size::UNDEFINED, grid_auto_flow: GridAutoFlow::DEFAULT, + grid_template_rows: Vec::new(), + grid_template_columns: Vec::new(), + grid_auto_rows: Vec::new(), + grid_auto_columns: Vec::new(), grid_column: GridPlacement::DEFAULT, grid_row: GridPlacement::DEFAULT, }; @@ -766,6 +778,100 @@ impl Default for GridAutoFlow { } } +#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect)] +#[reflect_value(PartialEq, Serialize, Deserialize)] +pub(crate) enum MinTrackSizingFunction { + /// Track minimum size should be a fixed points or percentage value + Fixed(Val), + /// Track minimum size should be content sized under a min-content constraint + MinContent, + /// Track minimum size should be content sized under a max-content constraint + MaxContent, + /// Track minimum size should be automatically sized + Auto, +} + +#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect)] +#[reflect_value(PartialEq, Serialize, Deserialize)] +pub (crate) enum MaxTrackSizingFunction { + /// Track maximum size should be a fixed points or percentage value + Fixed(Val), + /// Track maximum size should be content sized under a min-content constraint + MinContent, + /// Track maximum size should be content sized under a max-content constraint + MaxContent, + /// Track maximum size should be sized according to the fit-content formula + FitContent(Val), + /// Track maximum size should be automatically sized + Auto, + /// The dimension as a fraction of the total available grid space (`fr` units in CSS) + /// Specified value is the numerator of the fraction. Denominator is the sum of all fraction specified in that grid dimension + /// Spec: + Fraction(f32), +} + +#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect)] +#[reflect(PartialEq, Serialize, Deserialize)] +pub struct GridTrack { + pub(crate) min_sizing_function: MinTrackSizingFunction, + pub(crate) max_sizing_function: MaxTrackSizingFunction, +} + +impl GridTrack { + const DEFAULT: Self = Self { + min_sizing_function: MinTrackSizingFunction::Auto, + max_sizing_function: MaxTrackSizingFunction::Auto, + }; + + /// Create a grid track with automatic size + pub fn auto() -> Self { + Self { + min_sizing_function: MinTrackSizingFunction::Auto, + max_sizing_function: MaxTrackSizingFunction::Auto, + } + } + + /// Create a grid track with a fixed pixel size + pub fn px(value: f32) -> Self { + Self { + min_sizing_function: MinTrackSizingFunction::Fixed(Val::Px(value)), + max_sizing_function: MaxTrackSizingFunction::Fixed(Val::Px(value)), + } + } + + /// Create a grid track with a percentage size + pub fn percent(value: f32) -> Self { + Self { + min_sizing_function: MinTrackSizingFunction::Fixed(Val::Percent(value)), + max_sizing_function: MaxTrackSizingFunction::Fixed(Val::Percent(value)), + } + } + + /// Create a grid track with an `fr` size. + /// Note that this will give the track a content-based minimum size. + /// Usually you are best off using `GridTrack::flex` instead which uses a zero minimum size + pub fn fr(value: f32) -> Self { + Self { + min_sizing_function: MinTrackSizingFunction::Auto, + max_sizing_function: MaxTrackSizingFunction::Fraction(value), + } + } + + /// Create a grid track with an `minmax(0, Nfr)` size. + pub fn flex(value: f32) -> Self { + Self { + min_sizing_function: MinTrackSizingFunction::Fixed(Val::Px(0.0)), + max_sizing_function: MaxTrackSizingFunction::Fraction(value), + } + } +} + +impl Default for GridTrack { + fn default() -> Self { + Self::DEFAULT + } +} + #[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)] #[reflect(PartialEq, Serialize, Deserialize)] pub struct GridPlacement { From 92cfb4a4d8c72e47aa66394282dd9fcb75655f8f Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Fri, 10 Mar 2023 16:59:28 +0000 Subject: [PATCH 07/65] Ignore fields that are problematic for reflection --- crates/bevy_ui/src/ui_node.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index f7752114ba29b..161332e41192b 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -341,12 +341,16 @@ pub struct Style { /// Only affect Grid layouts pub grid_auto_flow: GridAutoFlow, /// Defines the track sizing functions (widths) of the grid rows + #[reflect(ignore)] pub grid_template_rows: Vec, /// Defines the track sizing functions (heights) of the grid columns + #[reflect(ignore)] pub grid_template_columns: Vec, /// Defines the size of implicitly created rows + #[reflect(ignore)] pub grid_auto_rows: Vec, /// Defined the size of implicitly created columns + #[reflect(ignore)] pub grid_auto_columns: Vec, /// The column in which a grid item starts and how many columns it span pub grid_column: GridPlacement, From c92d8a70dfb5ab3b51a9b385afa050994a52458a Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Fri, 10 Mar 2023 16:59:41 +0000 Subject: [PATCH 08/65] Fix conversion of grid track lists --- crates/bevy_ui/src/flex/convert.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/bevy_ui/src/flex/convert.rs b/crates/bevy_ui/src/flex/convert.rs index 1d34dd6639809..f44012e95029d 100644 --- a/crates/bevy_ui/src/flex/convert.rs +++ b/crates/bevy_ui/src/flex/convert.rs @@ -127,10 +127,10 @@ pub fn from_style(scale_factor: f64, style: &Style) -> taffy::style::Style { aspect_ratio: style.aspect_ratio, gap: style.gap.scaled(scale_factor).into(), grid_auto_flow: style.grid_auto_flow.into(), - grid_template_rows: style.grid_template_rows.into(), - grid_template_columns: style.grid_template_columns.into(), - grid_auto_rows: style.grid_auto_rows.into(), - grid_auto_columns: style.grid_auto_columns.into(), + grid_template_rows: style.grid_template_rows.iter().map(|item| (*item).into()).collect::>(), + grid_template_columns: style.grid_template_columns.iter().map(|item| (*item).into()).collect::>(), + grid_auto_rows: style.grid_auto_rows.iter().map(|item| (*item).into()).collect::>(), + grid_auto_columns: style.grid_auto_columns.iter().map(|item| (*item).into()).collect::>(), grid_row: style.grid_row.into(), grid_column: style.grid_column.into(), } From ad7b087096a665d88e85d36f916c0325e59e0aff Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Fri, 10 Mar 2023 17:02:36 +0000 Subject: [PATCH 09/65] cargo fmt --- crates/bevy_ui/src/flex/convert.rs | 24 ++++++++++++++++++++---- crates/bevy_ui/src/ui_node.rs | 12 +++++++++--- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/crates/bevy_ui/src/flex/convert.rs b/crates/bevy_ui/src/flex/convert.rs index f44012e95029d..a125b59e282a2 100644 --- a/crates/bevy_ui/src/flex/convert.rs +++ b/crates/bevy_ui/src/flex/convert.rs @@ -127,10 +127,26 @@ pub fn from_style(scale_factor: f64, style: &Style) -> taffy::style::Style { aspect_ratio: style.aspect_ratio, gap: style.gap.scaled(scale_factor).into(), grid_auto_flow: style.grid_auto_flow.into(), - grid_template_rows: style.grid_template_rows.iter().map(|item| (*item).into()).collect::>(), - grid_template_columns: style.grid_template_columns.iter().map(|item| (*item).into()).collect::>(), - grid_auto_rows: style.grid_auto_rows.iter().map(|item| (*item).into()).collect::>(), - grid_auto_columns: style.grid_auto_columns.iter().map(|item| (*item).into()).collect::>(), + grid_template_rows: style + .grid_template_rows + .iter() + .map(|item| (*item).into()) + .collect::>(), + grid_template_columns: style + .grid_template_columns + .iter() + .map(|item| (*item).into()) + .collect::>(), + grid_auto_rows: style + .grid_auto_rows + .iter() + .map(|item| (*item).into()) + .collect::>(), + grid_auto_columns: style + .grid_auto_columns + .iter() + .map(|item| (*item).into()) + .collect::>(), grid_row: style.grid_row.into(), grid_column: style.grid_column.into(), } diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index 161332e41192b..3924ccd280424 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -797,7 +797,7 @@ pub(crate) enum MinTrackSizingFunction { #[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect)] #[reflect_value(PartialEq, Serialize, Deserialize)] -pub (crate) enum MaxTrackSizingFunction { +pub(crate) enum MaxTrackSizingFunction { /// Track maximum size should be a fixed points or percentage value Fixed(Val), /// Track maximum size should be content sized under a min-content constraint @@ -894,12 +894,18 @@ impl GridPlacement { /// Place the grid item automatically and make it span 1 track pub fn auto() -> Self { - Self { start: None, span: 1} + Self { + start: None, + span: 1, + } } /// Place the grid item starting in the specified track pub fn start(start: u16) -> Self { - Self { start: Some(start), span: 1} + Self { + start: Some(start), + span: 1, + } } /// Place the grid item automatically and make it span the specified number of tracks From 437c55b7a7d8df07bff533754793ce5466e6e597 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Fri, 10 Mar 2023 17:03:27 +0000 Subject: [PATCH 10/65] Remove const modifier from with_style function --- crates/bevy_ui/src/node_bundles.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_ui/src/node_bundles.rs b/crates/bevy_ui/src/node_bundles.rs index e0eee6a61062a..448ded1c9aa92 100644 --- a/crates/bevy_ui/src/node_bundles.rs +++ b/crates/bevy_ui/src/node_bundles.rs @@ -179,7 +179,7 @@ impl TextBundle { } /// Returns this [`TextBundle`] with a new [`Style`]. - pub const fn with_style(mut self, style: Style) -> Self { + pub fn with_style(mut self, style: Style) -> Self { self.style = style; self } From 25ed5590ff97676e79e6f9ee2919daf4f056d76b Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Fri, 10 Mar 2023 17:40:00 +0000 Subject: [PATCH 11/65] Add CSS Grid example --- Cargo.toml | 4 ++ examples/ui/grid.rs | 159 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 163 insertions(+) create mode 100644 examples/ui/grid.rs diff --git a/Cargo.toml b/Cargo.toml index ac0fd63b8cdd3..9a1c981e251b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1729,6 +1729,10 @@ wasm = true name = "text_layout" path = "examples/ui/text_layout.rs" +[[example]] +name = "grid" +path = "examples/ui/grid.rs" + [package.metadata.example.text_layout] name = "Text Layout" description = "Demonstrates how the AlignItems and JustifyContent properties can be composed to layout text" diff --git a/examples/ui/grid.rs b/examples/ui/grid.rs new file mode 100644 index 0000000000000..953b085a5d240 --- /dev/null +++ b/examples/ui/grid.rs @@ -0,0 +1,159 @@ +//! Demonstrates how the `AlignItems` and `JustifyContent` properties can be composed to layout text. +use bevy::prelude::*; + +const ALIGN_ITEMS_COLOR: Color = Color::rgb(1., 0.066, 0.349); +const MARGIN: Val = Val::Px(5.); + +fn main() { + App::new() + .add_plugins(DefaultPlugins.set(WindowPlugin { + primary_window: Some(Window { + resolution: [870., 1066.].into(), + title: "Bevy CSS Grid Layout Example".to_string(), + ..default() + }), + ..default() + })) + .add_startup_system(spawn_layout) + .run(); +} + +fn rect(color: Color) -> NodeBundle { + NodeBundle { + background_color: BackgroundColor(color), + ..default() + } +} + +fn spawn_layout(mut commands: Commands, asset_server: Res) { + let font = asset_server.load("fonts/FiraSans-Bold.ttf"); + commands.spawn(Camera2dBundle::default()); + commands + .spawn(NodeBundle { + style: Style { + display: Display::Grid, + size: Size::all(Val::Percent(100.)), + grid_template_columns: vec![GridTrack::flex(1.), GridTrack::flex(2.), GridTrack::flex(1.)], + grid_template_rows: vec![GridTrack::auto(), GridTrack::px(150.), GridTrack::flex(1.)], + gap: Size::all(Val::Px(20.)), + ..default() + }, + background_color: BackgroundColor(Color::BLACK), + ..default() + }) + .with_children(|builder| { + builder.spawn(rect(Color::BLACK)); + builder.spawn(NodeBundle { + style: Style { + display: Display::Grid, + ..default() + }, + ..default() + }) + .with_children(|builder| { + + spawn_nested_text_bundle( + builder, + font.clone(), + ALIGN_ITEMS_COLOR, + UiRect::right(MARGIN), + "hello world", + ); + + const REALLY_LONG_PARAGRAPH : &str = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; + spawn_nested_text_bundle( + builder, + font.clone(), + ALIGN_ITEMS_COLOR, + UiRect::right(MARGIN), + REALLY_LONG_PARAGRAPH, + ); + }); + + builder.spawn(rect(Color::ALICE_BLUE)); + builder.spawn(rect(Color::ANTIQUE_WHITE)); + builder.spawn(rect(Color::AQUAMARINE)); + builder.spawn(rect(Color::AZURE)); + builder.spawn(rect(Color::DARK_GREEN)); + + + builder.spawn(NodeBundle { + style: Style { + display: Display::Grid, + grid_template_columns: vec![GridTrack::flex(1.), GridTrack::flex(2.), GridTrack::flex(1.)], + grid_template_rows: vec![GridTrack::flex(1.), GridTrack::percent(50.), GridTrack::flex(1.)], + ..default() + }, + ..default() + }) + .with_children(|builder| { + builder.spawn(rect(Color::ORANGE)); + builder.spawn(rect(Color::BISQUE)); + builder.spawn(rect(Color::BLUE)); + builder.spawn(rect(Color::CRIMSON)); + + // .with_styled_child(button("Increment").on_press(Message::Increment), |style| { + // style.align_self = Some(AlignSelf::Center); + // style.justify_self = Some(AlignSelf::Center); + // }) + builder.spawn(rect(Color::CYAN)); + + builder.spawn(rect(Color::ORANGE_RED)); + builder.spawn(rect(Color::DARK_GREEN)); + builder.spawn(rect(Color::FUCHSIA)); + builder.spawn(rect(Color::GOLD)); + + builder.spawn(NodeBundle { + style: Style { + position_type: PositionType::Absolute, + grid_row: GridPlacement::start(1), + grid_column: GridPlacement::start(1), + position: UiRect { + left: Val::Px(10.), + top: Val::Px(10.), + ..default() + }, + ..default() + }, + ..default() + }); + }); + + builder.spawn(rect(Color::GREEN)); + }); +} + +fn spawn_nested_text_bundle( + builder: &mut ChildBuilder, + font: Handle, + background_color: Color, + margin: UiRect, + text: &str, +) { + builder + .spawn(NodeBundle { + style: Style { + margin, + padding: UiRect { + top: Val::Px(1.), + left: Val::Px(5.), + right: Val::Px(5.), + bottom: Val::Px(1.), + }, + min_size: Size::width(Val::Px(0.)), + ..default() + }, + background_color: BackgroundColor(background_color), + ..default() + }) + .with_children(|builder| { + builder.spawn(TextBundle::from_section( + text, + TextStyle { + font, + font_size: 24.0, + color: Color::BLACK, + }, + )); + }); +} From 3d5e948b8e55e064e476c99b4c8b652d2d7f7914 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Fri, 10 Mar 2023 17:47:14 +0000 Subject: [PATCH 12/65] Add metadata to example --- Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 9a1c981e251b9..b65af85307154 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1731,7 +1731,10 @@ path = "examples/ui/text_layout.rs" [[example]] name = "grid" +description = "An example for CSS Grid layout" +category = "UI (User Interface)" path = "examples/ui/grid.rs" +wasm=false [package.metadata.example.text_layout] name = "Text Layout" From d8a9d6b16af91ac6a40334370a262f050f8aaa58 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Fri, 10 Mar 2023 17:53:44 +0000 Subject: [PATCH 13/65] Fix example metadata (take 2) --- Cargo.toml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b65af85307154..d6a6ba8c5253d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1729,16 +1729,19 @@ wasm = true name = "text_layout" path = "examples/ui/text_layout.rs" +[package.metadata.example.text_layout] +name = "Text Layout" +description = "Demonstrates how the AlignItems and JustifyContent properties can be composed to layout text" +category = "UI (User Interface)" +wasm = false + [[example]] name = "grid" -description = "An example for CSS Grid layout" -category = "UI (User Interface)" path = "examples/ui/grid.rs" -wasm=false -[package.metadata.example.text_layout] -name = "Text Layout" -description = "Demonstrates how the AlignItems and JustifyContent properties can be composed to layout text" +[package.metadata.example.grid] +name = "CSS Grid" +description = "An example for CSS Grid layout" category = "UI (User Interface)" wasm = false From c83676255b34d372992bab3a2fcafa5f8c2677fd Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Fri, 10 Mar 2023 17:54:02 +0000 Subject: [PATCH 14/65] Fix reflection of Style struct --- crates/bevy_ui/src/ui_node.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index 3924ccd280424..04daf9e4a6a30 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -341,16 +341,12 @@ pub struct Style { /// Only affect Grid layouts pub grid_auto_flow: GridAutoFlow, /// Defines the track sizing functions (widths) of the grid rows - #[reflect(ignore)] pub grid_template_rows: Vec, /// Defines the track sizing functions (heights) of the grid columns - #[reflect(ignore)] pub grid_template_columns: Vec, /// Defines the size of implicitly created rows - #[reflect(ignore)] pub grid_auto_rows: Vec, /// Defined the size of implicitly created columns - #[reflect(ignore)] pub grid_auto_columns: Vec, /// The column in which a grid item starts and how many columns it span pub grid_column: GridPlacement, @@ -782,7 +778,7 @@ impl Default for GridAutoFlow { } } -#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect)] +#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect, FromReflect)] #[reflect_value(PartialEq, Serialize, Deserialize)] pub(crate) enum MinTrackSizingFunction { /// Track minimum size should be a fixed points or percentage value @@ -795,7 +791,7 @@ pub(crate) enum MinTrackSizingFunction { Auto, } -#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect)] +#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect, FromReflect)] #[reflect_value(PartialEq, Serialize, Deserialize)] pub(crate) enum MaxTrackSizingFunction { /// Track maximum size should be a fixed points or percentage value @@ -814,7 +810,7 @@ pub(crate) enum MaxTrackSizingFunction { Fraction(f32), } -#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect)] +#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect, FromReflect)] #[reflect(PartialEq, Serialize, Deserialize)] pub struct GridTrack { pub(crate) min_sizing_function: MinTrackSizingFunction, From 8b569a74c9c9b3b6f25ec435dcf15b73ad2a9890 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Fri, 10 Mar 2023 17:54:56 +0000 Subject: [PATCH 15/65] Make default window size of grid example smaller --- examples/ui/grid.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/ui/grid.rs b/examples/ui/grid.rs index 953b085a5d240..ef792c3c30949 100644 --- a/examples/ui/grid.rs +++ b/examples/ui/grid.rs @@ -8,7 +8,7 @@ fn main() { App::new() .add_plugins(DefaultPlugins.set(WindowPlugin { primary_window: Some(Window { - resolution: [870., 1066.].into(), + resolution: [800., 600.].into(), title: "Bevy CSS Grid Layout Example".to_string(), ..default() }), From 458abbc232581f09d12c982e16b5a6fe5468d4f4 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Fri, 10 Mar 2023 17:58:58 +0000 Subject: [PATCH 16/65] Format example --- examples/ui/grid.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/ui/grid.rs b/examples/ui/grid.rs index ef792c3c30949..bf146b9e5c785 100644 --- a/examples/ui/grid.rs +++ b/examples/ui/grid.rs @@ -44,12 +44,12 @@ fn spawn_layout(mut commands: Commands, asset_server: Res) { .with_children(|builder| { builder.spawn(rect(Color::BLACK)); builder.spawn(NodeBundle { - style: Style { - display: Display::Grid, - ..default() - }, + style: Style { + display: Display::Grid, ..default() - }) + }, + ..default() + }) .with_children(|builder| { spawn_nested_text_bundle( From 1b6b271d3ee95dccc45847bea8026eaee2a1724b Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Fri, 10 Mar 2023 18:11:05 +0000 Subject: [PATCH 17/65] Update example docs --- examples/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/README.md b/examples/README.md index bc03d2382c372..49a0404122256 100644 --- a/examples/README.md +++ b/examples/README.md @@ -325,6 +325,7 @@ Example | Description Example | Description --- | --- [Button](../examples/ui/button.rs) | Illustrates creating and updating a button +[CSS Grid](../examples/ui/grid.rs) | An example for CSS Grid layout [Font Atlas Debug](../examples/ui/font_atlas_debug.rs) | Illustrates how FontAtlases are populated (used to optimize text rendering internally) [Relative Cursor Position](../examples/ui/relative_cursor_position.rs) | Showcases the RelativeCursorPosition component [Text](../examples/ui/text.rs) | Illustrates creating and updating text From 58d0a18298f56aecb3fe653112a0c8930b1ad1a2 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Fri, 10 Mar 2023 18:29:42 +0000 Subject: [PATCH 18/65] Fix position:absolute node not displaying --- examples/ui/grid.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/ui/grid.rs b/examples/ui/grid.rs index bf146b9e5c785..b65da5b98e8c2 100644 --- a/examples/ui/grid.rs +++ b/examples/ui/grid.rs @@ -1,4 +1,4 @@ -//! Demonstrates how the `AlignItems` and `JustifyContent` properties can be composed to layout text. +//! Demonstrates how CSS Grid layout can be used to lay items out in a 2D grid use bevy::prelude::*; const ALIGN_ITEMS_COLOR: Color = Color::rgb(1., 0.066, 0.349); @@ -38,7 +38,7 @@ fn spawn_layout(mut commands: Commands, asset_server: Res) { gap: Size::all(Val::Px(20.)), ..default() }, - background_color: BackgroundColor(Color::BLACK), + background_color: BackgroundColor(Color::WHITE), ..default() }) .with_children(|builder| { @@ -113,8 +113,10 @@ fn spawn_layout(mut commands: Commands, asset_server: Res) { top: Val::Px(10.), ..default() }, + size: Size::all(Val::Px(40.)), ..default() }, + background_color: BackgroundColor(Color::BLACK), ..default() }); }); From a5c15a27e0f44ecab30a4d1c9be54a3b0a5c6087 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Fri, 10 Mar 2023 20:09:05 +0000 Subject: [PATCH 19/65] Apply suggestions from code review Co-authored-by: Rob Parrett --- crates/bevy_ui/src/ui_node.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index 04daf9e4a6a30..177f1e9ce0767 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -400,7 +400,7 @@ impl Default for Style { #[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)] #[reflect(PartialEq, Serialize, Deserialize)] pub enum AlignItems { - /// The items are packed in their default position as is no alignment was applied + /// The items are packed in their default position as if no alignment was applied Normal, /// Items are packed towards the start of the axis. Start, @@ -434,7 +434,7 @@ impl Default for AlignItems { #[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)] #[reflect(PartialEq, Serialize, Deserialize)] pub enum JustifyItems { - /// The items are packed in their default position as is no alignment was applied + /// The items are packed in their default position as if no alignment was applied Normal, /// Items are packed towards the start of the axis. Start, @@ -444,7 +444,7 @@ pub enum JustifyItems { /// then they are packed towards the end of the axis. FlexStart, /// Items are packed towards the end of the axis, unless the flex direction is reversed; - /// then they are packed towards the end of the axis. + /// then they are packed towards the start of the axis. FlexEnd, /// Items are aligned at the center. Center, @@ -513,8 +513,8 @@ pub enum JustifySelf { /// This item will be aligned with the start of the axis, unless the flex direction is reversed; /// then it will be aligned with the end of the axis. FlexStart, - /// This item will be aligned with the start of the axis, unless the flex direction is reversed; - /// then it will be aligned with the end of the axis. + /// This item will be aligned with the end of the axis, unless the flex direction is reversed; + /// then it will be aligned with the start of the axis. FlexEnd, /// This item will be aligned at the center. Center, @@ -540,7 +540,7 @@ impl Default for JustifySelf { #[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)] #[reflect(PartialEq, Serialize, Deserialize)] pub enum AlignContent { - /// The items are packed in their default position as is no alignment was applied + /// The items are packed in their default position as if no alignment was applied Normal, /// Each line moves towards the start of the cross axis. Start, @@ -579,7 +579,7 @@ impl Default for AlignContent { #[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)] #[reflect(PartialEq, Serialize, Deserialize)] pub enum JustifyContent { - /// The items are packed in their default position as is no alignment was applied + /// The items are packed in their default position as if no alignment was applied Normal, /// Items are packed toward the start of the axis. Start, From 414f15490d5a6f035fddb1fbcc61e09ef8cb7f59 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Fri, 10 Mar 2023 20:09:47 +0000 Subject: [PATCH 20/65] Update crates/bevy_ui/src/ui_node.rs Co-authored-by: Rob Parrett --- crates/bevy_ui/src/ui_node.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index 177f1e9ce0767..ec91087810658 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -805,7 +805,7 @@ pub(crate) enum MaxTrackSizingFunction { /// Track maximum size should be automatically sized Auto, /// The dimension as a fraction of the total available grid space (`fr` units in CSS) - /// Specified value is the numerator of the fraction. Denominator is the sum of all fraction specified in that grid dimension + /// Specified value is the numerator of the fraction. Denominator is the sum of all fractions specified in that grid dimension /// Spec: Fraction(f32), } From 5a3c8f07ffbf986a2af454be4284a39ba1a267cb Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Fri, 10 Mar 2023 20:13:10 +0000 Subject: [PATCH 21/65] Rename Normal variants to Default --- crates/bevy_ui/src/flex/convert.rs | 8 ++++---- crates/bevy_ui/src/ui_node.rs | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/crates/bevy_ui/src/flex/convert.rs b/crates/bevy_ui/src/flex/convert.rs index a125b59e282a2..6502612d54efb 100644 --- a/crates/bevy_ui/src/flex/convert.rs +++ b/crates/bevy_ui/src/flex/convert.rs @@ -155,7 +155,7 @@ pub fn from_style(scale_factor: f64, style: &Style) -> taffy::style::Style { impl From for Option { fn from(value: AlignItems) -> Self { match value { - AlignItems::Normal => None, + AlignItems::Default => None, AlignItems::Start => taffy::style::AlignItems::Start.into(), AlignItems::End => taffy::style::AlignItems::End.into(), AlignItems::FlexStart => taffy::style::AlignItems::FlexStart.into(), @@ -170,7 +170,7 @@ impl From for Option { impl From for Option { fn from(value: JustifyItems) -> Self { match value { - JustifyItems::Normal => None, + JustifyItems::Default => None, JustifyItems::Start => taffy::style::JustifyItems::Start.into(), JustifyItems::End => taffy::style::JustifyItems::End.into(), JustifyItems::FlexStart => taffy::style::JustifyItems::FlexStart.into(), @@ -215,7 +215,7 @@ impl From for Option { impl From for Option { fn from(value: AlignContent) -> Self { match value { - AlignContent::Normal => None, + AlignContent::Default => None, AlignContent::Start => taffy::style::AlignContent::Start.into(), AlignContent::End => taffy::style::AlignContent::End.into(), AlignContent::FlexStart => taffy::style::AlignContent::FlexStart.into(), @@ -232,7 +232,7 @@ impl From for Option { impl From for Option { fn from(value: JustifyContent) -> Self { match value { - JustifyContent::Normal => None, + JustifyContent::Default => None, JustifyContent::Start => taffy::style::JustifyContent::Start.into(), JustifyContent::End => taffy::style::JustifyContent::End.into(), JustifyContent::FlexStart => taffy::style::JustifyContent::FlexStart.into(), diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index ec91087810658..24f275f3f01a8 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -401,7 +401,7 @@ impl Default for Style { #[reflect(PartialEq, Serialize, Deserialize)] pub enum AlignItems { /// The items are packed in their default position as if no alignment was applied - Normal, + Default, /// Items are packed towards the start of the axis. Start, /// Items are packed towards the end of the axis. @@ -421,7 +421,7 @@ pub enum AlignItems { } impl AlignItems { - pub const DEFAULT: Self = Self::Normal; + pub const DEFAULT: Self = Self::Default; } impl Default for AlignItems { @@ -435,7 +435,7 @@ impl Default for AlignItems { #[reflect(PartialEq, Serialize, Deserialize)] pub enum JustifyItems { /// The items are packed in their default position as if no alignment was applied - Normal, + Default, /// Items are packed towards the start of the axis. Start, /// Items are packed towards the end of the axis. @@ -455,7 +455,7 @@ pub enum JustifyItems { } impl JustifyItems { - pub const DEFAULT: Self = Self::Normal; + pub const DEFAULT: Self = Self::Default; } impl Default for JustifyItems { @@ -541,7 +541,7 @@ impl Default for JustifySelf { #[reflect(PartialEq, Serialize, Deserialize)] pub enum AlignContent { /// The items are packed in their default position as if no alignment was applied - Normal, + Default, /// Each line moves towards the start of the cross axis. Start, /// Each line moves towards the end of the cross axis. @@ -566,7 +566,7 @@ pub enum AlignContent { } impl AlignContent { - pub const DEFAULT: Self = Self::Normal; + pub const DEFAULT: Self = Self::Default; } impl Default for AlignContent { @@ -580,7 +580,7 @@ impl Default for AlignContent { #[reflect(PartialEq, Serialize, Deserialize)] pub enum JustifyContent { /// The items are packed in their default position as if no alignment was applied - Normal, + Default, /// Items are packed toward the start of the axis. Start, /// Items are packed toward the end of the axis. @@ -600,7 +600,7 @@ pub enum JustifyContent { } impl JustifyContent { - pub const DEFAULT: Self = Self::Normal; + pub const DEFAULT: Self = Self::Default; } impl Default for JustifyContent { From e189f12f64a154e3c426e1f1d2c8eb0add58817f Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Sat, 11 Mar 2023 19:16:09 +0000 Subject: [PATCH 22/65] Ensure that grid style values are scaled when converting to taffy styles --- crates/bevy_ui/src/flex/convert.rs | 189 ++++++++++++++--------------- 1 file changed, 89 insertions(+), 100 deletions(-) diff --git a/crates/bevy_ui/src/flex/convert.rs b/crates/bevy_ui/src/flex/convert.rs index 6502612d54efb..62870436e2fdd 100644 --- a/crates/bevy_ui/src/flex/convert.rs +++ b/crates/bevy_ui/src/flex/convert.rs @@ -1,4 +1,3 @@ -use taffy::style::LengthPercentageAuto; use taffy::style_helpers; use crate::{ @@ -16,85 +15,56 @@ impl Val { Val::Undefined => Val::Undefined, } } - - fn to_inset(self) -> LengthPercentageAuto { - match self { - Val::Auto | Val::Undefined => taffy::style::LengthPercentageAuto::Auto, - Val::Percent(value) => taffy::style::LengthPercentageAuto::Percent(value / 100.0), - Val::Px(value) => taffy::style::LengthPercentageAuto::Points(value), - } - } -} - -impl UiRect { - fn scaled(self, scale_factor: f64) -> Self { - Self { - left: self.left.scaled(scale_factor), - right: self.right.scaled(scale_factor), - top: self.top.scaled(scale_factor), - bottom: self.bottom.scaled(scale_factor), - } - } -} - -impl Size { - fn scaled(self, scale_factor: f64) -> Self { - Self { - width: self.width.scaled(scale_factor), - height: self.height.scaled(scale_factor), - } - } -} - -impl> From for taffy::prelude::Rect { - fn from(value: UiRect) -> Self { - Self { - left: value.left.into(), - right: value.right.into(), - top: value.top.into(), - bottom: value.bottom.into(), - } - } -} - -impl> From for taffy::prelude::Size { - fn from(value: Size) -> Self { - Self { - width: value.width.into(), - height: value.height.into(), - } - } -} - -impl From for taffy::style::Dimension { - fn from(value: Val) -> Self { - match value { + fn into_dimension(self, scale_factor: f64) -> taffy::style::Dimension { + match self.scaled(scale_factor) { Val::Auto | Val::Undefined => taffy::style::Dimension::Auto, Val::Percent(value) => taffy::style::Dimension::Percent(value / 100.0), Val::Px(value) => taffy::style::Dimension::Points(value), } } -} -impl From for taffy::style::LengthPercentage { - fn from(value: Val) -> Self { - match value { + fn into_length_percentage(self, scale_factor: f64) -> taffy::style::LengthPercentage { + match self.scaled(scale_factor) { Val::Auto | Val::Undefined => taffy::style::LengthPercentage::Points(0.0), Val::Percent(value) => taffy::style::LengthPercentage::Percent(value / 100.0), Val::Px(value) => taffy::style::LengthPercentage::Points(value), } } -} - -impl From for taffy::style::LengthPercentageAuto { - fn from(value: Val) -> Self { - match value { + fn into_length_percentage_auto(self, scale_factor: f64) -> taffy::style::LengthPercentageAuto { + match self.scaled(scale_factor) { Val::Auto => taffy::style::LengthPercentageAuto::Auto, Val::Percent(value) => taffy::style::LengthPercentageAuto::Percent(value / 100.0), Val::Px(value) => taffy::style::LengthPercentageAuto::Points(value), Val::Undefined => taffy::style::LengthPercentageAuto::Points(0.), } } + fn into_inset(self, scale_factor: f64) -> taffy::style::LengthPercentageAuto { + match self.scaled(scale_factor) { + Val::Auto | Val::Undefined => taffy::style::LengthPercentageAuto::Auto, + Val::Percent(value) => taffy::style::LengthPercentageAuto::Percent(value / 100.0), + Val::Px(value) => taffy::style::LengthPercentageAuto::Points(value), + } + } +} + +impl UiRect { + fn map_to_taffy_rect(self, map_fn: impl Fn(Val) -> T) -> taffy::geometry::Rect { + taffy::geometry::Rect { + left: map_fn(self.left), + right: map_fn(self.right), + top: map_fn(self.top), + bottom: map_fn(self.bottom), + } + } +} + +impl Size { + fn map_to_taffy_size(self, map_fn: impl Fn(Val) -> T) -> taffy::geometry::Size { + taffy::geometry::Size { + width: map_fn(self.width), + height: map_fn(self.height), + } + } } pub fn from_style(scale_factor: f64, style: &Style) -> taffy::style::Style { @@ -110,42 +80,56 @@ pub fn from_style(scale_factor: f64, style: &Style) -> taffy::style::Style { align_content: style.align_content.into(), justify_content: style.justify_content.into(), inset: taffy::prelude::Rect { - left: style.position.left.scaled(scale_factor).to_inset(), - right: style.position.right.scaled(scale_factor).to_inset(), - top: style.position.top.scaled(scale_factor).to_inset(), - bottom: style.position.bottom.scaled(scale_factor).to_inset(), + left: style.position.left.into_inset(scale_factor), + right: style.position.right.into_inset(scale_factor), + top: style.position.top.into_inset(scale_factor), + bottom: style.position.bottom.into_inset(scale_factor), }, - margin: style.margin.scaled(scale_factor).into(), - padding: style.padding.scaled(scale_factor).into(), - border: style.border.scaled(scale_factor).into(), + margin: style + .margin + .map_to_taffy_rect(|m| m.into_length_percentage_auto(scale_factor)), + padding: style + .padding + .map_to_taffy_rect(|m| m.into_length_percentage(scale_factor)), + border: style + .border + .map_to_taffy_rect(|m| m.into_length_percentage(scale_factor)), flex_grow: style.flex_grow, flex_shrink: style.flex_shrink, - flex_basis: style.flex_basis.scaled(scale_factor).into(), - size: style.size.scaled(scale_factor).into(), - min_size: style.min_size.scaled(scale_factor).into(), - max_size: style.max_size.scaled(scale_factor).into(), + flex_basis: style.flex_basis.into_dimension(scale_factor), + size: style + .size + .map_to_taffy_size(|s| s.into_dimension(scale_factor)), + min_size: style + .min_size + .map_to_taffy_size(|s| s.into_dimension(scale_factor)), + max_size: style + .max_size + .map_to_taffy_size(|s| s.into_dimension(scale_factor)), aspect_ratio: style.aspect_ratio, - gap: style.gap.scaled(scale_factor).into(), + gap: style + .gap + .map_to_taffy_size(|s| s.into_length_percentage(scale_factor)), grid_auto_flow: style.grid_auto_flow.into(), grid_template_rows: style .grid_template_rows .iter() - .map(|item| (*item).into()) + .map(|track| track.into_track_sizing_function(scale_factor)) .collect::>(), grid_template_columns: style .grid_template_columns .iter() - .map(|item| (*item).into()) + .map(|track| track.into_track_sizing_function(scale_factor)) .collect::>(), grid_auto_rows: style .grid_auto_rows .iter() - .map(|item| (*item).into()) + .map(|track| track.into_non_repeating_track_sizing_function(scale_factor)) .collect::>(), grid_auto_columns: style .grid_auto_columns .iter() - .map(|item| (*item).into()) + .map(|track| track.into_non_repeating_track_sizing_function(scale_factor)) .collect::>(), grid_row: style.grid_row.into(), grid_column: style.grid_column.into(), @@ -307,12 +291,12 @@ impl From for taffy::geometry::Line } } -impl From for taffy::style::MinTrackSizingFunction { - fn from(value: MinTrackSizingFunction) -> Self { - match value { - MinTrackSizingFunction::Fixed(val) => { - taffy::style::MinTrackSizingFunction::Fixed(val.into()) - } +impl MinTrackSizingFunction { + fn into_taffy(self, scale_factor: f64) -> taffy::style::MinTrackSizingFunction { + match self { + MinTrackSizingFunction::Fixed(val) => taffy::style::MinTrackSizingFunction::Fixed( + val.into_length_percentage(scale_factor), + ), MinTrackSizingFunction::Auto => taffy::style::MinTrackSizingFunction::Auto, MinTrackSizingFunction::MinContent => taffy::style::MinTrackSizingFunction::MinContent, MinTrackSizingFunction::MaxContent => taffy::style::MinTrackSizingFunction::MaxContent, @@ -320,17 +304,19 @@ impl From for taffy::style::MinTrackSizingFunction { } } -impl From for taffy::style::MaxTrackSizingFunction { - fn from(value: MaxTrackSizingFunction) -> Self { - match value { - MaxTrackSizingFunction::Fixed(val) => { - taffy::style::MaxTrackSizingFunction::Fixed(val.into()) - } +impl MaxTrackSizingFunction { + fn into_taffy(self, scale_factor: f64) -> taffy::style::MaxTrackSizingFunction { + match self { + MaxTrackSizingFunction::Fixed(val) => taffy::style::MaxTrackSizingFunction::Fixed( + val.into_length_percentage(scale_factor), + ), MaxTrackSizingFunction::Auto => taffy::style::MaxTrackSizingFunction::Auto, MaxTrackSizingFunction::MinContent => taffy::style::MaxTrackSizingFunction::MinContent, MaxTrackSizingFunction::MaxContent => taffy::style::MaxTrackSizingFunction::MaxContent, MaxTrackSizingFunction::FitContent(val) => { - taffy::style::MaxTrackSizingFunction::FitContent(val.into()) + taffy::style::MaxTrackSizingFunction::FitContent( + val.into_length_percentage(scale_factor), + ) } MaxTrackSizingFunction::Fraction(fraction) => { taffy::style::MaxTrackSizingFunction::Fraction(fraction) @@ -339,18 +325,21 @@ impl From for taffy::style::MaxTrackSizingFunction { } } -impl From for taffy::style::NonRepeatedTrackSizingFunction { - fn from(value: GridTrack) -> Self { - let min = value.min_sizing_function.into(); - let max = value.max_sizing_function.into(); +impl GridTrack { + fn into_non_repeating_track_sizing_function( + self, + scale_factor: f64, + ) -> taffy::style::NonRepeatedTrackSizingFunction { + let min = self.min_sizing_function.into_taffy(scale_factor); + let max = self.max_sizing_function.into_taffy(scale_factor); taffy::style_helpers::minmax(min, max) } } -impl From for taffy::style::TrackSizingFunction { - fn from(value: GridTrack) -> Self { - let min = value.min_sizing_function.into(); - let max = value.max_sizing_function.into(); +impl GridTrack { + fn into_track_sizing_function(self, scale_factor: f64) -> taffy::style::TrackSizingFunction { + let min = self.min_sizing_function.into_taffy(scale_factor); + let max = self.max_sizing_function.into_taffy(scale_factor); taffy::style_helpers::minmax(min, max) } } From 0a677746551724ac2ccc69b2333c622ccd1a66de Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Sat, 11 Mar 2023 20:05:54 +0000 Subject: [PATCH 23/65] Add support for repeated track definitions --- crates/bevy_ui/src/flex/convert.rs | 42 +++++++++++------ crates/bevy_ui/src/ui_node.rs | 72 +++++++++++++++++++++++++++--- 2 files changed, 94 insertions(+), 20 deletions(-) diff --git a/crates/bevy_ui/src/flex/convert.rs b/crates/bevy_ui/src/flex/convert.rs index 62870436e2fdd..d696880041d00 100644 --- a/crates/bevy_ui/src/flex/convert.rs +++ b/crates/bevy_ui/src/flex/convert.rs @@ -2,8 +2,9 @@ use taffy::style_helpers; use crate::{ AlignContent, AlignItems, AlignSelf, Display, FlexDirection, FlexWrap, GridAutoFlow, - GridPlacement, GridTrack, JustifyContent, JustifyItems, JustifySelf, MaxTrackSizingFunction, - MinTrackSizingFunction, PositionType, Size, Style, UiRect, Val, + GridPlacement, GridTrack, GridTrackRepetition, JustifyContent, JustifyItems, JustifySelf, + MaxTrackSizingFunction, MinTrackSizingFunction, PositionType, RepeatedGridTrack, Size, Style, + UiRect, Val, }; impl Val { @@ -114,22 +115,22 @@ pub fn from_style(scale_factor: f64, style: &Style) -> taffy::style::Style { grid_template_rows: style .grid_template_rows .iter() - .map(|track| track.into_track_sizing_function(scale_factor)) + .map(|track| track.into_repeated_taffy_track(scale_factor)) .collect::>(), grid_template_columns: style .grid_template_columns .iter() - .map(|track| track.into_track_sizing_function(scale_factor)) + .map(|track| track.into_repeated_taffy_track(scale_factor)) .collect::>(), grid_auto_rows: style .grid_auto_rows .iter() - .map(|track| track.into_non_repeating_track_sizing_function(scale_factor)) + .map(|track| track.into_taffy_track(scale_factor)) .collect::>(), grid_auto_columns: style .grid_auto_columns .iter() - .map(|track| track.into_non_repeating_track_sizing_function(scale_factor)) + .map(|track| track.into_taffy_track(scale_factor)) .collect::>(), grid_row: style.grid_row.into(), grid_column: style.grid_column.into(), @@ -326,20 +327,35 @@ impl MaxTrackSizingFunction { } impl GridTrack { - fn into_non_repeating_track_sizing_function( - self, - scale_factor: f64, - ) -> taffy::style::NonRepeatedTrackSizingFunction { + fn into_taffy_track(self, scale_factor: f64) -> taffy::style::NonRepeatedTrackSizingFunction { let min = self.min_sizing_function.into_taffy(scale_factor); let max = self.max_sizing_function.into_taffy(scale_factor); taffy::style_helpers::minmax(min, max) } } -impl GridTrack { - fn into_track_sizing_function(self, scale_factor: f64) -> taffy::style::TrackSizingFunction { +impl RepeatedGridTrack { + fn into_repeated_taffy_track(self, scale_factor: f64) -> taffy::style::TrackSizingFunction { let min = self.min_sizing_function.into_taffy(scale_factor); let max = self.max_sizing_function.into_taffy(scale_factor); - taffy::style_helpers::minmax(min, max) + let taffy_track: taffy::style::NonRepeatedTrackSizingFunction = + taffy::style_helpers::minmax(min, max); + match self.repetition { + GridTrackRepetition::Count(count) => { + if count == 1 { + taffy::style::TrackSizingFunction::Single(taffy_track) + } else { + taffy::style_helpers::repeat(count, vec![taffy_track]) + } + } + GridTrackRepetition::AutoFit => taffy::style_helpers::repeat( + taffy::style::GridTrackRepetition::AutoFit, + vec![taffy_track], + ), + GridTrackRepetition::AutoFill => taffy::style_helpers::repeat( + taffy::style::GridTrackRepetition::AutoFill, + vec![taffy_track], + ), + } } } diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index 24f275f3f01a8..28d5ac299db70 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -341,9 +341,9 @@ pub struct Style { /// Only affect Grid layouts pub grid_auto_flow: GridAutoFlow, /// Defines the track sizing functions (widths) of the grid rows - pub grid_template_rows: Vec, + pub grid_template_rows: Vec, /// Defines the track sizing functions (heights) of the grid columns - pub grid_template_columns: Vec, + pub grid_template_columns: Vec, /// Defines the size of implicitly created rows pub grid_auto_rows: Vec, /// Defined the size of implicitly created columns @@ -824,45 +824,71 @@ impl GridTrack { }; /// Create a grid track with automatic size - pub fn auto() -> Self { + pub fn auto>() -> T { Self { min_sizing_function: MinTrackSizingFunction::Auto, max_sizing_function: MaxTrackSizingFunction::Auto, } + .into() } /// Create a grid track with a fixed pixel size - pub fn px(value: f32) -> Self { + pub fn px>(value: f32) -> T { Self { min_sizing_function: MinTrackSizingFunction::Fixed(Val::Px(value)), max_sizing_function: MaxTrackSizingFunction::Fixed(Val::Px(value)), } + .into() } /// Create a grid track with a percentage size - pub fn percent(value: f32) -> Self { + pub fn percent>(value: f32) -> T { Self { min_sizing_function: MinTrackSizingFunction::Fixed(Val::Percent(value)), max_sizing_function: MaxTrackSizingFunction::Fixed(Val::Percent(value)), } + .into() } /// Create a grid track with an `fr` size. /// Note that this will give the track a content-based minimum size. /// Usually you are best off using `GridTrack::flex` instead which uses a zero minimum size - pub fn fr(value: f32) -> Self { + pub fn fr>(value: f32) -> T { Self { min_sizing_function: MinTrackSizingFunction::Auto, max_sizing_function: MaxTrackSizingFunction::Fraction(value), } + .into() } /// Create a grid track with an `minmax(0, Nfr)` size. - pub fn flex(value: f32) -> Self { + pub fn flex>(value: f32) -> T { Self { min_sizing_function: MinTrackSizingFunction::Fixed(Val::Px(0.0)), max_sizing_function: MaxTrackSizingFunction::Fraction(value), } + .into() + } + + /// Created a repeated set of grid tracks. + /// + /// The repetition parameter can either be: + /// - a `u16` count to repeat the track N times + /// - A `GridTrackRepetition::AutoFit` or `GridTrackRepetition::AutoFill` + /// + /// You may only use one auto-repetition per track list. And if your track list contains an auto repetition + /// then all track (in and outside of the repetition) must be fixed size (px or percent). + /// + /// Integer repetitions are just shorthand for writing out N tracks longhand and are not subject to the same limitations. + pub fn repeat>( + repetition: Repetition, + track: GridTrack, + ) -> RepeatedGridTrack { + RepeatedGridTrack { + repetition: repetition.into(), + min_sizing_function: track.min_sizing_function, + max_sizing_function: track.max_sizing_function, + } } } @@ -872,6 +898,38 @@ impl Default for GridTrack { } } +#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect, FromReflect)] +#[reflect(PartialEq, Serialize, Deserialize)] +pub enum GridTrackRepetition { + AutoFit, + AutoFill, + Count(u16), +} + +impl From for GridTrackRepetition { + fn from(count: u16) -> Self { + Self::Count(count) + } +} + +#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect, FromReflect)] +#[reflect(PartialEq, Serialize, Deserialize)] +pub struct RepeatedGridTrack { + pub(crate) repetition: GridTrackRepetition, + pub(crate) min_sizing_function: MinTrackSizingFunction, + pub(crate) max_sizing_function: MaxTrackSizingFunction, +} + +impl From for RepeatedGridTrack { + fn from(track: GridTrack) -> Self { + Self { + repetition: GridTrackRepetition::Count(1), + min_sizing_function: track.min_sizing_function, + max_sizing_function: track.max_sizing_function, + } + } +} + #[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)] #[reflect(PartialEq, Serialize, Deserialize)] pub struct GridPlacement { From cfeff47f3adaedc4f7ce90b3acb599b990fa5191 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Sat, 11 Mar 2023 20:08:10 +0000 Subject: [PATCH 24/65] Use method rather than static function for repeating --- crates/bevy_ui/src/ui_node.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index 28d5ac299db70..5dfec45b45984 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -881,13 +881,13 @@ impl GridTrack { /// /// Integer repetitions are just shorthand for writing out N tracks longhand and are not subject to the same limitations. pub fn repeat>( + self, repetition: Repetition, - track: GridTrack, ) -> RepeatedGridTrack { RepeatedGridTrack { repetition: repetition.into(), - min_sizing_function: track.min_sizing_function, - max_sizing_function: track.max_sizing_function, + min_sizing_function: self.min_sizing_function, + max_sizing_function: self.max_sizing_function, } } } From 49d9424ecaebd615f78ebe1dc83d85f71355e886 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Sat, 11 Mar 2023 20:19:42 +0000 Subject: [PATCH 25/65] Add constructors for min-content, max-content, and fit-content grid tracks --- crates/bevy_ui/src/ui_node.rs | 36 +++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index 5dfec45b45984..b6b30c54798db 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -870,6 +870,42 @@ impl GridTrack { .into() } + /// Create a grid track with min-content size + pub fn min_content>() -> T { + Self { + min_sizing_function: MinTrackSizingFunction::MinContent, + max_sizing_function: MaxTrackSizingFunction::MinContent, + } + .into() + } + + /// Create a grid track with max-content size + pub fn max_content>() -> T { + Self { + min_sizing_function: MinTrackSizingFunction::MaxContent, + max_sizing_function: MaxTrackSizingFunction::MaxContent, + } + .into() + } + + /// Create a fit-content() grid track with fixed pixel limit + pub fn fit_content_px>(limit: f32) -> T { + Self { + min_sizing_function: MinTrackSizingFunction::Auto, + max_sizing_function: MaxTrackSizingFunction::FitContent(Val::Px(limit)), + } + .into() + } + + /// Create a fit-content() grid track with percentage limit + pub fn fit_content_percent>(limit: f32) -> T { + Self { + min_sizing_function: MinTrackSizingFunction::Auto, + max_sizing_function: MaxTrackSizingFunction::FitContent(Val::Percent(limit)), + } + .into() + } + /// Created a repeated set of grid tracks. /// /// The repetition parameter can either be: From 40eee01334ab92e5ac6ce4e53916c9880aebee6b Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Sat, 11 Mar 2023 20:31:32 +0000 Subject: [PATCH 26/65] Add constructor for minmax() grid tracks --- crates/bevy_ui/src/ui_node.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index b6b30c54798db..e002b4d976b82 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -780,7 +780,7 @@ impl Default for GridAutoFlow { #[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect, FromReflect)] #[reflect_value(PartialEq, Serialize, Deserialize)] -pub(crate) enum MinTrackSizingFunction { +pub enum MinTrackSizingFunction { /// Track minimum size should be a fixed points or percentage value Fixed(Val), /// Track minimum size should be content sized under a min-content constraint @@ -793,7 +793,7 @@ pub(crate) enum MinTrackSizingFunction { #[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect, FromReflect)] #[reflect_value(PartialEq, Serialize, Deserialize)] -pub(crate) enum MaxTrackSizingFunction { +pub enum MaxTrackSizingFunction { /// Track maximum size should be a fixed points or percentage value Fixed(Val), /// Track maximum size should be content sized under a min-content constraint @@ -906,6 +906,15 @@ impl GridTrack { .into() } + /// Create a minmax() grid track + pub fn minmax>(min: MinTrackSizingFunction, max: MaxTrackSizingFunction) -> T { + Self { + min_sizing_function: min, + max_sizing_function: max, + } + .into() + } + /// Created a repeated set of grid tracks. /// /// The repetition parameter can either be: From 726329d72eef2db592fbc6f006fee2dee77253b2 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Mon, 13 Mar 2023 19:46:43 +0000 Subject: [PATCH 27/65] Fix convert test --- crates/bevy_ui/src/flex/convert.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/bevy_ui/src/flex/convert.rs b/crates/bevy_ui/src/flex/convert.rs index 78c2d52374f25..2f0934bb33a47 100644 --- a/crates/bevy_ui/src/flex/convert.rs +++ b/crates/bevy_ui/src/flex/convert.rs @@ -568,7 +568,7 @@ mod tests { ); assert_eq!( taffy_style.grid_template_rows, - vec![sh::points(10.0), sh::percent(50.0), sh::fr(1.0)] + vec![sh::points(10.0), sh::percent(0.5), sh::fr(1.0)] ); assert_eq!( taffy_style.grid_template_columns, @@ -578,7 +578,7 @@ mod tests { taffy_style.grid_auto_rows, vec![ sh::fit_content(taffy::style::LengthPercentage::Points(10.0)), - sh::fit_content(taffy::style::LengthPercentage::Percent(50.0)), + sh::fit_content(taffy::style::LengthPercentage::Percent(0.25)), sh::minmax(sh::points(0.0), sh::fr(2.0)), ] ); @@ -586,7 +586,7 @@ mod tests { taffy_style.grid_auto_columns, vec![sh::auto(), sh::min_content(), sh::max_content()] ); - assert_eq!(taffy_style.grid_column, sh::line(4)); - assert_eq!(taffy_style.grid_row, sh::span(3)); + assert_eq!(taffy_style.grid_column, taffy::geometry::Line { start: sh::line(4), end: sh::span(1) }); + assert_eq!(taffy_style.grid_row, taffy::geometry::Line { start: sh::auto(), end: sh::span(3) }); } } From 9beb56307d3006e4bcad59694b3417e118e93a22 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Mon, 13 Mar 2023 20:01:57 +0000 Subject: [PATCH 28/65] Add documentation to grid example --- examples/ui/grid.rs | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/examples/ui/grid.rs b/examples/ui/grid.rs index 0e8b8ecab205d..bff6947117bf8 100644 --- a/examples/ui/grid.rs +++ b/examples/ui/grid.rs @@ -18,24 +18,29 @@ fn main() { .run(); } -fn rect(color: Color) -> NodeBundle { - NodeBundle { - background_color: BackgroundColor(color), - ..default() - } -} - fn spawn_layout(mut commands: Commands, asset_server: Res) { let font = asset_server.load("fonts/FiraSans-Bold.ttf"); commands.spawn(Camera2dBundle::default()); commands .spawn(NodeBundle { style: Style { + /// Use the CSS Grid algorithm for laying out this node display: Display::Grid, + /// Make node fill the entirety it's parent (in this case the window) size: Size::all(Val::Percent(100.)), + /// Set a 20px gap/gutter between both rows and columns + gap: Size::all(Val::Px(20.)), + /// Set the grid to have 3 columns with sizes [minmax(0, 1fr), minmax(0, 2fr), minmax(0, 1fr)] + /// This means that the columns with initially have zero size. They will then expand to take up + /// the remaining available space in proportion to thier "flex fractions" (fr values). + /// + /// The sum of the fr values is 4, so in this case: + /// - The 1st column will take 1/4 of the width + /// - The 2nd column will take up 2/4 = 1/2 of the width + /// - The 3rd column will be 1/4 of the width grid_template_columns: vec![GridTrack::flex(1.), GridTrack::flex(2.), GridTrack::flex(1.)], + /// Set the grid to have 3 rows with sizes [auto, 150px, minmax(0, 1fr)] grid_template_rows: vec![GridTrack::auto(), GridTrack::px(150.), GridTrack::flex(1.)], - gap: Size::all(Val::Px(20.)), ..default() }, background_color: BackgroundColor(Color::WHITE), @@ -91,13 +96,7 @@ fn spawn_layout(mut commands: Commands, asset_server: Res) { builder.spawn(rect(Color::BISQUE)); builder.spawn(rect(Color::BLUE)); builder.spawn(rect(Color::CRIMSON)); - - // .with_styled_child(button("Increment").on_press(Message::Increment), |style| { - // style.align_self = Some(AlignSelf::Center); - // style.justify_self = Some(AlignSelf::Center); - // }) builder.spawn(rect(Color::CYAN)); - builder.spawn(rect(Color::ORANGE_RED)); builder.spawn(rect(Color::DARK_GREEN)); builder.spawn(rect(Color::FUCHSIA)); @@ -122,6 +121,16 @@ fn spawn_layout(mut commands: Commands, asset_server: Res) { }); } +/// Create a coloured rectangle node. The node has size as it is assumed that it will be +/// spawned as a child of a Grid container with AlignItems::Stretch and JustifyItems::Stretch +/// which will allow it to take it's size from the size of the grid area it occupies. +fn rect(color: Color) -> NodeBundle { + NodeBundle { + background_color: BackgroundColor(color), + ..default() + } +} + fn spawn_nested_text_bundle( builder: &mut ChildBuilder, font: Handle, From d2016de93b46fa8693d2f1c6f308fa9bff198138 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Mon, 13 Mar 2023 21:18:06 +0000 Subject: [PATCH 29/65] Redo grid example --- examples/ui/grid.rs | 210 +++++++++++++++++++++++++++++--------------- 1 file changed, 137 insertions(+), 73 deletions(-) diff --git a/examples/ui/grid.rs b/examples/ui/grid.rs index bff6947117bf8..c9f933256f9ec 100644 --- a/examples/ui/grid.rs +++ b/examples/ui/grid.rs @@ -21,6 +21,8 @@ fn main() { fn spawn_layout(mut commands: Commands, asset_server: Res) { let font = asset_server.load("fonts/FiraSans-Bold.ttf"); commands.spawn(Camera2dBundle::default()); + + // Top-level grid (app frame) commands .spawn(NodeBundle { style: Style { @@ -29,95 +31,152 @@ fn spawn_layout(mut commands: Commands, asset_server: Res) { /// Make node fill the entirety it's parent (in this case the window) size: Size::all(Val::Percent(100.)), /// Set a 20px gap/gutter between both rows and columns - gap: Size::all(Val::Px(20.)), + // gap: Size::all(Val::Px(20.)), /// Set the grid to have 3 columns with sizes [minmax(0, 1fr), minmax(0, 2fr), minmax(0, 1fr)] - /// This means that the columns with initially have zero size. They will then expand to take up + /// This means that the columns with initially have zero size. They will then expand to take up /// the remaining available space in proportion to thier "flex fractions" (fr values). /// /// The sum of the fr values is 4, so in this case: /// - The 1st column will take 1/4 of the width /// - The 2nd column will take up 2/4 = 1/2 of the width /// - The 3rd column will be 1/4 of the width - grid_template_columns: vec![GridTrack::flex(1.), GridTrack::flex(2.), GridTrack::flex(1.)], + grid_template_columns: vec![GridTrack::min_content(), GridTrack::fr(1.0)], /// Set the grid to have 3 rows with sizes [auto, 150px, minmax(0, 1fr)] - grid_template_rows: vec![GridTrack::auto(), GridTrack::px(150.), GridTrack::flex(1.)], + grid_template_rows: vec![ + GridTrack::auto(), + GridTrack::flex(1.0), + GridTrack::px(20.), + ], ..default() }, background_color: BackgroundColor(Color::WHITE), ..default() }) .with_children(|builder| { - builder.spawn(rect(Color::BLACK)); - builder.spawn(NodeBundle { + // Header + builder + .spawn(NodeBundle { style: Style { display: Display::Grid, + /// Make this node span two grid column so that it takes up the entire top tow + grid_column: GridPlacement::span(2), + padding: UiRect::all(Val::Px(6.0)), ..default() }, ..default() }) .with_children(|builder| { + spawn_nested_text_bundle(builder, font.clone(), "Bevy CSS Grid Layout Example"); + }); - spawn_nested_text_bundle( - builder, - font.clone(), - ALIGN_ITEMS_COLOR, - UiRect::right(MARGIN), - "hello world", - ); + // Main content grid + builder + .spawn(NodeBundle { + style: Style { + display: Display::Grid, + padding: UiRect::all(Val::Px(24.0)), + grid_template_columns: vec![GridTrack::flex::(1.0).repeat(4)], + grid_template_rows: vec![GridTrack::flex::(1.0).repeat(4)], + gap: Size::all(Val::Px(12.0)), + aspect_ratio: Some(1.0), + size: Size::height(Val::Percent(100.0)), + max_size: Size::all(Val::Percent(100.0)), + ..default() + }, + background_color: BackgroundColor(Color::DARK_GRAY), + ..default() + }) + .with_children(|mut builder| { + // Note there is no need to specify the position for each grid item. Grid items that are + // not given an explicit position will be automatically positioned into the next available + // grid cell. The order in which this is performed can be controlled using the grid_auto_flow + // style property. - const REALLY_LONG_PARAGRAPH : &str = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; - spawn_nested_text_bundle( - builder, - font.clone(), - ALIGN_ITEMS_COLOR, - UiRect::right(MARGIN), - REALLY_LONG_PARAGRAPH, - ); - }); + item_rect(&mut builder, Color::ORANGE); + item_rect(&mut builder, Color::BISQUE); + item_rect(&mut builder, Color::BLUE); + item_rect(&mut builder, Color::CRIMSON); - builder.spawn(rect(Color::ALICE_BLUE)); - builder.spawn(rect(Color::ANTIQUE_WHITE)); - builder.spawn(rect(Color::AQUAMARINE)); - builder.spawn(rect(Color::AZURE)); - builder.spawn(rect(Color::DARK_GREEN)); + item_rect(&mut builder, Color::CYAN); + item_rect(&mut builder, Color::ORANGE_RED); + item_rect(&mut builder, Color::DARK_GREEN); + item_rect(&mut builder, Color::FUCHSIA); + item_rect(&mut builder, Color::GOLD); + item_rect(&mut builder, Color::ALICE_BLUE); + item_rect(&mut builder, Color::GOLD); + item_rect(&mut builder, Color::ANTIQUE_WHITE); - builder.spawn(NodeBundle { - style: Style { - display: Display::Grid, - grid_template_columns: vec![GridTrack::flex(1.), GridTrack::flex(2.), GridTrack::flex(1.)], - grid_template_rows: vec![GridTrack::flex(1.), GridTrack::percent(50.), GridTrack::flex(1.)], - ..default() - }, + item_rect(&mut builder, Color::GOLD); + item_rect(&mut builder, Color::GOLD); + item_rect(&mut builder, Color::GOLD); + item_rect(&mut builder, Color::GOLD); + }); + + // Right side bar + // builder.spawn(rect(Color::BLACK)); + builder + .spawn(NodeBundle { + style: Style { + display: Display::Grid, + align_items: AlignItems::Start, + justify_items: JustifyItems::Center, + padding: UiRect::top(Val::Px(20.)), ..default() - }) + }, + background_color: BackgroundColor(Color::BLACK), + ..default() + }) .with_children(|builder| { - builder.spawn(rect(Color::ORANGE)); - builder.spawn(rect(Color::BISQUE)); - builder.spawn(rect(Color::BLUE)); - builder.spawn(rect(Color::CRIMSON)); - builder.spawn(rect(Color::CYAN)); - builder.spawn(rect(Color::ORANGE_RED)); - builder.spawn(rect(Color::DARK_GREEN)); - builder.spawn(rect(Color::FUCHSIA)); - builder.spawn(rect(Color::GOLD)); - - builder.spawn(NodeBundle { - style: Style { - position_type: PositionType::Absolute, - top: Val::Px(10.), - left: Val::Px(10.), - size: Size::all(Val::Px(40.)), - grid_row: GridPlacement::start(1), - grid_column: GridPlacement::start(1), - ..default() + builder.spawn(TextBundle::from_section( + "Sidebar", + TextStyle { + font, + font_size: 24.0, + color: Color::WHITE, }, - background_color: BackgroundColor(Color::BLACK), - ..default() - }); + )); }); - builder.spawn(rect(Color::GREEN)); + // Footer / status bar + builder.spawn(NodeBundle { + style: Style { + /// Make this node span two grid column so that it takes up the entire top tow + grid_column: GridPlacement::span(2), + ..default() + }, + background_color: BackgroundColor(Color::WHITE), + ..default() + }); + + // Modal (uncomment to view) + // builder.spawn(NodeBundle { + // style: Style { + // position_type: PositionType::Absolute, + // margin: UiRect { + // top: Val::Px(100.), + // bottom: Val::Auto, + // left: Val::Auto, + // right: Val::Auto, + // }, + // size: Size { + // width: Val::Percent(60.), + // height: Val::Px(300.), + // }, + // max_size: Size { + // width: Val::Px(600.), + // height: Val::Auto, + // }, + // ..default() + // }, + // background_color: BackgroundColor(Color::Rgba { + // red: 255.0, + // green: 255.0, + // blue: 255.0, + // alpha: 0.8, + // }), + // ..default() + // }); }); } @@ -131,27 +190,32 @@ fn rect(color: Color) -> NodeBundle { } } -fn spawn_nested_text_bundle( - builder: &mut ChildBuilder, - font: Handle, - background_color: Color, - margin: UiRect, - text: &str, -) { +fn item_rect(builder: &mut ChildBuilder, color: Color) { + builder + .spawn(NodeBundle { + style: Style { + display: Display::Grid, + padding: UiRect::all(Val::Px(3.0)), + ..default() + }, + background_color: BackgroundColor(Color::BLACK), + ..default() + }) + .with_children(|builder| { + builder.spawn(NodeBundle { + background_color: BackgroundColor(color), + ..default() + }); + }); +} + +fn spawn_nested_text_bundle(builder: &mut ChildBuilder, font: Handle, text: &str) { builder .spawn(NodeBundle { style: Style { - margin, - padding: UiRect { - top: Val::Px(1.), - left: Val::Px(5.), - right: Val::Px(5.), - bottom: Val::Px(1.), - }, min_size: Size::width(Val::Px(0.)), ..default() }, - background_color: BackgroundColor(background_color), ..default() }) .with_children(|builder| { From faee682d3df5892038d23b8098ba19c2197f8fd2 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Mon, 13 Mar 2023 21:24:57 +0000 Subject: [PATCH 30/65] Clean up example --- examples/ui/grid.rs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/examples/ui/grid.rs b/examples/ui/grid.rs index c9f933256f9ec..f2c3975f17d06 100644 --- a/examples/ui/grid.rs +++ b/examples/ui/grid.rs @@ -1,9 +1,6 @@ //! Demonstrates how CSS Grid layout can be used to lay items out in a 2D grid use bevy::prelude::*; -const ALIGN_ITEMS_COLOR: Color = Color::rgb(1., 0.066, 0.349); -const MARGIN: Val = Val::Px(5.); - fn main() { App::new() .add_plugins(DefaultPlugins.set(WindowPlugin { @@ -80,7 +77,6 @@ fn spawn_layout(mut commands: Commands, asset_server: Res) { gap: Size::all(Val::Px(12.0)), aspect_ratio: Some(1.0), size: Size::height(Val::Percent(100.0)), - max_size: Size::all(Val::Percent(100.0)), ..default() }, background_color: BackgroundColor(Color::DARK_GRAY), @@ -183,13 +179,6 @@ fn spawn_layout(mut commands: Commands, asset_server: Res) { /// Create a coloured rectangle node. The node has size as it is assumed that it will be /// spawned as a child of a Grid container with AlignItems::Stretch and JustifyItems::Stretch /// which will allow it to take it's size from the size of the grid area it occupies. -fn rect(color: Color) -> NodeBundle { - NodeBundle { - background_color: BackgroundColor(color), - ..default() - } -} - fn item_rect(builder: &mut ChildBuilder, color: Color) { builder .spawn(NodeBundle { From e183cafcb7e7d78213d310e0c71eeb50e052ab63 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Mon, 13 Mar 2023 21:33:35 +0000 Subject: [PATCH 31/65] Document grid example --- examples/ui/grid.rs | 46 ++++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/examples/ui/grid.rs b/examples/ui/grid.rs index f2c3975f17d06..72ad2366f7f4f 100644 --- a/examples/ui/grid.rs +++ b/examples/ui/grid.rs @@ -27,18 +27,14 @@ fn spawn_layout(mut commands: Commands, asset_server: Res) { display: Display::Grid, /// Make node fill the entirety it's parent (in this case the window) size: Size::all(Val::Percent(100.)), - /// Set a 20px gap/gutter between both rows and columns - // gap: Size::all(Val::Px(20.)), - /// Set the grid to have 3 columns with sizes [minmax(0, 1fr), minmax(0, 2fr), minmax(0, 1fr)] - /// This means that the columns with initially have zero size. They will then expand to take up - /// the remaining available space in proportion to thier "flex fractions" (fr values). - /// - /// The sum of the fr values is 4, so in this case: - /// - The 1st column will take 1/4 of the width - /// - The 2nd column will take up 2/4 = 1/2 of the width - /// - The 3rd column will be 1/4 of the width - grid_template_columns: vec![GridTrack::min_content(), GridTrack::fr(1.0)], - /// Set the grid to have 3 rows with sizes [auto, 150px, minmax(0, 1fr)] + /// Set the grid to have 2 columns with sizes [min-content, minmax(0, 1fr)] + /// - The first column will size to the size of it's contents + /// - The second column will take up the remaining available space + grid_template_columns: vec![GridTrack::min_content(), GridTrack::flex(1.0)], + /// Set the grid to have 3 rows with sizes [auto, minmax(0, 1fr), 20px] + /// - The first row will size to the size of it's contents + /// - The second row take up remaining available space (after rows 1 and 3 have both been sized) + /// - The third row will be exactly 20px high grid_template_rows: vec![ GridTrack::auto(), GridTrack::flex(1.0), @@ -66,17 +62,27 @@ fn spawn_layout(mut commands: Commands, asset_server: Res) { spawn_nested_text_bundle(builder, font.clone(), "Bevy CSS Grid Layout Example"); }); - // Main content grid + // Main content grid (auto placed in row 2, column 1) builder .spawn(NodeBundle { style: Style { + /// Make the height of the node + size: Size::height(Val::Percent(100.0)), + /// Make the grid have a 1:1 aspect ratio meaning it will scale as an exact square + /// As the height is set explicitly, this means the width will adjust to match the height + aspect_ratio: Some(1.0), + /// Use grid layout for this node display: Display::Grid, + // Add 24px of padding around the grid padding: UiRect::all(Val::Px(24.0)), + /// Set the grid to have 4 columns all with sizes minmax(0, 1fr) + /// This creates 4 exactly evenly sized columns grid_template_columns: vec![GridTrack::flex::(1.0).repeat(4)], + /// Set the grid to have 4 rows all with sizes minmax(0, 1fr) + /// This creates 4 exactly evenly sized rows grid_template_rows: vec![GridTrack::flex::(1.0).repeat(4)], + /// Set a 12px gap/gutter between rows and columns gap: Size::all(Val::Px(12.0)), - aspect_ratio: Some(1.0), - size: Size::height(Val::Percent(100.0)), ..default() }, background_color: BackgroundColor(Color::DARK_GRAY), @@ -109,14 +115,16 @@ fn spawn_layout(mut commands: Commands, asset_server: Res) { item_rect(&mut builder, Color::GOLD); }); - // Right side bar - // builder.spawn(rect(Color::BLACK)); + // Right side bar (auto placed in row 2, column 2) builder .spawn(NodeBundle { style: Style { display: Display::Grid, + // Align content towards the start (top) in the vertical axis align_items: AlignItems::Start, + // Align content towards the center in the horizontal axis justify_items: JustifyItems::Center, + // Add 20px padding to the top padding: UiRect::top(Val::Px(20.)), ..default() }, @@ -137,7 +145,7 @@ fn spawn_layout(mut commands: Commands, asset_server: Res) { // Footer / status bar builder.spawn(NodeBundle { style: Style { - /// Make this node span two grid column so that it takes up the entire top tow + /// Make this node span two grid column so that it takes up the entire bottom row grid_column: GridPlacement::span(2), ..default() }, @@ -145,7 +153,7 @@ fn spawn_layout(mut commands: Commands, asset_server: Res) { ..default() }); - // Modal (uncomment to view) + // Modal (absolutely positioned on top of content - uncomment to view) // builder.spawn(NodeBundle { // style: Style { // position_type: PositionType::Absolute, From d38dd224781f0345f5c824ce86437270ad283468 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Mon, 13 Mar 2023 21:37:00 +0000 Subject: [PATCH 32/65] cargo fmt --- crates/bevy_ui/src/flex/convert.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ui/src/flex/convert.rs b/crates/bevy_ui/src/flex/convert.rs index 2f0934bb33a47..768a12d423340 100644 --- a/crates/bevy_ui/src/flex/convert.rs +++ b/crates/bevy_ui/src/flex/convert.rs @@ -586,7 +586,19 @@ mod tests { taffy_style.grid_auto_columns, vec![sh::auto(), sh::min_content(), sh::max_content()] ); - assert_eq!(taffy_style.grid_column, taffy::geometry::Line { start: sh::line(4), end: sh::span(1) }); - assert_eq!(taffy_style.grid_row, taffy::geometry::Line { start: sh::auto(), end: sh::span(3) }); + assert_eq!( + taffy_style.grid_column, + taffy::geometry::Line { + start: sh::line(4), + end: sh::span(1) + } + ); + assert_eq!( + taffy_style.grid_row, + taffy::geometry::Line { + start: sh::auto(), + end: sh::span(3) + } + ); } } From 863391896f608ee70d6a199e37ecb3192b52a615 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Mon, 13 Mar 2023 22:09:16 +0000 Subject: [PATCH 33/65] Simplify text spawning --- examples/ui/grid.rs | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/examples/ui/grid.rs b/examples/ui/grid.rs index 72ad2366f7f4f..87d80d479578c 100644 --- a/examples/ui/grid.rs +++ b/examples/ui/grid.rs @@ -207,22 +207,12 @@ fn item_rect(builder: &mut ChildBuilder, color: Color) { } fn spawn_nested_text_bundle(builder: &mut ChildBuilder, font: Handle, text: &str) { - builder - .spawn(NodeBundle { - style: Style { - min_size: Size::width(Val::Px(0.)), - ..default() - }, - ..default() - }) - .with_children(|builder| { - builder.spawn(TextBundle::from_section( - text, - TextStyle { - font, - font_size: 24.0, - color: Color::BLACK, - }, - )); - }); + builder.spawn(TextBundle::from_section( + text, + TextStyle { + font, + font_size: 24.0, + color: Color::BLACK, + }, + )); } From b73c6c055df838b5b68cce7c2e06229952d7a9ff Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Mon, 13 Mar 2023 22:33:55 +0000 Subject: [PATCH 34/65] Remove FlexStart and FlexEnd variants from JustifyItems/JustifySelf as they are not useful --- crates/bevy_ui/src/flex/convert.rs | 4 ---- crates/bevy_ui/src/ui_node.rs | 12 ------------ 2 files changed, 16 deletions(-) diff --git a/crates/bevy_ui/src/flex/convert.rs b/crates/bevy_ui/src/flex/convert.rs index 768a12d423340..9cf1784d552a3 100644 --- a/crates/bevy_ui/src/flex/convert.rs +++ b/crates/bevy_ui/src/flex/convert.rs @@ -148,8 +148,6 @@ impl From for Option { JustifyItems::Default => None, JustifyItems::Start => taffy::style::JustifyItems::Start.into(), JustifyItems::End => taffy::style::JustifyItems::End.into(), - JustifyItems::FlexStart => taffy::style::JustifyItems::FlexStart.into(), - JustifyItems::FlexEnd => taffy::style::JustifyItems::FlexEnd.into(), JustifyItems::Center => taffy::style::JustifyItems::Center.into(), JustifyItems::Baseline => taffy::style::JustifyItems::Baseline.into(), JustifyItems::Stretch => taffy::style::JustifyItems::Stretch.into(), @@ -178,8 +176,6 @@ impl From for Option { JustifySelf::Auto => None, JustifySelf::Start => taffy::style::JustifySelf::Start.into(), JustifySelf::End => taffy::style::JustifySelf::End.into(), - JustifySelf::FlexStart => taffy::style::JustifySelf::FlexStart.into(), - JustifySelf::FlexEnd => taffy::style::JustifySelf::FlexEnd.into(), JustifySelf::Center => taffy::style::JustifySelf::Center.into(), JustifySelf::Baseline => taffy::style::JustifySelf::Baseline.into(), JustifySelf::Stretch => taffy::style::JustifySelf::Stretch.into(), diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index d1487d33be962..be535265ab898 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -441,12 +441,6 @@ pub enum JustifyItems { Start, /// Items are packed towards the end of the axis. End, - /// Items are packed towards the start of the axis, unless the flex direction is reversed; - /// then they are packed towards the end of the axis. - FlexStart, - /// Items are packed towards the end of the axis, unless the flex direction is reversed; - /// then they are packed towards the start of the axis. - FlexEnd, /// Items are aligned at the center. Center, /// Items are aligned at the baseline. @@ -511,12 +505,6 @@ pub enum JustifySelf { Start, /// This item will be aligned with the end of the axis. End, - /// This item will be aligned with the start of the axis, unless the flex direction is reversed; - /// then it will be aligned with the end of the axis. - FlexStart, - /// This item will be aligned with the end of the axis, unless the flex direction is reversed; - /// then it will be aligned with the start of the axis. - FlexEnd, /// This item will be aligned at the center. Center, /// This item will be aligned at the baseline. From e209d599a677c43db259d2240642e07d1d26d554 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Mon, 13 Mar 2023 23:40:24 +0000 Subject: [PATCH 35/65] Improve documentation of Style struct --- crates/bevy_ui/src/ui_node.rs | 331 ++++++++++++++++++++++++++++------ 1 file changed, 278 insertions(+), 53 deletions(-) diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index be535265ab898..0d9656a78e128 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -220,43 +220,202 @@ impl Val { } } -/// Describes the style of a UI node +/// Describes the style of a UI container node /// -/// It uses the [Flexbox](https://cssreference.io/flexbox/) system. +/// Node's can be laid out using either Flexbox or CSS Grid Layout.
+/// See below for general learning resources and for documentation on the individual style properties. +/// +/// ### Flexbox +/// +/// - [Flexbox Froggy](https://flexboxfroggy.com/). An interactive tutorial/game that teaches the essential parts of Flebox in a fun engaging way. +/// - [A Complete Guide To Flexbox](https://css-tricks.com/snippets/css/a-guide-to-flexbox/) by CSS Tricks. This is detailed guide with illustrations and comphrehensive written explanation of the different Flexbox properties and how they work. +/// +/// ### CSS Grid +/// +/// - [CSS Grid Garden](https://cssgridgarden.com/). An interactive tutorial/game that teaches the essential parts of CSS Grid in a fun engaging way. +/// - [A Complete Guide To CSS Grid](https://css-tricks.com/snippets/css/complete-guide-grid/) by CSS Tricks. This is detailed guide with illustrations and comphrehensive written explanation of the different CSS Grid properties and how they work. + #[derive(Component, Clone, PartialEq, Debug, Reflect)] #[reflect(Component, Default, PartialEq)] pub struct Style { - /// Whether to arrange this node and its children with flexbox layout + /// Which layout algorithm to use when laying out this node's contents: + /// - [`Display::Flex`]: Use the Flexbox layout algorithm + /// - [`Display::Grid`]: Use the CSS Grid layout algorithm + /// - [`Display::None`]: Hide this node and perform layout as if it does not exist. /// - /// If this is set to [`Display::None`], this node will be collapsed. + /// + /// + ///   pub display: Display, - /// Whether to arrange this node relative to other nodes, or positioned absolutely + + /// Whether a node should be laid out in-flow with, or independently of it's siblings: + /// - [`PositionType::Relative`]: Layout this node in-flow with other nodes using the usual (flexbox/grid) layout algorithm. + /// - [`PositionType::Absolute`]: Layout this node on top and independently of other nodes. + /// + /// + /// + ///   pub position_type: PositionType, + + /// Whether overflowing content should be displayed or clipped. + /// + /// + /// + ///   + pub overflow: Overflow, + + /// Defines the text direction. For example English is written LTR (left-to-right) while Arabic is written RTL (right-to-left). + /// + /// Note: the corresponding CSS property also affects box layout order, but this isn't yet implemented in bevy. + /// + /// + ///   + pub direction: Direction, + + /// The horizontal position of the left edge of the node. + /// - For relatively positioned nodes, this is relative to the node's position as computed during regular layout. + /// - For absolutely positioned nodes, this is relative to the *parent* node's bounding box. + /// + /// + /// + ///   pub left: Val, + + /// The horizontal position of the right edge of the node. + /// - For relatively positioned nodes, this is relative to the node's position as computed during regular layout. + /// - For absolutely positioned nodes, this is relative to the *parent* node's bounding box. + /// + /// + /// + ///   pub right: Val, + + /// The vertical position of the top edge of the node. + /// - For relatively positioned nodes, this is relative to the node's position as computed during regular layout. + /// - For absolutely positioned nodes, this is relative to the *parent* node's bounding box. + /// + /// + /// + ///   pub top: Val, + + /// The vertical position of the bottom edge of the node. + /// - For relatively positioned nodes, this is relative to the node's position as computed during regular layout. + /// - For absolutely positioned nodes, this is relative to the *parent* node's bounding box. + /// + /// + /// + ///   pub bottom: Val, - /// Which direction the content of this node should go - pub direction: Direction, - /// Whether to use column or row layout - pub flex_direction: FlexDirection, - /// How to wrap nodes - pub flex_wrap: FlexWrap, - /// How items are aligned according to the cross axis + + /// The ideal size of the node + /// + /// `size.width` is used when it is within the bounds defined by `min_size.width` and `max_size.width`. + /// `size.height` is used when it is within the bounds defined by `min_size.height` and `max_size.height`. + /// + ///
+ /// + /// + ///   + pub size: Size, + + /// The minimum size of the node + /// + /// `min_size.width` is used if it is greater than either `size.width` or `max_size.width`, or both. + /// `min_size.height` is used if it is greater than either `size.height` or `max_size.height`, or both. + /// + ///
+ /// + /// + ///   + pub min_size: Size, + + /// The maximum size of the node + /// + /// `max_size.width` is used if it is within the bounds defined by `min_size.width` and `size.width`. + /// `max_size.height` is used if it is within the bounds defined by `min_size.height` and `size.height. + /// + ///
+ /// + /// + ///   + pub max_size: Size, + + /// The aspect ratio of the node (defined as `width / height`) + /// + /// + /// + ///   + pub aspect_ratio: Option, + + /// For Flexbox containers: + /// - Sets default cross-axis alignment of the child items. + /// For CSS Grid containers: + /// - Controls block (vertical) axis alignment of children of this grid container within their grid areas + /// + /// This value is overriden [`JustifySelf`] on the child node is set. + /// + /// + /// + ///   pub align_items: AlignItems, - /// How items are aligned according to the inline axis + + /// For Flexbox containers: + /// - This property has no effect. See `justify_content` for main-axis alignment of flex items. + /// For CSS Grid containers: + /// - Sets default inline (horizontal) axis alignment of child items within their grid areas + /// + /// This value is overriden [`JustifySelf`] on the child node is set. + /// + /// + /// + ///   pub justify_items: JustifyItems, - /// How this item is aligned according to the cross axis. - /// Overrides [`AlignItems`]. + + /// For Flexbox items: + /// - Controls cross-axis alignment of the item. + /// For CSS Grid items: + /// - Controls block (vertical) axis alignment of a grid item within it's grid area + /// + /// If set to `Auto`, alignment is inherited from the value of [`AlignItems`] set on the parent node. + /// + /// + /// + ///   pub align_self: AlignSelf, - /// How this item is aligned according to the inline axis. - /// Overrides [`JustifyItems`]. + + /// For Flexbox items: + /// - This property has no effect. See `justify_content` for main-axis alignment of flex items. + /// For CSS Grid items: + /// - Controls inline (horizontal) axis alignment of a grid item within it's grid area. + /// + /// If set to `Auto`, alignment is inherited from the value of [`JustifyItems`] set on the parent node. + /// + /// + /// + ///   pub justify_self: JustifySelf, - /// How to align each line, only applies if flex_wrap is set to - /// [`FlexWrap::Wrap`] and there are multiple lines of items + + /// For Flexbox containers: + /// - Controls alignment of lines if flex_wrap is set to [`FlexWrap::Wrap`] and there are multiple lines of items + /// For CSS Grid container: + /// - Controls alignment of grid rows + /// + /// + /// + ///   pub align_content: AlignContent, - /// How items align according to the main axis + + /// For Flexbox containers: + /// - Controls alignment of items in the main axis + /// For CSS Grid containers: + /// - Controls alignment of grid columns + /// + /// + /// + ///   pub justify_content: JustifyContent, + /// The amount of space around a node outside its border. /// /// If a percentage value is used, the percentage is calculated based on the width of the parent node. @@ -274,8 +433,13 @@ pub struct Style { /// ..Default::default() /// }; /// ``` - /// A node with this style and a parent with dimensions of 100px by 300px, will have calculated margins of 10px on both left and right edges, and 15px on both top and bottom egdes. + /// A node with this style and a parent with dimensions of 100px by 300px, will have calculated margins of 10px on both left and right edges, and 15px on both top and bottom edges. + /// + /// + /// + ///   pub margin: UiRect, + /// The amount of space between the edges of a node and its contents. /// /// If a percentage value is used, the percentage is calculated based on the width of the parent node. @@ -294,7 +458,12 @@ pub struct Style { /// }; /// ``` /// A node with this style and a parent with dimensions of 300px by 100px, will have calculated padding of 3px on the left, 6px on the right, 9px on the top and 12px on the bottom. + /// + /// + /// + ///   pub padding: UiRect, + /// The amount of space between the margins of a node and its padding. /// /// If a percentage value is used, the percentage is calculated based on the width of the parent node. @@ -302,54 +471,110 @@ pub struct Style { /// The size of the node will be expanded if there are constraints that prevent the layout algorithm from placing the border within the existing node boundary. /// /// Rendering for borders is not yet implemented. + /// + /// + /// + ///   pub border: UiRect, - /// Defines how much a flexbox item should grow if there's space available + + /// Whether a Flexbox container should be a row or a column. This property has no effect of Grid nodes. + /// + /// + /// + ///   + pub flex_direction: FlexDirection, + + /// Whether a Flexbox container should wrap it's contents onto multiple line wrap if they overflow. This property has no effect of Grid nodes. + /// + /// + /// + ///   + pub flex_wrap: FlexWrap, + + /// Defines how much a flexbox item should grow if there's space available. Defaults to 0 (don't grow at all). + /// + /// + /// + ///   pub flex_grow: f32, - /// How to shrink if there's not enough space available + + /// Defines how much a flexbox item should shrink if there's not enough space available. Defaults to 1. + /// + /// + /// + ///   pub flex_shrink: f32, - /// The initial length of the main axis, before other properties are applied. + + /// The initial length of a flexbox in the main axis, before flex growing/shrinking properties are applied. /// - /// If both are set, `flex_basis` overrides `size` on the main axis but it obeys the bounds defined by `min_size` and `max_size`. - pub flex_basis: Val, - /// The ideal size of the flexbox + /// `flex_basis` overrides `size` on the main axis if both are set, but it obeys the bounds defined by `min_size` and `max_size`. /// - /// `size.width` is used when it is within the bounds defined by `min_size.width` and `max_size.width`. - /// `size.height` is used when it is within the bounds defined by `min_size.height` and `max_size.height`. - pub size: Size, - /// The minimum size of the flexbox + /// /// - /// `min_size.width` is used if it is greater than either `size.width` or `max_size.width`, or both. - /// `min_size.height` is used if it is greater than either `size.height` or `max_size.height`, or both. - pub min_size: Size, - /// The maximum size of the flexbox + ///   + pub flex_basis: Val, + + /// The size of the gutters between items in flexbox layout or rows/columns in a grid layout /// - /// `max_size.width` is used if it is within the bounds defined by `min_size.width` and `size.width`. - /// `max_size.height` is used if it is within the bounds defined by `min_size.height` and `size.height. - pub max_size: Size, - /// The aspect ratio of the flexbox - pub aspect_ratio: Option, - /// How to handle overflow - pub overflow: Overflow, - /// The size of the gutters between the rows and columns of the flexbox layout + /// Note: Values of `Val::Auto` are not valid and are treated as zero. /// - /// A value of `Size::AUTO` is treated as zero. - pub gap: Size, - /// Controls whether grid items are placed row-wise or column-wise. And whether the sparse or dense packing algorithm is used. + /// /// + ///   + pub gap: Size, + + /// Controls whether automatically placed grid items are placed row-wise or column-wise. And whether the sparse or dense packing algorithm is used. /// Only affect Grid layouts + /// + /// + /// + ///   pub grid_auto_flow: GridAutoFlow, - /// Defines the track sizing functions (widths) of the grid rows + + /// Defines the number of rows a grid has and the sizes of those rows. If grid items are given explicit placements then more rows may + /// be implicitly generated by items that are placed out of bounds. The sizes of those rows are controlled by `grid_auto_rows` property. + /// + /// + /// + ///   pub grid_template_rows: Vec, - /// Defines the track sizing functions (heights) of the grid columns + + /// Defines the number of columns a grid has and the sizes of those columns. If grid items are given explicit placements then more columns may + /// be implicitly generated by items that are placed out of bounds. The sizes of those columns are controlled by `grid_auto_columns` property. + /// + /// + /// + ///   pub grid_template_columns: Vec, - /// Defines the size of implicitly created rows + + /// Defines the size of implicitly created rows. Rows are created implicitly when grid items are given explicit placements that are out of bounds + /// of the rows explicitly created using `grid_template_rows`. + /// + /// + /// + ///   pub grid_auto_rows: Vec, - /// Defined the size of implicitly created columns + /// Defines the size of implicitly created columns. Columns are created implicitly when grid items are given explicit placements that are out of bounds + /// of the columns explicitly created using `grid_template_columms`. + /// + /// + /// + ///   pub grid_auto_columns: Vec, - /// The column in which a grid item starts and how many columns it span - pub grid_column: GridPlacement, - /// The row in which a grid item starts and how many rows it span + + /// The row in which a grid item starts and how many rows it spans. + /// + /// + /// + ///   pub grid_row: GridPlacement, + + /// The column in which a grid item starts and how many columns it spans. + /// + /// + /// + ///   + pub grid_column: GridPlacement, } impl Style { From 9533721decea3d6347b97c0d184a3779260783c6 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Mon, 13 Mar 2023 23:50:14 +0000 Subject: [PATCH 36/65] Document RepeatedGridTrack --- crates/bevy_ui/src/ui_node.rs | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index 0d9656a78e128..cdbc5a796e8dd 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -1143,11 +1143,7 @@ impl GridTrack { self, repetition: Repetition, ) -> RepeatedGridTrack { - RepeatedGridTrack { - repetition: repetition.into(), - min_sizing_function: self.min_sizing_function, - max_sizing_function: self.max_sizing_function, - } + RepeatedGridTrack::repeat(repetition, self) } } @@ -1159,10 +1155,21 @@ impl Default for GridTrack { #[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect, FromReflect)] #[reflect(PartialEq, Serialize, Deserialize)] +/// How many times to repeat a repeated grid track +/// +/// pub enum GridTrackRepetition { - AutoFit, - AutoFill, + /// Repeat the track fixed number of times Count(u16), + /// Repeat the track to fill available space + /// + /// + AutoFill, + /// Repeat the track to fill available space but collapse any tracks that do not end up with + /// an item placed in them. + /// + /// + AutoFit, } impl From for GridTrackRepetition { @@ -1173,12 +1180,26 @@ impl From for GridTrackRepetition { #[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect, FromReflect)] #[reflect(PartialEq, Serialize, Deserialize)] +/// Represents a possibly repeated GridTrack: +/// - Non-repeated `RepeatedGridTrack`s can be created using the constructor method on [`GridTrack`] +/// - Repeated `RepeatedGridTrack`s can be created using `repeat` constructor method below pub struct RepeatedGridTrack { pub(crate) repetition: GridTrackRepetition, pub(crate) min_sizing_function: MinTrackSizingFunction, pub(crate) max_sizing_function: MaxTrackSizingFunction, } +impl RepeatedGridTrack { + /// Create a repeating set of [`GridTrack`]s + pub fn repeat(repetition: impl Into, track: GridTrack) -> Self { + Self { + repetition: repetition.into(), + min_sizing_function: track.min_sizing_function, + max_sizing_function: track.max_sizing_function, + } + } +} + impl From for RepeatedGridTrack { fn from(track: GridTrack) -> Self { Self { From 4947f1f810e83ab796a0e5f5502439bf176edcee Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Tue, 14 Mar 2023 11:30:03 +0000 Subject: [PATCH 37/65] Fix missing backticks in docstring --- crates/bevy_ui/src/ui_node.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index cdbc5a796e8dd..7a4201e468ac9 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -1180,7 +1180,7 @@ impl From for GridTrackRepetition { #[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect, FromReflect)] #[reflect(PartialEq, Serialize, Deserialize)] -/// Represents a possibly repeated GridTrack: +/// Represents a possibly repeated `GridTrack`: /// - Non-repeated `RepeatedGridTrack`s can be created using the constructor method on [`GridTrack`] /// - Repeated `RepeatedGridTrack`s can be created using `repeat` constructor method below pub struct RepeatedGridTrack { From 33dc75df91ac71ec79cae7e4d5fd6365ad11c4d8 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Tue, 14 Mar 2023 14:48:33 +0000 Subject: [PATCH 38/65] Update API for repeated grid tracks --- crates/bevy_ui/src/ui_node.rs | 163 +++++++++++++++++++++++++++++----- examples/ui/grid.rs | 4 +- 2 files changed, 141 insertions(+), 26 deletions(-) diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index 7a4201e468ac9..7e1041b3ee133 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -1128,23 +1128,6 @@ impl GridTrack { } .into() } - - /// Created a repeated set of grid tracks. - /// - /// The repetition parameter can either be: - /// - a `u16` count to repeat the track N times - /// - A `GridTrackRepetition::AutoFit` or `GridTrackRepetition::AutoFill` - /// - /// You may only use one auto-repetition per track list. And if your track list contains an auto repetition - /// then all track (in and outside of the repetition) must be fixed size (px or percent). - /// - /// Integer repetitions are just shorthand for writing out N tracks longhand and are not subject to the same limitations. - pub fn repeat>( - self, - repetition: Repetition, - ) -> RepeatedGridTrack { - RepeatedGridTrack::repeat(repetition, self) - } } impl Default for GridTrack { @@ -1180,9 +1163,19 @@ impl From for GridTrackRepetition { #[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect, FromReflect)] #[reflect(PartialEq, Serialize, Deserialize)] -/// Represents a possibly repeated `GridTrack`: -/// - Non-repeated `RepeatedGridTrack`s can be created using the constructor method on [`GridTrack`] -/// - Repeated `RepeatedGridTrack`s can be created using `repeat` constructor method below +/// Represents a *possibly* repeated `GridTrack`. +/// +/// The repetition parameter can either be: +/// - The integer `1`, in which case the track is non-repeated. +/// - a `u16` count to repeat the track N times +/// - A `GridTrackRepetition::AutoFit` or `GridTrackRepetition::AutoFill` +/// +/// Note: that in the common case you want a non-repeating track (repetition count 1), you may use the constructor method on `GridTrack` +// to create a `RepeatedGridTrack`. i.e. `GridTrack::px(10.0)` is equivalent to `RepeatedGridTrack::px(1, 10.0)`. +/// +/// You may only use one auto-repetition per track list. And if your track list contains an auto repetition +/// then all track (in and outside of the repetition) must be fixed size (px or percent). Integer repetitions are just shorthand for writing out +/// N tracks longhand and are not subject to the same limitations. pub struct RepeatedGridTrack { pub(crate) repetition: GridTrackRepetition, pub(crate) min_sizing_function: MinTrackSizingFunction, @@ -1190,13 +1183,110 @@ pub struct RepeatedGridTrack { } impl RepeatedGridTrack { - /// Create a repeating set of [`GridTrack`]s - pub fn repeat(repetition: impl Into, track: GridTrack) -> Self { + /// Create a repeating set of grid tracks with a fixed pixel size + pub fn px>(repetition: impl Into, value: f32) -> T { Self { repetition: repetition.into(), - min_sizing_function: track.min_sizing_function, - max_sizing_function: track.max_sizing_function, + min_sizing_function: MinTrackSizingFunction::Fixed(Val::Px(value)), + max_sizing_function: MaxTrackSizingFunction::Fixed(Val::Px(value)), + } + .into() + } + + /// Create a repeating set of grid tracks with a percentage size + pub fn percent>(repetition: impl Into, value: f32) -> T { + Self { + repetition: repetition.into(), + min_sizing_function: MinTrackSizingFunction::Fixed(Val::Percent(value)), + max_sizing_function: MaxTrackSizingFunction::Fixed(Val::Percent(value)), + } + .into() + } + + /// Create a repeating set of grid tracks with automatic size + pub fn auto>(repetition: u16) -> T { + Self { + repetition: GridTrackRepetition::Count(repetition), + min_sizing_function: MinTrackSizingFunction::Auto, + max_sizing_function: MaxTrackSizingFunction::Auto, } + .into() + } + + /// Create a repeating set of grid tracks with an `fr` size. + /// Note that this will give the track a content-based minimum size. + /// Usually you are best off using `GridTrack::flex` instead which uses a zero minimum size + pub fn fr>(repetition: u16, value: f32) -> T { + Self { + repetition: GridTrackRepetition::Count(repetition), + min_sizing_function: MinTrackSizingFunction::Auto, + max_sizing_function: MaxTrackSizingFunction::Fraction(value), + } + .into() + } + + /// Create a repeating set of grid tracks with an `minmax(0, Nfr)` size. + pub fn flex>(repetition: u16, value: f32) -> T { + Self { + repetition: GridTrackRepetition::Count(repetition), + min_sizing_function: MinTrackSizingFunction::Fixed(Val::Px(0.0)), + max_sizing_function: MaxTrackSizingFunction::Fraction(value), + } + .into() + } + + /// Create a repeating set of grid tracks with min-content size + pub fn min_content>(repetition: u16) -> T { + Self { + repetition: GridTrackRepetition::Count(repetition), + min_sizing_function: MinTrackSizingFunction::MinContent, + max_sizing_function: MaxTrackSizingFunction::MinContent, + } + .into() + } + + /// Create a repeating set of grid tracks with max-content size + pub fn max_content>(repetition: u16) -> T { + Self { + repetition: GridTrackRepetition::Count(repetition), + min_sizing_function: MinTrackSizingFunction::MaxContent, + max_sizing_function: MaxTrackSizingFunction::MaxContent, + } + .into() + } + + /// Create a fit-content() grid track with fixed pixel limit + pub fn fit_content_px>(repetition: u16, limit: f32) -> T { + Self { + repetition: GridTrackRepetition::Count(repetition), + min_sizing_function: MinTrackSizingFunction::Auto, + max_sizing_function: MaxTrackSizingFunction::FitContent(Val::Px(limit)), + } + .into() + } + + /// Create a fit-content() grid track with percentage limit + pub fn fit_content_percent>(repetition: u16, limit: f32) -> T { + Self { + repetition: GridTrackRepetition::Count(repetition), + min_sizing_function: MinTrackSizingFunction::Auto, + max_sizing_function: MaxTrackSizingFunction::FitContent(Val::Percent(limit)), + } + .into() + } + + /// Create a minmax() grid track + pub fn minmax>( + repetition: impl Into, + min: MinTrackSizingFunction, + max: MaxTrackSizingFunction, + ) -> T { + Self { + repetition: repetition.into(), + min_sizing_function: min, + max_sizing_function: max, + } + .into() } } @@ -1210,6 +1300,31 @@ impl From for RepeatedGridTrack { } } +impl From for Vec { + fn from(track: GridTrack) -> Self { + vec![GridTrack { + min_sizing_function: track.min_sizing_function, + max_sizing_function: track.max_sizing_function, + }] + } +} + +impl From for Vec { + fn from(track: GridTrack) -> Self { + vec![RepeatedGridTrack { + repetition: GridTrackRepetition::Count(1), + min_sizing_function: track.min_sizing_function, + max_sizing_function: track.max_sizing_function, + }] + } +} + +impl From for Vec { + fn from(track: RepeatedGridTrack) -> Self { + vec![track] + } +} + #[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)] #[reflect(PartialEq, Serialize, Deserialize)] pub struct GridPlacement { diff --git a/examples/ui/grid.rs b/examples/ui/grid.rs index 87d80d479578c..6b8facd4cc434 100644 --- a/examples/ui/grid.rs +++ b/examples/ui/grid.rs @@ -77,10 +77,10 @@ fn spawn_layout(mut commands: Commands, asset_server: Res) { padding: UiRect::all(Val::Px(24.0)), /// Set the grid to have 4 columns all with sizes minmax(0, 1fr) /// This creates 4 exactly evenly sized columns - grid_template_columns: vec![GridTrack::flex::(1.0).repeat(4)], + grid_template_columns: RepeatedGridTrack::flex(4, 1.0), /// Set the grid to have 4 rows all with sizes minmax(0, 1fr) /// This creates 4 exactly evenly sized rows - grid_template_rows: vec![GridTrack::flex::(1.0).repeat(4)], + grid_template_rows: RepeatedGridTrack::flex(4, 1.0), /// Set a 12px gap/gutter between rows and columns gap: Size::all(Val::Px(12.0)), ..default() From 7bd94712ffab1e574a7ba3466335541ad301d5bd Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Tue, 14 Mar 2023 14:50:21 +0000 Subject: [PATCH 39/65] Add From impl for GridTrackRepetition --- crates/bevy_ui/src/ui_node.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index 7e1041b3ee133..3e3ac0f4a065c 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -1161,6 +1161,12 @@ impl From for GridTrackRepetition { } } +impl From for GridTrackRepetition { + fn from(count: usize) -> Self { + Self::Count(count as u16) + } +} + #[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect, FromReflect)] #[reflect(PartialEq, Serialize, Deserialize)] /// Represents a *possibly* repeated `GridTrack`. From b75e576200b2d1b8ae3c4a4267bfd5fb0ab157a9 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Tue, 14 Mar 2023 15:13:33 +0000 Subject: [PATCH 40/65] Fixing / in doc comment --- crates/bevy_ui/src/ui_node.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index 3e3ac0f4a065c..2a675b7c46464 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -1167,8 +1167,6 @@ impl From for GridTrackRepetition { } } -#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect, FromReflect)] -#[reflect(PartialEq, Serialize, Deserialize)] /// Represents a *possibly* repeated `GridTrack`. /// /// The repetition parameter can either be: @@ -1177,11 +1175,13 @@ impl From for GridTrackRepetition { /// - A `GridTrackRepetition::AutoFit` or `GridTrackRepetition::AutoFill` /// /// Note: that in the common case you want a non-repeating track (repetition count 1), you may use the constructor method on `GridTrack` -// to create a `RepeatedGridTrack`. i.e. `GridTrack::px(10.0)` is equivalent to `RepeatedGridTrack::px(1, 10.0)`. +/// to create a `RepeatedGridTrack`. i.e. `GridTrack::px(10.0)` is equivalent to `RepeatedGridTrack::px(1, 10.0)`. /// /// You may only use one auto-repetition per track list. And if your track list contains an auto repetition /// then all track (in and outside of the repetition) must be fixed size (px or percent). Integer repetitions are just shorthand for writing out /// N tracks longhand and are not subject to the same limitations. +#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect, FromReflect)] +#[reflect(PartialEq, Serialize, Deserialize)] pub struct RepeatedGridTrack { pub(crate) repetition: GridTrackRepetition, pub(crate) min_sizing_function: MinTrackSizingFunction, From 3c46510c4cfb46b8f355679e8285054369c9299e Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Tue, 14 Mar 2023 15:57:23 +0000 Subject: [PATCH 41/65] Update crates/bevy_ui/src/ui_node.rs Co-authored-by: Rob Parrett --- crates/bevy_ui/src/ui_node.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index 2a675b7c46464..013743551e739 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -1174,7 +1174,7 @@ impl From for GridTrackRepetition { /// - a `u16` count to repeat the track N times /// - A `GridTrackRepetition::AutoFit` or `GridTrackRepetition::AutoFill` /// -/// Note: that in the common case you want a non-repeating track (repetition count 1), you may use the constructor method on `GridTrack` +/// Note: that in the common case you want a non-repeating track (repetition count 1), you may use the constructor methods on [`GridTrack`] /// to create a `RepeatedGridTrack`. i.e. `GridTrack::px(10.0)` is equivalent to `RepeatedGridTrack::px(1, 10.0)`. /// /// You may only use one auto-repetition per track list. And if your track list contains an auto repetition From 3f568e11b95b4c44f88978e1b2f79e7525ae565f Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Tue, 14 Mar 2023 16:17:22 +0000 Subject: [PATCH 42/65] Impl From for GridTrackRepetition + fix test --- crates/bevy_ui/src/flex/convert.rs | 2 +- crates/bevy_ui/src/ui_node.rs | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ui/src/flex/convert.rs b/crates/bevy_ui/src/flex/convert.rs index 9cf1784d552a3..e1c169f380fcf 100644 --- a/crates/bevy_ui/src/flex/convert.rs +++ b/crates/bevy_ui/src/flex/convert.rs @@ -415,7 +415,7 @@ mod tests { GridTrack::percent(50.0), GridTrack::fr(1.0), ], - grid_template_columns: vec![GridTrack::px::(10.0).repeat(5)], + grid_template_columns: RepeatedGridTrack::px(5, 10.0), grid_auto_rows: vec![ GridTrack::fit_content_px(10.0), GridTrack::fit_content_percent(25.0), diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index 013743551e739..6147a1a7981a3 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -1161,6 +1161,12 @@ impl From for GridTrackRepetition { } } +impl From for GridTrackRepetition { + fn from(count: i32) -> Self { + Self::Count(count as u16) + } +} + impl From for GridTrackRepetition { fn from(count: usize) -> Self { Self::Count(count as u16) From 78931a1e200f3e7869deb7ce843b95ffecb32fa1 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Tue, 14 Mar 2023 20:12:41 +0000 Subject: [PATCH 43/65] Fix clippy lints --- examples/ui/grid.rs | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/examples/ui/grid.rs b/examples/ui/grid.rs index 6b8facd4cc434..07ead2a0439a7 100644 --- a/examples/ui/grid.rs +++ b/examples/ui/grid.rs @@ -88,31 +88,31 @@ fn spawn_layout(mut commands: Commands, asset_server: Res) { background_color: BackgroundColor(Color::DARK_GRAY), ..default() }) - .with_children(|mut builder| { + .with_children(|builder| { // Note there is no need to specify the position for each grid item. Grid items that are // not given an explicit position will be automatically positioned into the next available // grid cell. The order in which this is performed can be controlled using the grid_auto_flow // style property. - item_rect(&mut builder, Color::ORANGE); - item_rect(&mut builder, Color::BISQUE); - item_rect(&mut builder, Color::BLUE); - item_rect(&mut builder, Color::CRIMSON); + item_rect(builder, Color::ORANGE); + item_rect(builder, Color::BISQUE); + item_rect(builder, Color::BLUE); + item_rect(builder, Color::CRIMSON); - item_rect(&mut builder, Color::CYAN); - item_rect(&mut builder, Color::ORANGE_RED); - item_rect(&mut builder, Color::DARK_GREEN); - item_rect(&mut builder, Color::FUCHSIA); + item_rect(builder, Color::CYAN); + item_rect(builder, Color::ORANGE_RED); + item_rect(builder, Color::DARK_GREEN); + item_rect(builder, Color::FUCHSIA); - item_rect(&mut builder, Color::GOLD); - item_rect(&mut builder, Color::ALICE_BLUE); - item_rect(&mut builder, Color::GOLD); - item_rect(&mut builder, Color::ANTIQUE_WHITE); + item_rect(builder, Color::GOLD); + item_rect(builder, Color::ALICE_BLUE); + item_rect(builder, Color::GOLD); + item_rect(builder, Color::ANTIQUE_WHITE); - item_rect(&mut builder, Color::GOLD); - item_rect(&mut builder, Color::GOLD); - item_rect(&mut builder, Color::GOLD); - item_rect(&mut builder, Color::GOLD); + item_rect(builder, Color::GOLD); + item_rect(builder, Color::GOLD); + item_rect(builder, Color::GOLD); + item_rect(builder, Color::GOLD); }); // Right side bar (auto placed in row 2, column 2) From ad9c4e862155a2ca8381131749ddc4411be12158 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Tue, 14 Mar 2023 20:13:53 +0000 Subject: [PATCH 44/65] More lint fixes --- examples/ui/grid.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/ui/grid.rs b/examples/ui/grid.rs index 07ead2a0439a7..1a9cdcfdeeff0 100644 --- a/examples/ui/grid.rs +++ b/examples/ui/grid.rs @@ -145,7 +145,7 @@ fn spawn_layout(mut commands: Commands, asset_server: Res) { // Footer / status bar builder.spawn(NodeBundle { style: Style { - /// Make this node span two grid column so that it takes up the entire bottom row + // Make this node span two grid column so that it takes up the entire bottom row grid_column: GridPlacement::span(2), ..default() }, From 002966709c59fafc2599c68e229bfc1d38fccbfc Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Tue, 14 Mar 2023 20:32:52 +0000 Subject: [PATCH 45/65] Fix missing backticks in doc comment --- examples/ui/grid.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/ui/grid.rs b/examples/ui/grid.rs index 1a9cdcfdeeff0..7bdf3a094cad0 100644 --- a/examples/ui/grid.rs +++ b/examples/ui/grid.rs @@ -185,7 +185,7 @@ fn spawn_layout(mut commands: Commands, asset_server: Res) { } /// Create a coloured rectangle node. The node has size as it is assumed that it will be -/// spawned as a child of a Grid container with AlignItems::Stretch and JustifyItems::Stretch +/// spawned as a child of a Grid container with `AlignItems::Stretch` and `JustifyItems::Stretch` /// which will allow it to take it's size from the size of the grid area it occupies. fn item_rect(builder: &mut ChildBuilder, color: Color) { builder From 35707824db259f57315a47f991c661ffa89af30e Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Wed, 15 Mar 2023 21:19:58 +0000 Subject: [PATCH 46/65] Flatten MinTrackSizingFunction and MaxTrackSizingFunction enums --- crates/bevy_ui/src/flex/convert.rs | 23 +++++++++++---- crates/bevy_ui/src/ui_node.rs | 46 +++++++++++++++++------------- 2 files changed, 43 insertions(+), 26 deletions(-) diff --git a/crates/bevy_ui/src/flex/convert.rs b/crates/bevy_ui/src/flex/convert.rs index e1c169f380fcf..2f58a156abe16 100644 --- a/crates/bevy_ui/src/flex/convert.rs +++ b/crates/bevy_ui/src/flex/convert.rs @@ -281,8 +281,11 @@ impl From for taffy::geometry::Line impl MinTrackSizingFunction { fn into_taffy(self, scale_factor: f64) -> taffy::style::MinTrackSizingFunction { match self { - MinTrackSizingFunction::Fixed(val) => taffy::style::MinTrackSizingFunction::Fixed( - val.into_length_percentage(scale_factor), + MinTrackSizingFunction::Px(val) => taffy::style::MinTrackSizingFunction::Fixed( + Val::Px(val).into_length_percentage(scale_factor), + ), + MinTrackSizingFunction::Percent(val) => taffy::style::MinTrackSizingFunction::Fixed( + Val::Percent(val).into_length_percentage(scale_factor), ), MinTrackSizingFunction::Auto => taffy::style::MinTrackSizingFunction::Auto, MinTrackSizingFunction::MinContent => taffy::style::MinTrackSizingFunction::MinContent, @@ -294,15 +297,23 @@ impl MinTrackSizingFunction { impl MaxTrackSizingFunction { fn into_taffy(self, scale_factor: f64) -> taffy::style::MaxTrackSizingFunction { match self { - MaxTrackSizingFunction::Fixed(val) => taffy::style::MaxTrackSizingFunction::Fixed( - val.into_length_percentage(scale_factor), + MaxTrackSizingFunction::Px(val) => taffy::style::MaxTrackSizingFunction::Fixed( + Val::Px(val).into_length_percentage(scale_factor), + ), + MaxTrackSizingFunction::Percent(val) => taffy::style::MaxTrackSizingFunction::Fixed( + Val::Percent(val).into_length_percentage(scale_factor), ), MaxTrackSizingFunction::Auto => taffy::style::MaxTrackSizingFunction::Auto, MaxTrackSizingFunction::MinContent => taffy::style::MaxTrackSizingFunction::MinContent, MaxTrackSizingFunction::MaxContent => taffy::style::MaxTrackSizingFunction::MaxContent, - MaxTrackSizingFunction::FitContent(val) => { + MaxTrackSizingFunction::FitContentPx(val) => { + taffy::style::MaxTrackSizingFunction::FitContent( + Val::Px(val).into_length_percentage(scale_factor), + ) + } + MaxTrackSizingFunction::FitContentPercent(val) => { taffy::style::MaxTrackSizingFunction::FitContent( - val.into_length_percentage(scale_factor), + Val::Percent(val).into_length_percentage(scale_factor), ) } MaxTrackSizingFunction::Fraction(fraction) => { diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index 6147a1a7981a3..e18909419c713 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -995,8 +995,10 @@ impl Default for GridAutoFlow { #[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect, FromReflect)] #[reflect_value(PartialEq, Serialize, Deserialize)] pub enum MinTrackSizingFunction { - /// Track minimum size should be a fixed points or percentage value - Fixed(Val), + /// Track minimum size should be a fixed pixel value + Px(f32), + /// Track minimum size should be a percentage value + Percent(f32), /// Track minimum size should be content sized under a min-content constraint MinContent, /// Track minimum size should be content sized under a max-content constraint @@ -1008,14 +1010,18 @@ pub enum MinTrackSizingFunction { #[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect, FromReflect)] #[reflect_value(PartialEq, Serialize, Deserialize)] pub enum MaxTrackSizingFunction { - /// Track maximum size should be a fixed points or percentage value - Fixed(Val), + /// Track maximum size should be a fixed pixel value + Px(f32), + /// Track maximum size should be a percentage value + Percent(f32), /// Track maximum size should be content sized under a min-content constraint MinContent, /// Track maximum size should be content sized under a max-content constraint MaxContent, - /// Track maximum size should be sized according to the fit-content formula - FitContent(Val), + /// Track maximum size should be sized according to the fit-content formula with a fixed pixel limit + FitContentPx(f32), + /// Track maximum size should be sized according to the fit-content formula with a percentage limit + FitContentPercent(f32), /// Track maximum size should be automatically sized Auto, /// The dimension as a fraction of the total available grid space (`fr` units in CSS) @@ -1049,8 +1055,8 @@ impl GridTrack { /// Create a grid track with a fixed pixel size pub fn px>(value: f32) -> T { Self { - min_sizing_function: MinTrackSizingFunction::Fixed(Val::Px(value)), - max_sizing_function: MaxTrackSizingFunction::Fixed(Val::Px(value)), + min_sizing_function: MinTrackSizingFunction::Px(value), + max_sizing_function: MaxTrackSizingFunction::Px(value), } .into() } @@ -1058,8 +1064,8 @@ impl GridTrack { /// Create a grid track with a percentage size pub fn percent>(value: f32) -> T { Self { - min_sizing_function: MinTrackSizingFunction::Fixed(Val::Percent(value)), - max_sizing_function: MaxTrackSizingFunction::Fixed(Val::Percent(value)), + min_sizing_function: MinTrackSizingFunction::Percent(value), + max_sizing_function: MaxTrackSizingFunction::Percent(value), } .into() } @@ -1078,7 +1084,7 @@ impl GridTrack { /// Create a grid track with an `minmax(0, Nfr)` size. pub fn flex>(value: f32) -> T { Self { - min_sizing_function: MinTrackSizingFunction::Fixed(Val::Px(0.0)), + min_sizing_function: MinTrackSizingFunction::Px(0.0), max_sizing_function: MaxTrackSizingFunction::Fraction(value), } .into() @@ -1106,7 +1112,7 @@ impl GridTrack { pub fn fit_content_px>(limit: f32) -> T { Self { min_sizing_function: MinTrackSizingFunction::Auto, - max_sizing_function: MaxTrackSizingFunction::FitContent(Val::Px(limit)), + max_sizing_function: MaxTrackSizingFunction::FitContentPx(limit), } .into() } @@ -1115,7 +1121,7 @@ impl GridTrack { pub fn fit_content_percent>(limit: f32) -> T { Self { min_sizing_function: MinTrackSizingFunction::Auto, - max_sizing_function: MaxTrackSizingFunction::FitContent(Val::Percent(limit)), + max_sizing_function: MaxTrackSizingFunction::FitContentPercent(limit), } .into() } @@ -1199,8 +1205,8 @@ impl RepeatedGridTrack { pub fn px>(repetition: impl Into, value: f32) -> T { Self { repetition: repetition.into(), - min_sizing_function: MinTrackSizingFunction::Fixed(Val::Px(value)), - max_sizing_function: MaxTrackSizingFunction::Fixed(Val::Px(value)), + min_sizing_function: MinTrackSizingFunction::Px(value), + max_sizing_function: MaxTrackSizingFunction::Px(value), } .into() } @@ -1209,8 +1215,8 @@ impl RepeatedGridTrack { pub fn percent>(repetition: impl Into, value: f32) -> T { Self { repetition: repetition.into(), - min_sizing_function: MinTrackSizingFunction::Fixed(Val::Percent(value)), - max_sizing_function: MaxTrackSizingFunction::Fixed(Val::Percent(value)), + min_sizing_function: MinTrackSizingFunction::Percent(value), + max_sizing_function: MaxTrackSizingFunction::Percent(value), } .into() } @@ -1241,7 +1247,7 @@ impl RepeatedGridTrack { pub fn flex>(repetition: u16, value: f32) -> T { Self { repetition: GridTrackRepetition::Count(repetition), - min_sizing_function: MinTrackSizingFunction::Fixed(Val::Px(0.0)), + min_sizing_function: MinTrackSizingFunction::Px(0.0), max_sizing_function: MaxTrackSizingFunction::Fraction(value), } .into() @@ -1272,7 +1278,7 @@ impl RepeatedGridTrack { Self { repetition: GridTrackRepetition::Count(repetition), min_sizing_function: MinTrackSizingFunction::Auto, - max_sizing_function: MaxTrackSizingFunction::FitContent(Val::Px(limit)), + max_sizing_function: MaxTrackSizingFunction::FitContentPx(limit), } .into() } @@ -1282,7 +1288,7 @@ impl RepeatedGridTrack { Self { repetition: GridTrackRepetition::Count(repetition), min_sizing_function: MinTrackSizingFunction::Auto, - max_sizing_function: MaxTrackSizingFunction::FitContent(Val::Percent(limit)), + max_sizing_function: MaxTrackSizingFunction::FitContentPercent(limit), } .into() } From 8982201e5c6c66393aeb44f77a5d0927e0afe6f2 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Wed, 15 Mar 2023 22:32:42 +0000 Subject: [PATCH 47/65] Make it possible to repeat multiple grid tracks --- crates/bevy_ui/src/flex/convert.rs | 47 +++++++++++++---------- crates/bevy_ui/src/ui_node.rs | 60 +++++++++++++++--------------- 2 files changed, 58 insertions(+), 49 deletions(-) diff --git a/crates/bevy_ui/src/flex/convert.rs b/crates/bevy_ui/src/flex/convert.rs index 2f58a156abe16..1033bd0e972e0 100644 --- a/crates/bevy_ui/src/flex/convert.rs +++ b/crates/bevy_ui/src/flex/convert.rs @@ -332,27 +332,36 @@ impl GridTrack { } impl RepeatedGridTrack { - fn into_repeated_taffy_track(self, scale_factor: f64) -> taffy::style::TrackSizingFunction { - let min = self.min_sizing_function.into_taffy(scale_factor); - let max = self.max_sizing_function.into_taffy(scale_factor); - let taffy_track: taffy::style::NonRepeatedTrackSizingFunction = - taffy::style_helpers::minmax(min, max); - match self.repetition { - GridTrackRepetition::Count(count) => { - if count == 1 { - taffy::style::TrackSizingFunction::Single(taffy_track) - } else { - taffy::style_helpers::repeat(count, vec![taffy_track]) + fn into_repeated_taffy_track(&self, scale_factor: f64) -> taffy::style::TrackSizingFunction { + if self.tracks.len() == 1 && self.repetition == GridTrackRepetition::Count(1) { + let min = self.tracks[0].min_sizing_function.into_taffy(scale_factor); + let max = self.tracks[0].max_sizing_function.into_taffy(scale_factor); + let taffy_track = taffy::style_helpers::minmax(min, max); + taffy::style::TrackSizingFunction::Single(taffy_track) + } else { + let taffy_tracks: Vec<_> = self + .tracks + .iter() + .map(|track| { + let min = track.min_sizing_function.into_taffy(scale_factor); + let max = track.max_sizing_function.into_taffy(scale_factor); + taffy::style_helpers::minmax(min, max) + }) + .collect(); + + match self.repetition { + GridTrackRepetition::Count(count) => { + taffy::style_helpers::repeat(count, taffy_tracks) } + GridTrackRepetition::AutoFit => taffy::style_helpers::repeat( + taffy::style::GridTrackRepetition::AutoFit, + taffy_tracks, + ), + GridTrackRepetition::AutoFill => taffy::style_helpers::repeat( + taffy::style::GridTrackRepetition::AutoFill, + taffy_tracks, + ), } - GridTrackRepetition::AutoFit => taffy::style_helpers::repeat( - taffy::style::GridTrackRepetition::AutoFit, - vec![taffy_track], - ), - GridTrackRepetition::AutoFill => taffy::style_helpers::repeat( - taffy::style::GridTrackRepetition::AutoFill, - vec![taffy_track], - ), } } } diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index e18909419c713..53e2657bdba2e 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -9,6 +9,7 @@ use bevy_render::{ }; use bevy_transform::prelude::GlobalTransform; use serde::{Deserialize, Serialize}; +use smallvec::SmallVec; use std::ops::{Div, DivAssign, Mul, MulAssign}; use thiserror::Error; @@ -1192,12 +1193,11 @@ impl From for GridTrackRepetition { /// You may only use one auto-repetition per track list. And if your track list contains an auto repetition /// then all track (in and outside of the repetition) must be fixed size (px or percent). Integer repetitions are just shorthand for writing out /// N tracks longhand and are not subject to the same limitations. -#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect, FromReflect)] +#[derive(Clone, PartialEq, Debug, Serialize, Deserialize, Reflect, FromReflect)] #[reflect(PartialEq, Serialize, Deserialize)] pub struct RepeatedGridTrack { pub(crate) repetition: GridTrackRepetition, - pub(crate) min_sizing_function: MinTrackSizingFunction, - pub(crate) max_sizing_function: MaxTrackSizingFunction, + pub(crate) tracks: SmallVec<[GridTrack; 1]>, } impl RepeatedGridTrack { @@ -1205,8 +1205,7 @@ impl RepeatedGridTrack { pub fn px>(repetition: impl Into, value: f32) -> T { Self { repetition: repetition.into(), - min_sizing_function: MinTrackSizingFunction::Px(value), - max_sizing_function: MaxTrackSizingFunction::Px(value), + tracks: SmallVec::from_buf([GridTrack::px(value)]), } .into() } @@ -1215,8 +1214,7 @@ impl RepeatedGridTrack { pub fn percent>(repetition: impl Into, value: f32) -> T { Self { repetition: repetition.into(), - min_sizing_function: MinTrackSizingFunction::Percent(value), - max_sizing_function: MaxTrackSizingFunction::Percent(value), + tracks: SmallVec::from_buf([GridTrack::percent(value)]), } .into() } @@ -1225,8 +1223,7 @@ impl RepeatedGridTrack { pub fn auto>(repetition: u16) -> T { Self { repetition: GridTrackRepetition::Count(repetition), - min_sizing_function: MinTrackSizingFunction::Auto, - max_sizing_function: MaxTrackSizingFunction::Auto, + tracks: SmallVec::from_buf([GridTrack::auto()]), } .into() } @@ -1237,8 +1234,7 @@ impl RepeatedGridTrack { pub fn fr>(repetition: u16, value: f32) -> T { Self { repetition: GridTrackRepetition::Count(repetition), - min_sizing_function: MinTrackSizingFunction::Auto, - max_sizing_function: MaxTrackSizingFunction::Fraction(value), + tracks: SmallVec::from_buf([GridTrack::fr(value)]), } .into() } @@ -1247,8 +1243,7 @@ impl RepeatedGridTrack { pub fn flex>(repetition: u16, value: f32) -> T { Self { repetition: GridTrackRepetition::Count(repetition), - min_sizing_function: MinTrackSizingFunction::Px(0.0), - max_sizing_function: MaxTrackSizingFunction::Fraction(value), + tracks: SmallVec::from_buf([GridTrack::flex(value)]), } .into() } @@ -1257,8 +1252,7 @@ impl RepeatedGridTrack { pub fn min_content>(repetition: u16) -> T { Self { repetition: GridTrackRepetition::Count(repetition), - min_sizing_function: MinTrackSizingFunction::MinContent, - max_sizing_function: MaxTrackSizingFunction::MinContent, + tracks: SmallVec::from_buf([GridTrack::min_content()]), } .into() } @@ -1267,33 +1261,30 @@ impl RepeatedGridTrack { pub fn max_content>(repetition: u16) -> T { Self { repetition: GridTrackRepetition::Count(repetition), - min_sizing_function: MinTrackSizingFunction::MaxContent, - max_sizing_function: MaxTrackSizingFunction::MaxContent, + tracks: SmallVec::from_buf([GridTrack::max_content()]), } .into() } - /// Create a fit-content() grid track with fixed pixel limit + /// Create a repeating set of fit-content() grid tracks with fixed pixel limit pub fn fit_content_px>(repetition: u16, limit: f32) -> T { Self { repetition: GridTrackRepetition::Count(repetition), - min_sizing_function: MinTrackSizingFunction::Auto, - max_sizing_function: MaxTrackSizingFunction::FitContentPx(limit), + tracks: SmallVec::from_buf([GridTrack::fit_content_px(limit)]), } .into() } - /// Create a fit-content() grid track with percentage limit + /// Create a repeating set of fit-content() grid tracks with percentage limit pub fn fit_content_percent>(repetition: u16, limit: f32) -> T { Self { repetition: GridTrackRepetition::Count(repetition), - min_sizing_function: MinTrackSizingFunction::Auto, - max_sizing_function: MaxTrackSizingFunction::FitContentPercent(limit), + tracks: SmallVec::from_buf([GridTrack::fit_content_percent(limit)]), } .into() } - /// Create a minmax() grid track + /// Create a repeating set of minmax() grid track pub fn minmax>( repetition: impl Into, min: MinTrackSizingFunction, @@ -1301,8 +1292,19 @@ impl RepeatedGridTrack { ) -> T { Self { repetition: repetition.into(), - min_sizing_function: min, - max_sizing_function: max, + tracks: SmallVec::from_buf([GridTrack::minmax(min, max)]), + } + .into() + } + + /// Create a repetition of a set of tracks + pub fn repeat_many>( + repetition: impl Into, + tracks: impl Into>, + ) -> T { + Self { + repetition: repetition.into(), + tracks: SmallVec::from_vec(tracks.into()), } .into() } @@ -1312,8 +1314,7 @@ impl From for RepeatedGridTrack { fn from(track: GridTrack) -> Self { Self { repetition: GridTrackRepetition::Count(1), - min_sizing_function: track.min_sizing_function, - max_sizing_function: track.max_sizing_function, + tracks: SmallVec::from_buf([track]), } } } @@ -1331,8 +1332,7 @@ impl From for Vec { fn from(track: GridTrack) -> Self { vec![RepeatedGridTrack { repetition: GridTrackRepetition::Count(1), - min_sizing_function: track.min_sizing_function, - max_sizing_function: track.max_sizing_function, + tracks: SmallVec::from_buf([track]), }] } } From e74f819148906e676162b4cfdfa76e644d808aa2 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Wed, 15 Mar 2023 22:40:52 +0000 Subject: [PATCH 48/65] Appease clippy --- crates/bevy_ui/src/flex/convert.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/bevy_ui/src/flex/convert.rs b/crates/bevy_ui/src/flex/convert.rs index 1033bd0e972e0..dc4cad872227f 100644 --- a/crates/bevy_ui/src/flex/convert.rs +++ b/crates/bevy_ui/src/flex/convert.rs @@ -105,12 +105,12 @@ pub fn from_style(scale_factor: f64, style: &Style) -> taffy::style::Style { grid_template_rows: style .grid_template_rows .iter() - .map(|track| track.into_repeated_taffy_track(scale_factor)) + .map(|track| track.clone_into_repeated_taffy_track(scale_factor)) .collect::>(), grid_template_columns: style .grid_template_columns .iter() - .map(|track| track.into_repeated_taffy_track(scale_factor)) + .map(|track| track.clone_into_repeated_taffy_track(scale_factor)) .collect::>(), grid_auto_rows: style .grid_auto_rows @@ -332,7 +332,7 @@ impl GridTrack { } impl RepeatedGridTrack { - fn into_repeated_taffy_track(&self, scale_factor: f64) -> taffy::style::TrackSizingFunction { + fn clone_into_repeated_taffy_track(&self, scale_factor: f64) -> taffy::style::TrackSizingFunction { if self.tracks.len() == 1 && self.repetition == GridTrackRepetition::Count(1) { let min = self.tracks[0].min_sizing_function.into_taffy(scale_factor); let max = self.tracks[0].max_sizing_function.into_taffy(scale_factor); From f6402c51d4ba5bc0c0aad5563e1653642ff418c8 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Wed, 15 Mar 2023 22:57:40 +0000 Subject: [PATCH 49/65] cargo fmt --- crates/bevy_ui/src/flex/convert.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ui/src/flex/convert.rs b/crates/bevy_ui/src/flex/convert.rs index dc4cad872227f..243d055f1aaea 100644 --- a/crates/bevy_ui/src/flex/convert.rs +++ b/crates/bevy_ui/src/flex/convert.rs @@ -332,7 +332,10 @@ impl GridTrack { } impl RepeatedGridTrack { - fn clone_into_repeated_taffy_track(&self, scale_factor: f64) -> taffy::style::TrackSizingFunction { + fn clone_into_repeated_taffy_track( + &self, + scale_factor: f64, + ) -> taffy::style::TrackSizingFunction { if self.tracks.len() == 1 && self.repetition == GridTrackRepetition::Count(1) { let min = self.tracks[0].min_sizing_function.into_taffy(scale_factor); let max = self.tracks[0].max_sizing_function.into_taffy(scale_factor); From 3b12180ecacf85394d219055c84bc1a9edbff373 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Wed, 15 Mar 2023 23:43:04 +0000 Subject: [PATCH 50/65] Expose full grid placement model to bevy --- crates/bevy_ui/src/flex/convert.rs | 30 +++++---- crates/bevy_ui/src/ui_node.rs | 99 ++++++++++++++++++++++++------ 2 files changed, 98 insertions(+), 31 deletions(-) diff --git a/crates/bevy_ui/src/flex/convert.rs b/crates/bevy_ui/src/flex/convert.rs index 243d055f1aaea..2aa7fa6155667 100644 --- a/crates/bevy_ui/src/flex/convert.rs +++ b/crates/bevy_ui/src/flex/convert.rs @@ -269,12 +269,22 @@ impl From for taffy::style::GridAutoFlow { impl From for taffy::geometry::Line { fn from(value: GridPlacement) -> Self { - let start = match value.start { - None => taffy::style::GridPlacement::Auto, - Some(start) => style_helpers::line(start as i16), - }; - let span = taffy::style::GridPlacement::Span(value.span); - taffy::geometry::Line { start, end: span } + let span = value.span.unwrap_or(1).max(1); + match (value.start, value.end) { + (Some(start), Some(end)) => taffy::geometry::Line { + start: style_helpers::line(start), + end: style_helpers::line(end), + }, + (Some(start), None) => taffy::geometry::Line { + start: style_helpers::line(start), + end: style_helpers::span(span), + }, + (None, Some(end)) => taffy::geometry::Line { + start: style_helpers::span(span), + end: style_helpers::line(end), + }, + (None, None) => style_helpers::span(span), + } } } @@ -612,12 +622,6 @@ mod tests { end: sh::span(1) } ); - assert_eq!( - taffy_style.grid_row, - taffy::geometry::Line { - start: sh::auto(), - end: sh::span(3) - } - ); + assert_eq!(taffy_style.grid_row, sh::span(3)); } } diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index 53e2657bdba2e..aafc896f976c7 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -1345,50 +1345,113 @@ impl From for Vec { #[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)] #[reflect(PartialEq, Serialize, Deserialize)] +/// Represents the position of a grid item in a single axis. +/// +/// There are 3 fields which may be set: +/// - `start`: which grid line the item should start at +/// - `end`: which grid line the item should end at +/// - `span`: how many tracks the item should span +/// +/// The default `span` is 1. If neither `start` or `end` is set then the item will be placed automatically. +/// +/// Generally, at most two fields should be set. If all three fields are specifed then `span` will be ignored. If `end` specifies an earlier +/// grid line than `start` then `end` will be ignored and the item will have a span of 1. +/// +/// pub struct GridPlacement { - /// The grid line at which the node should start. Lines are 1-indexed. - /// None indicates automatic placement. - pub start: Option, - /// How many grid tracks the node should span. Defaults to 1. - pub span: u16, + /// The grid line at which the item should start. Lines are 1-indexed. Negative indexes count backwards from the end of the grid. Zero is not a valid index. + pub(crate) start: Option, + /// How many grid tracks the item should span. Defaults to 1. + pub(crate) span: Option, + /// The grid line at which the node should end. Lines are 1-indexed. Negative indexes count backwards from the end of the grid. Zero is not a valid index. + pub(crate) end: Option, } impl GridPlacement { const DEFAULT: Self = Self { start: None, - span: 1, + span: Some(1), + end: None, }; - /// Place the grid item automatically and make it span 1 track + /// Place the grid item automatically (letting the `span` default to `1`). pub fn auto() -> Self { Self { start: None, - span: 1, + end: None, + span: Some(1), + } + } + + /// Place the grid item automatically, specifying how many tracks it should `span`. + pub fn span(span: u16) -> Self { + Self { + start: None, + end: None, + span: Some(span), } } - /// Place the grid item starting in the specified track - pub fn start(start: u16) -> Self { + /// Place the grid item specifying the `start` grid line (letting the `span` default to `1`). + pub fn start(start: i16) -> Self { Self { start: Some(start), - span: 1, + end: None, + span: Some(1), } } - /// Place the grid item automatically and make it span the specified number of tracks - pub fn span(span: u16) -> Self { - Self { start: None, span } + /// Place the grid item specifying the `end` grid line (letting the `span` default to `1`). + pub fn end(end: i16) -> Self { + Self { + start: None, + end: Some(end), + span: Some(1), + } + } + + /// Place the grid item specifying the `start` grid line and how many tracks it should `span`. + pub fn start_span(start: i16, span: u16) -> Self { + Self { + start: Some(start), + end: None, + span: Some(span), + } + } + + /// Place the grid item specifying `start` and `end` grid lines (`span` will be inferred) + pub fn start_end(start: i16, end: i16) -> Self { + Self { + start: Some(start), + end: Some(end), + span: None, + } } - /// Place the grid item starting in the specified track - pub fn set_start(mut self, start: u16) -> Self { + /// Place the grid item specifying the `end` grid line and how many tracks it should `span`. + pub fn end_span(end: i16, span: u16) -> Self { + Self { + start: None, + end: Some(end), + span: Some(span), + } + } + + /// Mutate the item, setting the `start` grid line + pub fn set_start(mut self, start: i16) -> Self { self.start = Some(start); self } - /// Place the grid item automatically and make it span the specified number of tracks + /// Mutate the item, setting the `end` grid line + pub fn set_end(mut self, end: i16) -> Self { + self.end = Some(end); + self + } + + /// Mutate the item, setting the number of tracks the item should `span` pub fn set_span(mut self, span: u16) -> Self { - self.span = span; + self.span = Some(span); self } } From 887b640d11269d581f9c8ef877920e56d7144be7 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Wed, 15 Mar 2023 23:46:58 +0000 Subject: [PATCH 51/65] Add links to MDN Flexbox and CSS Grid guides --- crates/bevy_ui/src/ui_node.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index aafc896f976c7..0bfe03fee8270 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -228,13 +228,15 @@ impl Val { /// /// ### Flexbox /// -/// - [Flexbox Froggy](https://flexboxfroggy.com/). An interactive tutorial/game that teaches the essential parts of Flebox in a fun engaging way. +/// - [MDN: Basic Concepts of Grid Layout](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Basic_Concepts_of_Grid_Layout) /// - [A Complete Guide To Flexbox](https://css-tricks.com/snippets/css/a-guide-to-flexbox/) by CSS Tricks. This is detailed guide with illustrations and comphrehensive written explanation of the different Flexbox properties and how they work. +/// - [Flexbox Froggy](https://flexboxfroggy.com/). An interactive tutorial/game that teaches the essential parts of Flebox in a fun engaging way. /// /// ### CSS Grid /// -/// - [CSS Grid Garden](https://cssgridgarden.com/). An interactive tutorial/game that teaches the essential parts of CSS Grid in a fun engaging way. +/// - [MDN: Basic Concepts of Flexbox](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox) /// - [A Complete Guide To CSS Grid](https://css-tricks.com/snippets/css/complete-guide-grid/) by CSS Tricks. This is detailed guide with illustrations and comphrehensive written explanation of the different CSS Grid properties and how they work. +/// - [CSS Grid Garden](https://cssgridgarden.com/). An interactive tutorial/game that teaches the essential parts of CSS Grid in a fun engaging way. #[derive(Component, Clone, PartialEq, Debug, Reflect)] #[reflect(Component, Default, PartialEq)] From 54681909d496341f24fbd8194ef3b9a8ae0ff37f Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Thu, 16 Mar 2023 00:02:14 +0000 Subject: [PATCH 52/65] Improve docs of GridTrack --- crates/bevy_ui/src/ui_node.rs | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index 0bfe03fee8270..c18d0861e6942 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -1033,6 +1033,8 @@ pub enum MaxTrackSizingFunction { Fraction(f32), } +/// A [`GridTrack`] is a Row or Column of a CSS Grid. This struct specifies what size the track should be. +/// See below for the different "track sizing functions" you can specify. #[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect, FromReflect)] #[reflect(PartialEq, Serialize, Deserialize)] pub struct GridTrack { @@ -1046,15 +1048,6 @@ impl GridTrack { max_sizing_function: MaxTrackSizingFunction::Auto, }; - /// Create a grid track with automatic size - pub fn auto>() -> T { - Self { - min_sizing_function: MinTrackSizingFunction::Auto, - max_sizing_function: MaxTrackSizingFunction::Auto, - } - .into() - } - /// Create a grid track with a fixed pixel size pub fn px>(value: f32) -> T { Self { @@ -1093,7 +1086,16 @@ impl GridTrack { .into() } - /// Create a grid track with min-content size + /// Create a grid track which is automatically sized to fit it's contents, and then + pub fn auto>() -> T { + Self { + min_sizing_function: MinTrackSizingFunction::Auto, + max_sizing_function: MaxTrackSizingFunction::Auto, + } + .into() + } + + /// Create a grid track which is automatically sized to fit it's contents when sized at their "min-content" sizes pub fn min_content>() -> T { Self { min_sizing_function: MinTrackSizingFunction::MinContent, @@ -1102,7 +1104,7 @@ impl GridTrack { .into() } - /// Create a grid track with max-content size + /// Create a grid track which is automatically sized to fit it's contents when sized at their "max-content" sizes pub fn max_content>() -> T { Self { min_sizing_function: MinTrackSizingFunction::MaxContent, @@ -1112,6 +1114,8 @@ impl GridTrack { } /// Create a fit-content() grid track with fixed pixel limit + /// + /// pub fn fit_content_px>(limit: f32) -> T { Self { min_sizing_function: MinTrackSizingFunction::Auto, @@ -1121,6 +1125,8 @@ impl GridTrack { } /// Create a fit-content() grid track with percentage limit + /// + /// pub fn fit_content_percent>(limit: f32) -> T { Self { min_sizing_function: MinTrackSizingFunction::Auto, @@ -1130,6 +1136,8 @@ impl GridTrack { } /// Create a minmax() grid track + /// + /// pub fn minmax>(min: MinTrackSizingFunction, max: MaxTrackSizingFunction) -> T { Self { min_sizing_function: min, @@ -1182,7 +1190,7 @@ impl From for GridTrackRepetition { } } -/// Represents a *possibly* repeated `GridTrack`. +/// Represents a *possibly* repeated [`GridTrack`]. /// /// The repetition parameter can either be: /// - The integer `1`, in which case the track is non-repeated. From 4cc047d4ee1c156d5d0a9939ffa6bc45f76fae56 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Thu, 16 Mar 2023 00:02:48 +0000 Subject: [PATCH 53/65] Fix link formatting on GridAutoFlow --- crates/bevy_ui/src/ui_node.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index c18d0861e6942..d97b28c525196 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -971,7 +971,7 @@ impl Default for FlexWrap { /// /// Defaults to [`GridAutoFlow::Row`] /// -/// [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/grid-auto-flow) +/// #[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Reflect)] #[reflect(PartialEq, Serialize, Deserialize)] pub enum GridAutoFlow { From 29654df0dc8f7c9fbf9fa09a372cf0fa5802dceb Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Thu, 16 Mar 2023 00:06:18 +0000 Subject: [PATCH 54/65] Make all squares in example different colours --- examples/ui/grid.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/ui/grid.rs b/examples/ui/grid.rs index 7bdf3a094cad0..7a324e9372f56 100644 --- a/examples/ui/grid.rs +++ b/examples/ui/grid.rs @@ -104,15 +104,15 @@ fn spawn_layout(mut commands: Commands, asset_server: Res) { item_rect(builder, Color::DARK_GREEN); item_rect(builder, Color::FUCHSIA); - item_rect(builder, Color::GOLD); + item_rect(builder, Color::TEAL); item_rect(builder, Color::ALICE_BLUE); - item_rect(builder, Color::GOLD); + item_rect(builder, Color::CRIMSON); item_rect(builder, Color::ANTIQUE_WHITE); - item_rect(builder, Color::GOLD); - item_rect(builder, Color::GOLD); - item_rect(builder, Color::GOLD); - item_rect(builder, Color::GOLD); + item_rect(builder, Color::YELLOW); + item_rect(builder, Color::PINK); + item_rect(builder, Color::YELLOW_GREEN); + item_rect(builder, Color::SALMON); }); // Right side bar (auto placed in row 2, column 2) From c6cbaa78c40c60a2a8d6b7be91158117dba918c9 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Thu, 30 Mar 2023 14:16:34 +0100 Subject: [PATCH 55/65] Bump taffy req to 0.3.10 --- crates/bevy_ui/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_ui/Cargo.toml b/crates/bevy_ui/Cargo.toml index dc02893ba21bb..0f3bf3320f22d 100644 --- a/crates/bevy_ui/Cargo.toml +++ b/crates/bevy_ui/Cargo.toml @@ -31,7 +31,7 @@ bevy_window = { path = "../bevy_window", version = "0.11.0-dev" } bevy_utils = { path = "../bevy_utils", version = "0.11.0-dev" } # other -taffy = { version = "0.3.7" } +taffy = { version = "0.3.10" } serde = { version = "1", features = ["derive"] } smallvec = { version = "1.6", features = ["union", "const_generics"] } bytemuck = { version = "1.5", features = ["derive"] } From f14dc9868c421ec5d7e204b90688546fbe9664ba Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Thu, 6 Apr 2023 19:32:35 +0100 Subject: [PATCH 56/65] Apply suggestions from code review Co-authored-by: Andreas Weibye <13300393+Weibye@users.noreply.github.com> --- examples/ui/grid.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/ui/grid.rs b/examples/ui/grid.rs index d82b8f199b84a..7a2a5503fbd54 100644 --- a/examples/ui/grid.rs +++ b/examples/ui/grid.rs @@ -51,7 +51,7 @@ fn spawn_layout(mut commands: Commands, asset_server: Res) { .spawn(NodeBundle { style: Style { display: Display::Grid, - /// Make this node span two grid column so that it takes up the entire top tow + /// Make this node span two grid columns so that it takes up the entire top tow grid_column: GridPlacement::span(2), padding: UiRect::all(Val::Px(6.0)), ..default() @@ -66,7 +66,7 @@ fn spawn_layout(mut commands: Commands, asset_server: Res) { builder .spawn(NodeBundle { style: Style { - /// Make the height of the node + /// Make the height of the node fill its parent size: Size::height(Val::Percent(100.0)), /// Make the grid have a 1:1 aspect ratio meaning it will scale as an exact square /// As the height is set explicitly, this means the width will adjust to match the height From c220b99680871e054cfe0f95c5b4662615317706 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Thu, 6 Apr 2023 19:37:56 +0100 Subject: [PATCH 57/65] Remove unsafe Send/Sync impls for FlexSurface DioxusLabs/taffy#146 has now been merged so FlexSurface is now automatically Send and Sync without the unsafe impls! --- crates/bevy_ui/src/flex/mod.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/crates/bevy_ui/src/flex/mod.rs b/crates/bevy_ui/src/flex/mod.rs index d59d8c544164c..fbaf9e08bbab2 100644 --- a/crates/bevy_ui/src/flex/mod.rs +++ b/crates/bevy_ui/src/flex/mod.rs @@ -48,14 +48,11 @@ pub struct FlexSurface { taffy: Taffy, } -// SAFETY: as long as MeasureFunc is Send + Sync. https://github.com/DioxusLabs/taffy/issues/146 -unsafe impl Send for FlexSurface {} -unsafe impl Sync for FlexSurface {} - fn _assert_send_sync_flex_surface_impl_safe() { fn _assert_send_sync() {} _assert_send_sync::>(); _assert_send_sync::(); + _assert_send_sync::(); } impl fmt::Debug for FlexSurface { From c9c85d24d018b4339bcdfe74e4857fe0a488b926 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Thu, 6 Apr 2023 19:45:35 +0100 Subject: [PATCH 58/65] Rename flex module and types to layout/Ui as appropriate --- .../bevy_ui/src/{flex => layout}/convert.rs | 0 crates/bevy_ui/src/{flex => layout}/mod.rs | 56 +++++++++---------- crates/bevy_ui/src/lib.rs | 20 +++---- crates/bevy_ui/src/node_bundles.rs | 8 +-- 4 files changed, 42 insertions(+), 42 deletions(-) rename crates/bevy_ui/src/{flex => layout}/convert.rs (100%) rename crates/bevy_ui/src/{flex => layout}/mod.rs (89%) diff --git a/crates/bevy_ui/src/flex/convert.rs b/crates/bevy_ui/src/layout/convert.rs similarity index 100% rename from crates/bevy_ui/src/flex/convert.rs rename to crates/bevy_ui/src/layout/convert.rs diff --git a/crates/bevy_ui/src/flex/mod.rs b/crates/bevy_ui/src/layout/mod.rs similarity index 89% rename from crates/bevy_ui/src/flex/mod.rs rename to crates/bevy_ui/src/layout/mod.rs index fbaf9e08bbab2..3e4b075a1b4f1 100644 --- a/crates/bevy_ui/src/flex/mod.rs +++ b/crates/bevy_ui/src/layout/mod.rs @@ -42,29 +42,29 @@ impl LayoutContext { } #[derive(Resource)] -pub struct FlexSurface { +pub struct UiSurface { entity_to_taffy: HashMap, window_nodes: HashMap, taffy: Taffy, } -fn _assert_send_sync_flex_surface_impl_safe() { +fn _assert_send_sync_ui_surface_impl_safe() { fn _assert_send_sync() {} _assert_send_sync::>(); _assert_send_sync::(); - _assert_send_sync::(); + _assert_send_sync::(); } -impl fmt::Debug for FlexSurface { +impl fmt::Debug for UiSurface { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("FlexSurface") + f.debug_struct("UiSurface") .field("entity_to_taffy", &self.entity_to_taffy) .field("window_nodes", &self.window_nodes) .finish() } } -impl Default for FlexSurface { +impl Default for UiSurface { fn default() -> Self { Self { entity_to_taffy: Default::default(), @@ -74,7 +74,7 @@ impl Default for FlexSurface { } } -impl FlexSurface { +impl UiSurface { pub fn upsert_node(&mut self, entity: Entity, style: &Style, context: &LayoutContext) { let mut added = false; let taffy = &mut self.taffy; @@ -224,35 +224,35 @@ without UI components as a child of an entity with UI components, results may be } } - pub fn get_layout(&self, entity: Entity) -> Result<&taffy::layout::Layout, FlexError> { + pub fn get_layout(&self, entity: Entity) -> Result<&taffy::layout::Layout, LayoutError> { if let Some(taffy_node) = self.entity_to_taffy.get(&entity) { self.taffy .layout(*taffy_node) - .map_err(FlexError::TaffyError) + .map_err(LayoutError::TaffyError) } else { warn!( "Styled child in a non-UI entity hierarchy. You are using an entity \ with UI components as a child of an entity without UI components, results may be unexpected." ); - Err(FlexError::InvalidHierarchy) + Err(LayoutError::InvalidHierarchy) } } } #[derive(Debug)] -pub enum FlexError { +pub enum LayoutError { InvalidHierarchy, TaffyError(taffy::error::TaffyError), } #[allow(clippy::too_many_arguments)] -pub fn flex_node_system( +pub fn ui_layout_system( primary_window: Query<(Entity, &Window), With>, windows: Query<(Entity, &Window)>, ui_scale: Res, mut scale_factor_events: EventReader, mut resize_events: EventReader, - mut flex_surface: ResMut, + mut ui_surface: ResMut, root_node_query: Query, Without)>, node_query: Query<(Entity, &Style, Option<&CalculatedSize>), (With, Changed