From 11baebab1cea49f26266068366e9bcfcc910c559 Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Tue, 7 Mar 2023 20:09:43 +0000 Subject: [PATCH 01/11] Added a new example `size_constraints` --- Cargo.toml | 10 ++ examples/README.md | 1 + examples/ui/size_constraints.rs | 243 ++++++++++++++++++++++++++++++++ 3 files changed, 254 insertions(+) create mode 100644 examples/ui/size_constraints.rs diff --git a/Cargo.toml b/Cargo.toml index ac0fd63b8cdd3..c006fd98c401c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1705,6 +1705,16 @@ description = "Showcases the RelativeCursorPosition component" category = "UI (User Interface)" wasm = true +[[example]] +name = "size_constraints" +path = "examples/ui/size_constraints.rs" + +[package.metadata.example.size_constraints] +name = "Size Constraints" +description = "Demonstrates how the to use the size constraints to control the size of a UI node." +category = "UI (User Interface)" +wasm = true + [[example]] name = "text" path = "examples/ui/text.rs" diff --git a/examples/README.md b/examples/README.md index bc03d2382c372..4516ca024a034 100644 --- a/examples/README.md +++ b/examples/README.md @@ -327,6 +327,7 @@ Example | Description [Button](../examples/ui/button.rs) | Illustrates creating and updating a button [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 +[Size Constraints](../examples/ui/size_constraints.rs) | Demonstrates how the size constraints work. [Text](../examples/ui/text.rs) | Illustrates creating and updating text [Text Debug](../examples/ui/text_debug.rs) | An example for debugging text layout [Text Layout](../examples/ui/text_layout.rs) | Demonstrates how the AlignItems and JustifyContent properties can be composed to layout text diff --git a/examples/ui/size_constraints.rs b/examples/ui/size_constraints.rs new file mode 100644 index 0000000000000..26693d1ff35de --- /dev/null +++ b/examples/ui/size_constraints.rs @@ -0,0 +1,243 @@ +//! This example illustrates how to create a button that changes color and text based on its +//! interaction state. + +use bevy::{prelude::*, winit::WinitSettings}; + +fn main() { + App::new() + .add_plugins(DefaultPlugins) + .add_startup_system(setup) + .add_system(check_buttons) + .run(); +} + +#[derive(Component)] +struct Bar; + +#[derive(Copy, Clone)] +#[derive(Component)] +enum Constraint { + FlexBasis, + Width, + MinWidth, + MaxWidth, +} + +#[derive(Copy, Clone)] +#[derive(Component)] +pub struct ButtonValue(Val); + + + + +fn setup(mut commands: Commands, asset_server: Res) { + // ui camera + commands.spawn(Camera2dBundle::default()); + + let text_style = TextStyle { + font: asset_server.load("fonts/FiraSans-Bold.ttf"), + font_size: 40.0, + color: Color::rgb(0.9, 0.9, 0.9), + }; + + commands.spawn(NodeBundle { + style: Style { + flex_direction: FlexDirection::Column, + flex_basis: Val::Percent(100.0), + justify_content: JustifyContent::SpaceAround, + align_items: AlignItems::Center, + ..Default::default() + }, + background_color: Color::BLACK.into(), + ..Default::default() + }).with_children(|parent| { + parent.spawn(TextBundle::from_section("Size Constraints Example", text_style.clone())); + + spawn_bar(parent); + + parent.spawn(NodeBundle { + style: Style { + size: Size::width(Val::Px(1000.)), + flex_direction: FlexDirection::Column, + align_items: AlignItems::Stretch, + margin: UiRect::all(Val::Px(2.)), + ..Default::default() + }, + background_color: Color::CYAN.into(), + ..Default::default() + }).with_children(|parent| { + for constaint in [Constraint::MinWidth, Constraint::FlexBasis, Constraint::Width, Constraint::MaxWidth] { + spawn_button_row(parent, constaint, text_style.clone()); + } + }); + }); + + +} + +fn spawn_bar(parent: &mut ChildBuilder) { + parent.spawn(NodeBundle { + style: Style { + padding: UiRect::all(Val::Px(5.)), + ..Default::default() + }, + background_color: Color::WHITE.into(), + ..Default::default() + }).with_children(|parent| { + parent.spawn(NodeBundle { + style: Style { + align_items: AlignItems::Stretch, + size: Size::new(Val::Px(1000.), Val::Px(100.)), + padding: UiRect::all(Val::Px(2.)), + ..Default::default() + }, + background_color: Color::BLACK.into(), + ..Default::default() + }) + .with_children(|parent| { + parent.spawn((NodeBundle { + style: Style { + ..Default::default() + }, + background_color: Color::RED.into(), + ..Default::default() + }, + Bar) + ); + }); + }); +} + +fn spawn_button_row( + parent: &mut ChildBuilder, + constraint: Constraint, + text_style: TextStyle, +) { + let label = match constraint { + Constraint::FlexBasis => "flex_basis", + Constraint::Width => "size", + Constraint::MinWidth => "min_size", + Constraint::MaxWidth => "max_size", + }; + parent.spawn(NodeBundle { + style: Style { + flex_direction: FlexDirection::Column, + margin: UiRect::all(Val::Px(2.)), + padding: UiRect::all(Val::Px(2.)), + align_items: AlignItems::Stretch, + ..Default::default() + }, + background_color: Color::DARK_GRAY.into(), + ..Default::default() + }).with_children(|parent| { + parent.spawn(NodeBundle { + style: Style { + flex_direction: FlexDirection::Row, + justify_content: JustifyContent::SpaceBetween, + padding: UiRect::all(Val::Px(2.)), + ..Default::default() + }, + background_color: Color::RED.into(), + ..Default::default() + }).with_children(|parent| { + // spawn row label + parent.spawn(TextBundle { + text: Text::from_section( + label.to_string(), + text_style.clone(), + ), + background_color: Color::BLUE.into(), + ..Default::default() + }); + + // spawn row buttons + parent.spawn(NodeBundle { + background_color: Color::DARK_GREEN.into(), + ..Default::default() + }).with_children(|parent| { + spawn_button( + parent, + constraint, + ButtonValue(Val::Auto), + "Auto".to_string(), + text_style.clone(), + ); + for &percent in [0., 25., 50., 75., 100., 125.].iter() { + spawn_button( + parent, + constraint, + ButtonValue(Val::Percent(percent)), + format!("{percent}%"), + text_style.clone(), + ); + } + }); + }); + + }); +} + +fn spawn_button( + parent: &mut ChildBuilder, + constraint: Constraint, + action: ButtonValue, + label: String, + text_style: TextStyle, +) { + parent.spawn((ButtonBundle { + style: Style { + align_items: AlignItems::Center, + justify_content: JustifyContent::Center, + size: Size::width(Val::Px(100.)), + ..Default::default() + }, + background_color: Color::BLACK.into(), + ..Default::default() + }, + constraint, + action + )).with_children(|parent| { + parent.spawn(TextBundle { + text: Text::from_section( + label, + text_style, + ), + ..Default::default() + }); + }); +} + +fn check_buttons( + mut button_query: Query<(&Interaction, &Constraint, &ButtonValue, &mut BackgroundColor), Changed>, + mut bar_query: Query<&mut Style, With>, +) { + let mut style = bar_query.single_mut(); + for (interaction, constraint, value, mut background_color) in button_query.iter_mut() { + match interaction { + Interaction::Clicked => { + match constraint { + Constraint::FlexBasis => { + style.flex_basis = value.0; + } + Constraint::Width => { + style.size.width = value.0; + } + Constraint::MinWidth => { + style.min_size.width = value.0; + } + Constraint::MaxWidth => { + style.max_size.width = value.0; + } + } + background_color.0 = Color::rgb(0.5, 0.5, 0.5); + + } + Interaction::Hovered => { + background_color.0 = Color::rgb(0.7, 0.7, 0.7); + } + _ => { + background_color.0 = Color::BLACK; + } + } + } +} \ No newline at end of file From 4b6d2e9c1f0f48589d0d004564c02f2ab9fcee8b Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Tue, 7 Mar 2023 20:11:54 +0000 Subject: [PATCH 02/11] cargo fmt --- examples/ui/size_constraints.rs | 284 +++++++++++++++++--------------- 1 file changed, 149 insertions(+), 135 deletions(-) diff --git a/examples/ui/size_constraints.rs b/examples/ui/size_constraints.rs index 26693d1ff35de..3bf0928ff905a 100644 --- a/examples/ui/size_constraints.rs +++ b/examples/ui/size_constraints.rs @@ -14,8 +14,7 @@ fn main() { #[derive(Component)] struct Bar; -#[derive(Copy, Clone)] -#[derive(Component)] +#[derive(Copy, Clone, Component)] enum Constraint { FlexBasis, Width, @@ -23,12 +22,8 @@ enum Constraint { MaxWidth, } -#[derive(Copy, Clone)] -#[derive(Component)] +#[derive(Copy, Clone, Component)] pub struct ButtonValue(Val); - - - fn setup(mut commands: Commands, asset_server: Res) { // ui camera @@ -40,141 +35,153 @@ fn setup(mut commands: Commands, asset_server: Res) { color: Color::rgb(0.9, 0.9, 0.9), }; - commands.spawn(NodeBundle { - style: Style { - flex_direction: FlexDirection::Column, - flex_basis: Val::Percent(100.0), - justify_content: JustifyContent::SpaceAround, - align_items: AlignItems::Center, - ..Default::default() - }, - background_color: Color::BLACK.into(), - ..Default::default() - }).with_children(|parent| { - parent.spawn(TextBundle::from_section("Size Constraints Example", text_style.clone())); - - spawn_bar(parent); - - parent.spawn(NodeBundle { + commands + .spawn(NodeBundle { style: Style { - size: Size::width(Val::Px(1000.)), - flex_direction: FlexDirection::Column, - align_items: AlignItems::Stretch, - margin: UiRect::all(Val::Px(2.)), + flex_direction: FlexDirection::Column, + flex_basis: Val::Percent(100.0), + justify_content: JustifyContent::SpaceAround, + align_items: AlignItems::Center, ..Default::default() }, - background_color: Color::CYAN.into(), + background_color: Color::BLACK.into(), ..Default::default() - }).with_children(|parent| { - for constaint in [Constraint::MinWidth, Constraint::FlexBasis, Constraint::Width, Constraint::MaxWidth] { - spawn_button_row(parent, constaint, text_style.clone()); - } - }); - }); + }) + .with_children(|parent| { + parent.spawn(TextBundle::from_section( + "Size Constraints Example", + text_style.clone(), + )); + + spawn_bar(parent); - + parent + .spawn(NodeBundle { + style: Style { + size: Size::width(Val::Px(1000.)), + flex_direction: FlexDirection::Column, + align_items: AlignItems::Stretch, + margin: UiRect::all(Val::Px(2.)), + ..Default::default() + }, + background_color: Color::CYAN.into(), + ..Default::default() + }) + .with_children(|parent| { + for constaint in [ + Constraint::MinWidth, + Constraint::FlexBasis, + Constraint::Width, + Constraint::MaxWidth, + ] { + spawn_button_row(parent, constaint, text_style.clone()); + } + }); + }); } fn spawn_bar(parent: &mut ChildBuilder) { - parent.spawn(NodeBundle { - style: Style { - padding: UiRect::all(Val::Px(5.)), - ..Default::default() - }, - background_color: Color::WHITE.into(), - ..Default::default() - }).with_children(|parent| { - parent.spawn(NodeBundle { + parent + .spawn(NodeBundle { style: Style { - align_items: AlignItems::Stretch, - size: Size::new(Val::Px(1000.), Val::Px(100.)), - padding: UiRect::all(Val::Px(2.)), + padding: UiRect::all(Val::Px(5.)), ..Default::default() }, - background_color: Color::BLACK.into(), + background_color: Color::WHITE.into(), ..Default::default() }) .with_children(|parent| { - parent.spawn((NodeBundle { - style: Style { + parent + .spawn(NodeBundle { + style: Style { + align_items: AlignItems::Stretch, + size: Size::new(Val::Px(1000.), Val::Px(100.)), + padding: UiRect::all(Val::Px(2.)), + ..Default::default() + }, + background_color: Color::BLACK.into(), ..Default::default() - }, - background_color: Color::RED.into(), - ..Default::default() - }, - Bar) - ); + }) + .with_children(|parent| { + parent.spawn(( + NodeBundle { + style: Style { + ..Default::default() + }, + background_color: Color::RED.into(), + ..Default::default() + }, + Bar, + )); + }); }); - }); } -fn spawn_button_row( - parent: &mut ChildBuilder, - constraint: Constraint, - text_style: TextStyle, -) { +fn spawn_button_row(parent: &mut ChildBuilder, constraint: Constraint, text_style: TextStyle) { let label = match constraint { Constraint::FlexBasis => "flex_basis", Constraint::Width => "size", Constraint::MinWidth => "min_size", Constraint::MaxWidth => "max_size", }; - parent.spawn(NodeBundle { - style: Style { - flex_direction: FlexDirection::Column, - margin: UiRect::all(Val::Px(2.)), - padding: UiRect::all(Val::Px(2.)), - align_items: AlignItems::Stretch, - ..Default::default() - }, - background_color: Color::DARK_GRAY.into(), - ..Default::default() - }).with_children(|parent| { - parent.spawn(NodeBundle { + parent + .spawn(NodeBundle { style: Style { - flex_direction: FlexDirection::Row, - justify_content: JustifyContent::SpaceBetween, + flex_direction: FlexDirection::Column, + margin: UiRect::all(Val::Px(2.)), padding: UiRect::all(Val::Px(2.)), + align_items: AlignItems::Stretch, ..Default::default() }, - background_color: Color::RED.into(), + background_color: Color::DARK_GRAY.into(), ..Default::default() - }).with_children(|parent| { - // spawn row label - parent.spawn(TextBundle { - text: Text::from_section( - label.to_string(), - text_style.clone(), - ), - background_color: Color::BLUE.into(), - ..Default::default() - }); + }) + .with_children(|parent| { + parent + .spawn(NodeBundle { + style: Style { + flex_direction: FlexDirection::Row, + justify_content: JustifyContent::SpaceBetween, + padding: UiRect::all(Val::Px(2.)), + ..Default::default() + }, + background_color: Color::RED.into(), + ..Default::default() + }) + .with_children(|parent| { + // spawn row label + parent.spawn(TextBundle { + text: Text::from_section(label.to_string(), text_style.clone()), + background_color: Color::BLUE.into(), + ..Default::default() + }); - // spawn row buttons - parent.spawn(NodeBundle { - background_color: Color::DARK_GREEN.into(), - ..Default::default() - }).with_children(|parent| { - spawn_button( - parent, - constraint, - ButtonValue(Val::Auto), - "Auto".to_string(), - text_style.clone(), - ); - for &percent in [0., 25., 50., 75., 100., 125.].iter() { - spawn_button( - parent, - constraint, - ButtonValue(Val::Percent(percent)), - format!("{percent}%"), - text_style.clone(), - ); - } - }); + // spawn row buttons + parent + .spawn(NodeBundle { + background_color: Color::DARK_GREEN.into(), + ..Default::default() + }) + .with_children(|parent| { + spawn_button( + parent, + constraint, + ButtonValue(Val::Auto), + "Auto".to_string(), + text_style.clone(), + ); + for &percent in [0., 25., 50., 75., 100., 125.].iter() { + spawn_button( + parent, + constraint, + ButtonValue(Val::Percent(percent)), + format!("{percent}%"), + text_style.clone(), + ); + } + }); + }); }); - - }); } fn spawn_button( @@ -184,31 +191,39 @@ fn spawn_button( label: String, text_style: TextStyle, ) { - parent.spawn((ButtonBundle { - style: Style { - align_items: AlignItems::Center, - justify_content: JustifyContent::Center, - size: Size::width(Val::Px(100.)), - ..Default::default() - }, - background_color: Color::BLACK.into(), - ..Default::default() - }, - constraint, - action - )).with_children(|parent| { - parent.spawn(TextBundle { - text: Text::from_section( - label, - text_style, - ), - ..Default::default() + parent + .spawn(( + ButtonBundle { + style: Style { + align_items: AlignItems::Center, + justify_content: JustifyContent::Center, + size: Size::width(Val::Px(100.)), + ..Default::default() + }, + background_color: Color::BLACK.into(), + ..Default::default() + }, + constraint, + action, + )) + .with_children(|parent| { + parent.spawn(TextBundle { + text: Text::from_section(label, text_style), + ..Default::default() + }); }); - }); } fn check_buttons( - mut button_query: Query<(&Interaction, &Constraint, &ButtonValue, &mut BackgroundColor), Changed>, + mut button_query: Query< + ( + &Interaction, + &Constraint, + &ButtonValue, + &mut BackgroundColor, + ), + Changed, + >, mut bar_query: Query<&mut Style, With>, ) { let mut style = bar_query.single_mut(); @@ -228,9 +243,8 @@ fn check_buttons( Constraint::MaxWidth => { style.max_size.width = value.0; } - } + } background_color.0 = Color::rgb(0.5, 0.5, 0.5); - } Interaction::Hovered => { background_color.0 = Color::rgb(0.7, 0.7, 0.7); @@ -240,4 +254,4 @@ fn check_buttons( } } } -} \ No newline at end of file +} From dfdcf7134e22ae10588d72351de7f9ac897f9a54 Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Tue, 7 Mar 2023 20:42:08 +0000 Subject: [PATCH 03/11] removed unused import --- examples/ui/size_constraints.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/ui/size_constraints.rs b/examples/ui/size_constraints.rs index 3bf0928ff905a..4a6ca7df83775 100644 --- a/examples/ui/size_constraints.rs +++ b/examples/ui/size_constraints.rs @@ -1,7 +1,7 @@ //! This example illustrates how to create a button that changes color and text based on its //! interaction state. -use bevy::{prelude::*, winit::WinitSettings}; +use bevy::prelude::*; fn main() { App::new() From 9920eed127dc86d1c17c046af8de5cc4bded24a4 Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Tue, 7 Mar 2023 20:43:13 +0000 Subject: [PATCH 04/11] fix for explicit-iter-loop lint --- examples/ui/size_constraints.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/ui/size_constraints.rs b/examples/ui/size_constraints.rs index 4a6ca7df83775..e0a521f8ab640 100644 --- a/examples/ui/size_constraints.rs +++ b/examples/ui/size_constraints.rs @@ -170,7 +170,7 @@ fn spawn_button_row(parent: &mut ChildBuilder, constraint: Constraint, text_styl "Auto".to_string(), text_style.clone(), ); - for &percent in [0., 25., 50., 75., 100., 125.].iter() { + for percent in [0., 25., 50., 75., 100., 125.] { spawn_button( parent, constraint, From 4dde333b1bacfb69ce3475f637d5bb7d274d32f4 Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Tue, 7 Mar 2023 20:46:05 +0000 Subject: [PATCH 05/11] build-templated-page --- examples/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/README.md b/examples/README.md index 4516ca024a034..651fc55a4cbdb 100644 --- a/examples/README.md +++ b/examples/README.md @@ -327,7 +327,7 @@ Example | Description [Button](../examples/ui/button.rs) | Illustrates creating and updating a button [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 -[Size Constraints](../examples/ui/size_constraints.rs) | Demonstrates how the size constraints work. +[Size Constraints](../examples/ui/size_constraints.rs) | Demonstrates how the to use the size constraints to control the size of a UI node. [Text](../examples/ui/text.rs) | Illustrates creating and updating text [Text Debug](../examples/ui/text_debug.rs) | An example for debugging text layout [Text Layout](../examples/ui/text_layout.rs) | Demonstrates how the AlignItems and JustifyContent properties can be composed to layout text From 3791bee5c5204b56a0390e45cf46bb72d8e8bd9c Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Wed, 8 Mar 2023 14:10:17 +0000 Subject: [PATCH 06/11] Improved the example's presentation --- examples/ui/size_constraints.rs | 212 ++++++++++++++++++++++++++------ 1 file changed, 172 insertions(+), 40 deletions(-) diff --git a/examples/ui/size_constraints.rs b/examples/ui/size_constraints.rs index e0a521f8ab640..c7f4620837c9d 100644 --- a/examples/ui/size_constraints.rs +++ b/examples/ui/size_constraints.rs @@ -6,15 +6,27 @@ use bevy::prelude::*; fn main() { App::new() .add_plugins(DefaultPlugins) + .add_event::() .add_startup_system(setup) .add_system(check_buttons) + .add_system(update_radio_buttons_colors) .run(); } +const ACTIVE_BORDER_COLOR: Color = Color::ANTIQUE_WHITE; +const INACTIVE_BORDER_COLOR: Color = Color::BLACK; + +const ACTIVE_INNER_COLOR: Color = Color::WHITE; +const INACTIVE_INNER_COLOR: Color = Color::NAVY; + +const ACTIVE_TEXT_COLOR: Color = Color::BLACK; +const HOVERED_TEXT_COLOR: Color = Color::WHITE; +const UNHOVERED_TEXT_COLOR: Color = Color::GRAY; + #[derive(Component)] struct Bar; -#[derive(Copy, Clone, Component)] +#[derive(Copy, Clone, Debug, Component, PartialEq)] enum Constraint { FlexBasis, Width, @@ -23,7 +35,9 @@ enum Constraint { } #[derive(Copy, Clone, Component)] -pub struct ButtonValue(Val); +struct ButtonValue(Val); + +struct ButtonActivatedEvent(Entity); fn setup(mut commands: Commands, asset_server: Res) { // ui camera @@ -40,7 +54,7 @@ fn setup(mut commands: Commands, asset_server: Res) { style: Style { flex_direction: FlexDirection::Column, flex_basis: Val::Percent(100.0), - justify_content: JustifyContent::SpaceAround, + justify_content: JustifyContent::Center, align_items: AlignItems::Center, ..Default::default() }, @@ -48,23 +62,26 @@ fn setup(mut commands: Commands, asset_server: Res) { ..Default::default() }) .with_children(|parent| { - parent.spawn(TextBundle::from_section( - "Size Constraints Example", - text_style.clone(), - )); + parent.spawn( + TextBundle::from_section("Size Constraints Example", text_style.clone()) + .with_style(Style { + margin: UiRect::bottom(Val::Px(25.)), + ..Default::default() + }), + ); spawn_bar(parent); parent .spawn(NodeBundle { style: Style { - size: Size::width(Val::Px(1000.)), flex_direction: FlexDirection::Column, align_items: AlignItems::Stretch, - margin: UiRect::all(Val::Px(2.)), + padding: UiRect::all(Val::Px(10.)), + margin: UiRect::top(Val::Px(50.)), ..Default::default() }, - background_color: Color::CYAN.into(), + background_color: Color::YELLOW.into(), ..Default::default() }) .with_children(|parent| { @@ -84,10 +101,10 @@ fn spawn_bar(parent: &mut ChildBuilder) { parent .spawn(NodeBundle { style: Style { - padding: UiRect::all(Val::Px(5.)), + padding: UiRect::all(Val::Px(10.)), ..Default::default() }, - background_color: Color::WHITE.into(), + background_color: Color::YELLOW.into(), ..Default::default() }) .with_children(|parent| { @@ -108,7 +125,7 @@ fn spawn_bar(parent: &mut ChildBuilder) { style: Style { ..Default::default() }, - background_color: Color::RED.into(), + background_color: Color::WHITE.into(), ..Default::default() }, Bar, @@ -124,16 +141,16 @@ fn spawn_button_row(parent: &mut ChildBuilder, constraint: Constraint, text_styl Constraint::MinWidth => "min_size", Constraint::MaxWidth => "max_size", }; + parent .spawn(NodeBundle { style: Style { flex_direction: FlexDirection::Column, - margin: UiRect::all(Val::Px(2.)), padding: UiRect::all(Val::Px(2.)), align_items: AlignItems::Stretch, ..Default::default() }, - background_color: Color::DARK_GRAY.into(), + background_color: Color::BLACK.into(), ..Default::default() }) .with_children(|parent| { @@ -141,25 +158,37 @@ fn spawn_button_row(parent: &mut ChildBuilder, constraint: Constraint, text_styl .spawn(NodeBundle { style: Style { flex_direction: FlexDirection::Row, - justify_content: JustifyContent::SpaceBetween, + justify_content: JustifyContent::End, padding: UiRect::all(Val::Px(2.)), ..Default::default() }, - background_color: Color::RED.into(), + //background_color: Color::RED.into(), ..Default::default() }) .with_children(|parent| { // spawn row label - parent.spawn(TextBundle { - text: Text::from_section(label.to_string(), text_style.clone()), - background_color: Color::BLUE.into(), - ..Default::default() - }); + parent + .spawn(NodeBundle { + style: Style { + min_size: Size::width(Val::Px(200.)), + max_size: Size::width(Val::Px(200.)), + justify_content: JustifyContent::Center, + align_items: AlignItems::Center, + ..Default::default() + }, + ..Default::default() + }) + .with_children(|parent| { + parent.spawn(TextBundle { + text: Text::from_section(label.to_string(), text_style.clone()), + ..Default::default() + }); + }); // spawn row buttons parent .spawn(NodeBundle { - background_color: Color::DARK_GREEN.into(), + // background_color: Color::DARK_GREEN.into(), ..Default::default() }) .with_children(|parent| { @@ -169,6 +198,7 @@ fn spawn_button_row(parent: &mut ChildBuilder, constraint: Constraint, text_styl ButtonValue(Val::Auto), "Auto".to_string(), text_style.clone(), + true, ); for percent in [0., 25., 50., 75., 100., 125.] { spawn_button( @@ -177,6 +207,7 @@ fn spawn_button_row(parent: &mut ChildBuilder, constraint: Constraint, text_styl ButtonValue(Val::Percent(percent)), format!("{percent}%"), text_style.clone(), + false, ); } }); @@ -190,6 +221,7 @@ fn spawn_button( action: ButtonValue, label: String, text_style: TextStyle, + active: bool, ) { parent .spawn(( @@ -197,39 +229,73 @@ fn spawn_button( style: Style { align_items: AlignItems::Center, justify_content: JustifyContent::Center, - size: Size::width(Val::Px(100.)), + border: UiRect::all(Val::Px(2.)), + margin: UiRect::horizontal(Val::Px(2.)), ..Default::default() }, - background_color: Color::BLACK.into(), + background_color: if active { + ACTIVE_BORDER_COLOR + } else { + INACTIVE_BORDER_COLOR + } + .into(), ..Default::default() }, constraint, action, )) .with_children(|parent| { - parent.spawn(TextBundle { - text: Text::from_section(label, text_style), - ..Default::default() - }); + parent + .spawn(NodeBundle { + style: Style { + size: Size::width(Val::Px(100.)), + justify_content: JustifyContent::Center, + ..Default::default() + }, + background_color: if active { + ACTIVE_INNER_COLOR + } else { + INACTIVE_INNER_COLOR + } + .into(), + ..Default::default() + }) + .with_children(|parent| { + parent.spawn(TextBundle { + text: Text::from_section( + label, + TextStyle { + color: if active { + ACTIVE_TEXT_COLOR + } else { + UNHOVERED_TEXT_COLOR + } + .into(), + ..text_style + }, + ) + .with_alignment(TextAlignment::Center), + ..Default::default() + }); + }); }); } fn check_buttons( mut button_query: Query< - ( - &Interaction, - &Constraint, - &ButtonValue, - &mut BackgroundColor, - ), + (Entity, &Interaction, &Constraint, &ButtonValue), Changed, >, mut bar_query: Query<&mut Style, With>, + mut text_query: Query<&mut Text>, + children_query: Query<&Children>, + mut button_activated_event: EventWriter, ) { let mut style = bar_query.single_mut(); - for (interaction, constraint, value, mut background_color) in button_query.iter_mut() { + for (button_id, interaction, constraint, value) in button_query.iter_mut() { match interaction { Interaction::Clicked => { + button_activated_event.send(ButtonActivatedEvent(button_id)); match constraint { Constraint::FlexBasis => { style.flex_basis = value.0; @@ -244,13 +310,79 @@ fn check_buttons( style.max_size.width = value.0; } } - background_color.0 = Color::rgb(0.5, 0.5, 0.5); } Interaction::Hovered => { - background_color.0 = Color::rgb(0.7, 0.7, 0.7); + if let Ok(children) = children_query.get(button_id) { + for &child in children { + if let Ok(grand_children) = children_query.get(child) { + for &grandchild in grand_children { + if let Ok(mut text) = text_query.get_mut(grandchild) { + if text.sections[0].style.color != ACTIVE_TEXT_COLOR { + text.sections[0].style.color = HOVERED_TEXT_COLOR; + } + } + } + } + } + } } - _ => { - background_color.0 = Color::BLACK; + Interaction::None => { + if let Ok(children) = children_query.get(button_id) { + for &child in children { + if let Ok(grand_children) = children_query.get(child) { + for &grandchild in grand_children { + if let Ok(mut text) = text_query.get_mut(grandchild) { + if text.sections[0].style.color != ACTIVE_TEXT_COLOR { + text.sections[0].style.color = UNHOVERED_TEXT_COLOR; + } + } + } + } + } + } + } + } + } +} + +fn update_radio_buttons_colors( + mut event_reader: EventReader, + button_query: Query<(Entity, &Constraint, &Interaction)>, + mut color_query: Query<&mut BackgroundColor>, + mut text_query: Query<&mut Text>, + children_query: Query<&Children>, +) { + for &ButtonActivatedEvent(button_id) in event_reader.iter() { + let target_constraint = button_query.get_component::(button_id).unwrap(); + for (id, constraint, interaction) in button_query.iter() { + if target_constraint == constraint { + let (border_color, inner_color, text_color) = if id == button_id { + (ACTIVE_BORDER_COLOR, ACTIVE_INNER_COLOR, ACTIVE_TEXT_COLOR) + } else { + ( + INACTIVE_BORDER_COLOR, + INACTIVE_INNER_COLOR, + if matches!(interaction, Interaction::Hovered) { + HOVERED_TEXT_COLOR + } else { + UNHOVERED_TEXT_COLOR + }, + ) + }; + + color_query.get_mut(id).unwrap().0 = border_color; + if let Ok(children) = children_query.get(id) { + for &child in children { + color_query.get_mut(child).unwrap().0 = inner_color; + if let Ok(grand_children) = children_query.get(child) { + for &grandchild in grand_children { + if let Ok(mut text) = text_query.get_mut(grandchild) { + text.sections[0].style.color = text_color; + } + } + } + } + } } } } From c1513ca6b8de5b39af94eb3d0043bc7fa366e7f8 Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Wed, 8 Mar 2023 14:37:41 +0000 Subject: [PATCH 07/11] aligned the bar and controls --- examples/ui/size_constraints.rs | 61 ++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/examples/ui/size_constraints.rs b/examples/ui/size_constraints.rs index c7f4620837c9d..694be254c3f6d 100644 --- a/examples/ui/size_constraints.rs +++ b/examples/ui/size_constraints.rs @@ -52,7 +52,6 @@ fn setup(mut commands: Commands, asset_server: Res) { commands .spawn(NodeBundle { style: Style { - flex_direction: FlexDirection::Column, flex_basis: Val::Percent(100.0), justify_content: JustifyContent::Center, align_items: AlignItems::Center, @@ -62,37 +61,49 @@ fn setup(mut commands: Commands, asset_server: Res) { ..Default::default() }) .with_children(|parent| { - parent.spawn( - TextBundle::from_section("Size Constraints Example", text_style.clone()) - .with_style(Style { - margin: UiRect::bottom(Val::Px(25.)), - ..Default::default() - }), - ); - - spawn_bar(parent); - parent .spawn(NodeBundle { style: Style { flex_direction: FlexDirection::Column, - align_items: AlignItems::Stretch, - padding: UiRect::all(Val::Px(10.)), - margin: UiRect::top(Val::Px(50.)), + align_items: AlignItems::Center, + justify_content: JustifyContent::Center, ..Default::default() }, - background_color: Color::YELLOW.into(), ..Default::default() }) .with_children(|parent| { - for constaint in [ - Constraint::MinWidth, - Constraint::FlexBasis, - Constraint::Width, - Constraint::MaxWidth, - ] { - spawn_button_row(parent, constaint, text_style.clone()); - } + parent.spawn( + TextBundle::from_section("Size Constraints Example", text_style.clone()) + .with_style(Style { + margin: UiRect::bottom(Val::Px(25.)), + ..Default::default() + }), + ); + + spawn_bar(parent); + + parent + .spawn(NodeBundle { + style: Style { + flex_direction: FlexDirection::Column, + align_items: AlignItems::Stretch, + padding: UiRect::all(Val::Px(10.)), + margin: UiRect::top(Val::Px(50.)), + ..Default::default() + }, + background_color: Color::YELLOW.into(), + ..Default::default() + }) + .with_children(|parent| { + for constaint in [ + Constraint::MinWidth, + Constraint::FlexBasis, + Constraint::Width, + Constraint::MaxWidth, + ] { + spawn_button_row(parent, constaint, text_style.clone()); + } + }); }); }); } @@ -101,6 +112,8 @@ fn spawn_bar(parent: &mut ChildBuilder) { parent .spawn(NodeBundle { style: Style { + flex_basis: Val::Percent(100.0), + align_self: AlignSelf::Stretch, padding: UiRect::all(Val::Px(10.)), ..Default::default() }, @@ -112,7 +125,7 @@ fn spawn_bar(parent: &mut ChildBuilder) { .spawn(NodeBundle { style: Style { align_items: AlignItems::Stretch, - size: Size::new(Val::Px(1000.), Val::Px(100.)), + size: Size::new(Val::Percent(100.), Val::Px(100.)), padding: UiRect::all(Val::Px(2.)), ..Default::default() }, From 8cac420789d53c7e09dc55cedd1cb066302e0478 Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Wed, 8 Mar 2023 14:57:56 +0000 Subject: [PATCH 08/11] removed useless into() conversion --- examples/ui/size_constraints.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/ui/size_constraints.rs b/examples/ui/size_constraints.rs index 694be254c3f6d..e185039dbd08e 100644 --- a/examples/ui/size_constraints.rs +++ b/examples/ui/size_constraints.rs @@ -282,8 +282,7 @@ fn spawn_button( ACTIVE_TEXT_COLOR } else { UNHOVERED_TEXT_COLOR - } - .into(), + }, ..text_style }, ) From fce8526ab38f43a2a2a7acb93e6d62d8a3701260 Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Wed, 8 Mar 2023 15:41:30 +0000 Subject: [PATCH 09/11] Increased bar padding. --- examples/ui/size_constraints.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/ui/size_constraints.rs b/examples/ui/size_constraints.rs index e185039dbd08e..d1e93bb387da9 100644 --- a/examples/ui/size_constraints.rs +++ b/examples/ui/size_constraints.rs @@ -8,7 +8,7 @@ fn main() { .add_plugins(DefaultPlugins) .add_event::() .add_startup_system(setup) - .add_system(check_buttons) + .add_system(update_buttons) .add_system(update_radio_buttons_colors) .run(); } @@ -126,7 +126,7 @@ fn spawn_bar(parent: &mut ChildBuilder) { style: Style { align_items: AlignItems::Stretch, size: Size::new(Val::Percent(100.), Val::Px(100.)), - padding: UiRect::all(Val::Px(2.)), + padding: UiRect::all(Val::Px(4.)), ..Default::default() }, background_color: Color::BLACK.into(), @@ -293,7 +293,7 @@ fn spawn_button( }); } -fn check_buttons( +fn update_buttons( mut button_query: Query< (Entity, &Interaction, &Constraint, &ButtonValue), Changed, From 51c1a1d36c8d5fd533082a37ffc427bcf31699dd Mon Sep 17 00:00:00 2001 From: ickshonpe Date: Fri, 21 Apr 2023 21:30:47 +0100 Subject: [PATCH 10/11] Fixed module level doc comment --- examples/ui/size_constraints.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/ui/size_constraints.rs b/examples/ui/size_constraints.rs index d1e93bb387da9..df8be26930413 100644 --- a/examples/ui/size_constraints.rs +++ b/examples/ui/size_constraints.rs @@ -1,5 +1,4 @@ -//! This example illustrates how to create a button that changes color and text based on its -//! interaction state. +//! Demonstrates how the to use the size constraints to control the size of a UI node. use bevy::prelude::*; From e362d4a608f88f1b3704f72c55c34e7ab80d00c1 Mon Sep 17 00:00:00 2001 From: ickshonpe Date: Fri, 21 Apr 2023 21:36:47 +0100 Subject: [PATCH 11/11] Use `add_systems` to add systems. --- examples/ui/size_constraints.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/ui/size_constraints.rs b/examples/ui/size_constraints.rs index df8be26930413..6807b1675526a 100644 --- a/examples/ui/size_constraints.rs +++ b/examples/ui/size_constraints.rs @@ -6,9 +6,8 @@ fn main() { App::new() .add_plugins(DefaultPlugins) .add_event::() - .add_startup_system(setup) - .add_system(update_buttons) - .add_system(update_radio_buttons_colors) + .add_systems(Startup, setup) + .add_systems(Update, (update_buttons, update_radio_buttons_colors)) .run(); }