diff --git a/crates/bevy_render/src/mesh/mesh/conversions.rs b/crates/bevy_render/src/mesh/mesh/conversions.rs index cb4c85db89214..9ebaa06541659 100644 --- a/crates/bevy_render/src/mesh/mesh/conversions.rs +++ b/crates/bevy_render/src/mesh/mesh/conversions.rs @@ -522,7 +522,7 @@ mod tests { Err(error) => error, }; assert_eq!( - format!("{}", error), + error.to_string(), "cannot convert VertexAttributeValues::Uint32x4 to alloc::vec::Vec" ); assert_eq!(format!("{:?}", error), diff --git a/crates/bevy_text/src/text.rs b/crates/bevy_text/src/text.rs index 02f41ca0e992a..4d1c695d8491c 100644 --- a/crates/bevy_text/src/text.rs +++ b/crates/bevy_text/src/text.rs @@ -14,54 +14,83 @@ pub struct Text { } impl Text { - /// Constructs a [`Text`] with (initially) one section. + /// Constructs a [`Text`] with a single section. /// /// ``` - /// # use bevy_asset::{AssetServer, Handle}; + /// # use bevy_asset::Handle; /// # use bevy_render::color::Color; /// # use bevy_text::{Font, Text, TextAlignment, TextStyle, HorizontalAlign, VerticalAlign}; /// # /// # let font_handle: Handle = Default::default(); /// # - /// // basic usage - /// let hello_world = Text::with_section( - /// "hello world!".to_string(), + /// // Basic usage. + /// let hello_world = Text::from_section( + /// // Accepts a String or any type that converts into a String, such as &str. + /// "hello world!", /// TextStyle { /// font: font_handle.clone(), /// font_size: 60.0, /// color: Color::WHITE, /// }, - /// TextAlignment { - /// vertical: VerticalAlign::Center, - /// horizontal: HorizontalAlign::Center, - /// }, /// ); /// - /// let hello_bevy = Text::with_section( - /// // accepts a String or any type that converts into a String, such as &str + /// let hello_bevy = Text::from_section( /// "hello bevy!", /// TextStyle { /// font: font_handle, /// font_size: 60.0, /// color: Color::WHITE, /// }, - /// // you can still use Default - /// Default::default(), - /// ); + /// ) // You can still add an alignment. + /// .with_alignment(TextAlignment::CENTER); + /// ``` + pub fn from_section(value: impl Into, style: TextStyle) -> Self { + Self { + sections: vec![TextSection::new(value, style)], + alignment: Default::default(), + } + } + + /// Constructs a [`Text`] from a list of sections. + /// + /// ``` + /// # use bevy_asset::Handle; + /// # use bevy_render::color::Color; + /// # use bevy_text::{Font, Text, TextStyle, TextSection}; + /// # + /// # let font_handle: Handle = Default::default(); + /// # + /// let hello_world = Text::from_sections([ + /// TextSection::new( + /// "Hello, ", + /// TextStyle { + /// font: font_handle.clone(), + /// font_size: 60.0, + /// color: Color::BLUE, + /// }, + /// ), + /// TextSection::new( + /// "World!", + /// TextStyle { + /// font: font_handle, + /// font_size: 60.0, + /// color: Color::RED, + /// }, + /// ), + /// ]); /// ``` - pub fn with_section>( - value: S, - style: TextStyle, - alignment: TextAlignment, - ) -> Self { + pub fn from_sections(sections: impl IntoIterator) -> Self { Self { - sections: vec![TextSection { - value: value.into(), - style, - }], - alignment, + sections: sections.into_iter().collect(), + alignment: Default::default(), } } + + /// Returns this [`Text`] with a new [`TextAlignment`]. + pub const fn with_alignment(mut self, alignment: TextAlignment) -> Self { + self.alignment = alignment; + self + } } #[derive(Debug, Default, Clone, FromReflect, Reflect)] @@ -70,18 +99,89 @@ pub struct TextSection { pub style: TextStyle, } +impl TextSection { + /// Create a new [`TextSection`]. + pub fn new(value: impl Into, style: TextStyle) -> Self { + Self { + value: value.into(), + style, + } + } + + /// Create an empty [`TextSection`] from a style. Useful when the value will be set dynamically. + pub const fn from_style(style: TextStyle) -> Self { + Self { + value: String::new(), + style, + } + } +} + #[derive(Debug, Clone, Copy, Reflect)] pub struct TextAlignment { pub vertical: VerticalAlign, pub horizontal: HorizontalAlign, } +impl TextAlignment { + /// A [`TextAlignment`] set to the top-left. + pub const TOP_LEFT: Self = TextAlignment { + vertical: VerticalAlign::Top, + horizontal: HorizontalAlign::Left, + }; + + /// A [`TextAlignment`] set to the top-center. + pub const TOP_CENTER: Self = TextAlignment { + vertical: VerticalAlign::Top, + horizontal: HorizontalAlign::Center, + }; + + /// A [`TextAlignment`] set to the the top-right. + pub const TOP_RIGHT: Self = TextAlignment { + vertical: VerticalAlign::Top, + horizontal: HorizontalAlign::Right, + }; + + /// A [`TextAlignment`] set to center the center-left. + pub const CENTER_LEFT: Self = TextAlignment { + vertical: VerticalAlign::Center, + horizontal: HorizontalAlign::Left, + }; + + /// A [`TextAlignment`] set to center on both axes. + pub const CENTER: Self = TextAlignment { + vertical: VerticalAlign::Center, + horizontal: HorizontalAlign::Center, + }; + + /// A [`TextAlignment`] set to the center-right. + pub const CENTER_RIGHT: Self = TextAlignment { + vertical: VerticalAlign::Center, + horizontal: HorizontalAlign::Right, + }; + + /// A [`TextAlignment`] set to the bottom-left. + pub const BOTTOM_LEFT: Self = TextAlignment { + vertical: VerticalAlign::Bottom, + horizontal: HorizontalAlign::Left, + }; + + /// A [`TextAlignment`] set to the bottom-center. + pub const BOTTOM_CENTER: Self = TextAlignment { + vertical: VerticalAlign::Bottom, + horizontal: HorizontalAlign::Center, + }; + + /// A [`TextAlignment`] set to the bottom-right. + pub const BOTTOM_RIGHT: Self = TextAlignment { + vertical: VerticalAlign::Bottom, + horizontal: HorizontalAlign::Right, + }; +} + impl Default for TextAlignment { fn default() -> Self { - TextAlignment { - vertical: VerticalAlign::Top, - horizontal: HorizontalAlign::Left, - } + TextAlignment::TOP_LEFT } } diff --git a/crates/bevy_ui/src/entity.rs b/crates/bevy_ui/src/entity.rs index 5345ee3dd6726..3aa587f564d0d 100644 --- a/crates/bevy_ui/src/entity.rs +++ b/crates/bevy_ui/src/entity.rs @@ -13,7 +13,7 @@ use bevy_render::{ camera::Camera, extract_component::ExtractComponent, prelude::ComputedVisibility, view::Visibility, }; -use bevy_text::Text; +use bevy_text::{Text, TextAlignment, TextSection, TextStyle}; use bevy_transform::prelude::{GlobalTransform, Transform}; /// The basic UI node @@ -89,6 +89,40 @@ pub struct TextBundle { pub computed_visibility: ComputedVisibility, } +impl TextBundle { + /// Create a [`TextBundle`] from a single section. + /// + /// See [`Text::from_section`] for usage. + pub fn from_section(value: impl Into, style: TextStyle) -> Self { + Self { + text: Text::from_section(value, style), + ..Default::default() + } + } + + /// Create a [`TextBundle`] from a list of sections. + /// + /// See [`Text::from_sections`] for usage. + pub fn from_sections(sections: impl IntoIterator) -> Self { + Self { + text: Text::from_sections(sections), + ..Default::default() + } + } + + /// Returns this [`TextBundle`] with a new [`TextAlignment`] on [`Text`]. + pub const fn with_text_alignment(mut self, alignment: TextAlignment) -> Self { + self.text.alignment = alignment; + self + } + + /// Returns this [`TextBundle`] with a new [`Style`]. + pub const fn with_style(mut self, style: Style) -> Self { + self.style = style; + self + } +} + impl Default for TextBundle { fn default() -> Self { TextBundle { diff --git a/examples/2d/text2d.rs b/examples/2d/text2d.rs index 5da6429627802..b2edf872d26a8 100644 --- a/examples/2d/text2d.rs +++ b/examples/2d/text2d.rs @@ -31,30 +31,28 @@ fn setup(mut commands: Commands, asset_server: Res) { font_size: 60.0, color: Color::WHITE, }; - let text_alignment = TextAlignment { - vertical: VerticalAlign::Center, - horizontal: HorizontalAlign::Center, - }; + let text_alignment = TextAlignment::CENTER; // 2d camera commands.spawn_bundle(Camera2dBundle::default()); // Demonstrate changing translation commands .spawn_bundle(Text2dBundle { - text: Text::with_section("translation", text_style.clone(), text_alignment), + text: Text::from_section("translation", text_style.clone()) + .with_alignment(text_alignment), ..default() }) .insert(AnimateTranslation); // Demonstrate changing rotation commands .spawn_bundle(Text2dBundle { - text: Text::with_section("rotation", text_style.clone(), text_alignment), + text: Text::from_section("rotation", text_style.clone()).with_alignment(text_alignment), ..default() }) .insert(AnimateRotation); // Demonstrate changing scale commands .spawn_bundle(Text2dBundle { - text: Text::with_section("scale", text_style.clone(), text_alignment), + text: Text::from_section("scale", text_style.clone()).with_alignment(text_alignment), ..default() }) .insert(AnimateScale); @@ -70,16 +68,8 @@ fn setup(mut commands: Commands, asset_server: Res) { transform: Transform::from_translation(box_position.extend(0.0)), ..default() }); - let text_alignment_topleft = TextAlignment { - vertical: VerticalAlign::Top, - horizontal: HorizontalAlign::Left, - }; commands.spawn_bundle(Text2dBundle { - text: Text::with_section( - "this text wraps in the box", - text_style, - text_alignment_topleft, - ), + text: Text::from_section("this text wraps in the box", text_style), text_2d_bounds: Text2dBounds { // Wrap text in the rectangle size: box_size, diff --git a/examples/async_tasks/external_source_external_thread.rs b/examples/async_tasks/external_source_external_thread.rs index 76a78f519f0e3..679d67d6a626b 100644 --- a/examples/async_tasks/external_source_external_thread.rs +++ b/examples/async_tasks/external_source_external_thread.rs @@ -62,13 +62,11 @@ fn spawn_text( font_size: 20.0, color: Color::WHITE, }; - let text_alignment = TextAlignment { - vertical: VerticalAlign::Center, - horizontal: HorizontalAlign::Center, - }; + for (per_frame, event) in reader.iter().enumerate() { commands.spawn_bundle(Text2dBundle { - text: Text::with_section(format!("{}", event.0), text_style.clone(), text_alignment), + text: Text::from_section(event.0.to_string(), text_style.clone()) + .with_alignment(TextAlignment::CENTER), transform: Transform::from_xyz( per_frame as f32 * 100.0 + rand::thread_rng().gen_range(-40.0..40.0), 300.0, diff --git a/examples/ecs/state.rs b/examples/ecs/state.rs index 03e4e7e0ad8c8..f5a1bd161d1ab 100644 --- a/examples/ecs/state.rs +++ b/examples/ecs/state.rs @@ -55,18 +55,14 @@ fn setup_menu(mut commands: Commands, asset_server: Res) { ..default() }) .with_children(|parent| { - parent.spawn_bundle(TextBundle { - text: Text::with_section( - "Play", - TextStyle { - font: asset_server.load("fonts/FiraSans-Bold.ttf"), - font_size: 40.0, - color: Color::rgb(0.9, 0.9, 0.9), - }, - Default::default(), - ), - ..default() - }); + parent.spawn_bundle(TextBundle::from_section( + "Play", + TextStyle { + font: asset_server.load("fonts/FiraSans-Bold.ttf"), + font_size: 40.0, + color: Color::rgb(0.9, 0.9, 0.9), + }, + )); }) .id(); commands.insert_resource(MenuData { button_entity }); diff --git a/examples/games/alien_cake_addict.rs b/examples/games/alien_cake_addict.rs index 3d674382ea04b..f0a6b4e0c05cf 100644 --- a/examples/games/alien_cake_addict.rs +++ b/examples/games/alien_cake_addict.rs @@ -150,17 +150,16 @@ fn setup(mut commands: Commands, asset_server: Res, mut game: ResMu game.bonus.handle = asset_server.load("models/AlienCake/cakeBirthday.glb#Scene0"); // scoreboard - commands.spawn_bundle(TextBundle { - text: Text::with_section( + commands.spawn_bundle( + TextBundle::from_section( "Score:", TextStyle { font: asset_server.load("fonts/FiraSans-Bold.ttf"), font_size: 40.0, color: Color::rgb(0.5, 0.5, 1.0), }, - Default::default(), - ), - style: Style { + ) + .with_style(Style { position_type: PositionType::Absolute, position: UiRect { top: Val::Px(5.0), @@ -168,9 +167,8 @@ fn setup(mut commands: Commands, asset_server: Res, mut game: ResMu ..default() }, ..default() - }, - ..default() - }); + }), + ); } // remove all entities that are not a camera @@ -383,17 +381,13 @@ fn display_score(mut commands: Commands, asset_server: Res, game: R ..default() }) .with_children(|parent| { - parent.spawn_bundle(TextBundle { - text: Text::with_section( - format!("Cake eaten: {}", game.cake_eaten), - TextStyle { - font: asset_server.load("fonts/FiraSans-Bold.ttf"), - font_size: 80.0, - color: Color::rgb(0.5, 0.5, 1.0), - }, - Default::default(), - ), - ..default() - }); + parent.spawn_bundle(TextBundle::from_section( + format!("Cake eaten: {}", game.cake_eaten), + TextStyle { + font: asset_server.load("fonts/FiraSans-Bold.ttf"), + font_size: 80.0, + color: Color::rgb(0.5, 0.5, 1.0), + }, + )); }); } diff --git a/examples/games/breakout.rs b/examples/games/breakout.rs index c43f74421c458..2260ed91a58c8 100644 --- a/examples/games/breakout.rs +++ b/examples/games/breakout.rs @@ -216,29 +216,23 @@ fn setup(mut commands: Commands, asset_server: Res) { .insert(Velocity(INITIAL_BALL_DIRECTION.normalize() * BALL_SPEED)); // Scoreboard - commands.spawn_bundle(TextBundle { - text: Text { - sections: vec![ - TextSection { - value: "Score: ".to_string(), - style: TextStyle { - font: asset_server.load("fonts/FiraSans-Bold.ttf"), - font_size: SCOREBOARD_FONT_SIZE, - color: TEXT_COLOR, - }, - }, - TextSection { - value: "".to_string(), - style: TextStyle { - font: asset_server.load("fonts/FiraMono-Medium.ttf"), - font_size: SCOREBOARD_FONT_SIZE, - color: SCORE_COLOR, - }, + commands.spawn_bundle( + TextBundle::from_sections([ + TextSection::new( + "Score: ", + TextStyle { + font: asset_server.load("fonts/FiraSans-Bold.ttf"), + font_size: SCOREBOARD_FONT_SIZE, + color: TEXT_COLOR, }, - ], - ..default() - }, - style: Style { + ), + TextSection::from_style(TextStyle { + font: asset_server.load("fonts/FiraMono-Medium.ttf"), + font_size: SCOREBOARD_FONT_SIZE, + color: SCORE_COLOR, + }), + ]) + .with_style(Style { position_type: PositionType::Absolute, position: UiRect { top: SCOREBOARD_TEXT_PADDING, @@ -246,9 +240,8 @@ fn setup(mut commands: Commands, asset_server: Res) { ..default() }, ..default() - }, - ..default() - }); + }), + ); // Walls commands.spawn_bundle(WallBundle::new(WallLocation::Left)); @@ -351,7 +344,7 @@ fn apply_velocity(mut query: Query<(&mut Transform, &Velocity)>) { fn update_scoreboard(scoreboard: Res, mut query: Query<&mut Text>) { let mut text = query.single_mut(); - text.sections[1].value = format!("{}", scoreboard.score); + text.sections[1].value = scoreboard.score.to_string(); } fn check_for_collisions( diff --git a/examples/games/contributors.rs b/examples/games/contributors.rs index 0bad27798aea0..9bb6860107f90 100644 --- a/examples/games/contributors.rs +++ b/examples/games/contributors.rs @@ -134,37 +134,27 @@ fn setup_contributor_selection(mut commands: Commands, asset_server: Res) { commands.spawn_bundle(Camera2dBundle::default()); - commands - .spawn() - .insert(ContributorDisplay) - .insert_bundle(TextBundle { - style: Style { - align_self: AlignSelf::FlexEnd, - ..default() - }, - text: Text { - sections: vec![ - TextSection { - value: "Contributor showcase".to_string(), - style: TextStyle { - font: asset_server.load("fonts/FiraSans-Bold.ttf"), - font_size: 60.0, - color: Color::WHITE, - }, - }, - TextSection { - value: "".to_string(), - style: TextStyle { - font: asset_server.load("fonts/FiraSans-Bold.ttf"), - font_size: 60.0, - color: Color::WHITE, - }, - }, - ], - ..default() - }, + commands.spawn().insert(ContributorDisplay).insert_bundle( + TextBundle::from_sections([ + TextSection::new( + "Contributor showcase", + TextStyle { + font: asset_server.load("fonts/FiraSans-Bold.ttf"), + font_size: 60.0, + color: Color::WHITE, + }, + ), + TextSection::from_style(TextStyle { + font: asset_server.load("fonts/FiraSans-Bold.ttf"), + font_size: 60.0, + color: Color::WHITE, + }), + ]) + .with_style(Style { + align_self: AlignSelf::FlexEnd, ..default() - }); + }), + ); } /// Finds the next contributor to display and selects the entity diff --git a/examples/games/game_menu.rs b/examples/games/game_menu.rs index d07f9cf48459c..7868929d43458 100644 --- a/examples/games/game_menu.rs +++ b/examples/games/game_menu.rs @@ -165,58 +165,52 @@ mod game { .insert(OnGameScreen) .with_children(|parent| { // Display two lines of text, the second one with the current settings - parent.spawn_bundle(TextBundle { - style: Style { - margin: UiRect::all(Val::Px(50.0)), - ..default() - }, - text: Text::with_section( + parent.spawn_bundle( + TextBundle::from_section( "Will be back to the menu shortly...", TextStyle { font: font.clone(), font_size: 80.0, color: TEXT_COLOR, }, - Default::default(), - ), - ..default() - }); - parent.spawn_bundle(TextBundle { - style: Style { + ) + .with_style(Style { margin: UiRect::all(Val::Px(50.0)), ..default() - }, - text: Text { - sections: vec![ - TextSection { - value: format!("quality: {:?}", *display_quality), - style: TextStyle { - font: font.clone(), - font_size: 60.0, - color: Color::BLUE, - }, + }), + ); + parent.spawn_bundle( + TextBundle::from_sections([ + TextSection::new( + format!("quality: {:?}", *display_quality), + TextStyle { + font: font.clone(), + font_size: 60.0, + color: Color::BLUE, }, - TextSection { - value: " - ".to_string(), - style: TextStyle { - font: font.clone(), - font_size: 60.0, - color: TEXT_COLOR, - }, + ), + TextSection::new( + " - ", + TextStyle { + font: font.clone(), + font_size: 60.0, + color: TEXT_COLOR, }, - TextSection { - value: format!("volume: {:?}", *volume), - style: TextStyle { - font: font.clone(), - font_size: 60.0, - color: Color::GREEN, - }, + ), + TextSection::new( + format!("volume: {:?}", *volume), + TextStyle { + font: font.clone(), + font_size: 60.0, + color: Color::GREEN, }, - ], + ), + ]) + .with_style(Style { + margin: UiRect::all(Val::Px(50.0)), ..default() - }, - ..default() - }); + }), + ); }); // Spawn a 5 seconds timer to trigger going back to the menu commands.insert_resource(GameTimer(Timer::from_seconds(5.0, false))); @@ -432,22 +426,20 @@ mod menu { .insert(OnMainMenuScreen) .with_children(|parent| { // Display the game name - parent.spawn_bundle(TextBundle { - style: Style { - margin: UiRect::all(Val::Px(50.0)), - ..default() - }, - text: Text::with_section( + parent.spawn_bundle( + TextBundle::from_section( "Bevy Game Menu UI", TextStyle { font: font.clone(), font_size: 80.0, color: TEXT_COLOR, }, - Default::default(), - ), - ..default() - }); + ) + .with_style(Style { + margin: UiRect::all(Val::Px(50.0)), + ..default() + }), + ); // Display three buttons for each action available from the main menu: // - new game @@ -467,14 +459,10 @@ mod menu { image: UiImage(icon), ..default() }); - parent.spawn_bundle(TextBundle { - text: Text::with_section( - "New Game", - button_text_style.clone(), - Default::default(), - ), - ..default() - }); + parent.spawn_bundle(TextBundle::from_section( + "New Game", + button_text_style.clone(), + )); }); parent .spawn_bundle(ButtonBundle { @@ -490,14 +478,10 @@ mod menu { image: UiImage(icon), ..default() }); - parent.spawn_bundle(TextBundle { - text: Text::with_section( - "Settings", - button_text_style.clone(), - Default::default(), - ), - ..default() - }); + parent.spawn_bundle(TextBundle::from_section( + "Settings", + button_text_style.clone(), + )); }); parent .spawn_bundle(ButtonBundle { @@ -513,10 +497,7 @@ mod menu { image: UiImage(icon), ..default() }); - parent.spawn_bundle(TextBundle { - text: Text::with_section("Quit", button_text_style, Default::default()), - ..default() - }); + parent.spawn_bundle(TextBundle::from_section("Quit", button_text_style)); }); }); } @@ -529,6 +510,7 @@ mod menu { align_items: AlignItems::Center, ..default() }; + let button_text_style = TextStyle { font: asset_server.load("fonts/FiraSans-Bold.ttf"), font_size: 40.0, @@ -548,55 +530,25 @@ mod menu { }) .insert(OnSettingsMenuScreen) .with_children(|parent| { - // Display two buttons for the submenus - parent - .spawn_bundle(ButtonBundle { - style: button_style.clone(), - color: NORMAL_BUTTON.into(), - ..default() - }) - .insert(MenuButtonAction::SettingsDisplay) - .with_children(|parent| { - parent.spawn_bundle(TextBundle { - text: Text::with_section( - "Display", - button_text_style.clone(), - Default::default(), - ), + for (action, text) in [ + (MenuButtonAction::SettingsDisplay, "Display"), + (MenuButtonAction::SettingsSound, "Sound"), + (MenuButtonAction::BackToMainMenu, "Back"), + ] { + parent + .spawn_bundle(ButtonBundle { + style: button_style.clone(), + color: NORMAL_BUTTON.into(), ..default() - }); - }); - parent - .spawn_bundle(ButtonBundle { - style: button_style.clone(), - color: NORMAL_BUTTON.into(), - ..default() - }) - .insert(MenuButtonAction::SettingsSound) - .with_children(|parent| { - parent.spawn_bundle(TextBundle { - text: Text::with_section( - "Sound", + }) + .insert(action) + .with_children(|parent| { + parent.spawn_bundle(TextBundle::from_section( + text, button_text_style.clone(), - Default::default(), - ), - ..default() - }); - }); - // Display the back button to return to the main menu screen - parent - .spawn_bundle(ButtonBundle { - style: button_style, - color: NORMAL_BUTTON.into(), - ..default() - }) - .insert(MenuButtonAction::BackToMainMenu) - .with_children(|parent| { - parent.spawn_bundle(TextBundle { - text: Text::with_section("Back", button_text_style, Default::default()), - ..default() + )); }); - }); + } }); } @@ -644,14 +596,10 @@ mod menu { }) .with_children(|parent| { // Display a label for the current setting - parent.spawn_bundle(TextBundle { - text: Text::with_section( - "Display Quality", - button_text_style.clone(), - Default::default(), - ), - ..default() - }); + parent.spawn_bundle(TextBundle::from_section( + "Display Quality", + button_text_style.clone(), + )); // Display a button for each possible value for quality_setting in [ DisplayQuality::Low, @@ -667,14 +615,10 @@ mod menu { ..default() }); entity.insert(quality_setting).with_children(|parent| { - parent.spawn_bundle(TextBundle { - text: Text::with_section( - format!("{:?}", quality_setting), - button_text_style.clone(), - Default::default(), - ), - ..default() - }); + parent.spawn_bundle(TextBundle::from_section( + format!("{quality_setting:?}"), + button_text_style.clone(), + )); }); if *display_quality == quality_setting { entity.insert(SelectedOption); @@ -690,10 +634,7 @@ mod menu { }) .insert(MenuButtonAction::BackToSettings) .with_children(|parent| { - parent.spawn_bundle(TextBundle { - text: Text::with_section("Back", button_text_style, Default::default()), - ..default() - }); + parent.spawn_bundle(TextBundle::from_section("Back", button_text_style)); }); }); } @@ -739,14 +680,10 @@ mod menu { ..default() }) .with_children(|parent| { - parent.spawn_bundle(TextBundle { - text: Text::with_section( - "Volume", - button_text_style.clone(), - Default::default(), - ), - ..default() - }); + parent.spawn_bundle(TextBundle::from_section( + "Volume", + button_text_style.clone(), + )); for volume_setting in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] { let mut entity = parent.spawn_bundle(ButtonBundle { style: Style { @@ -770,10 +707,7 @@ mod menu { }) .insert(MenuButtonAction::BackToSettings) .with_children(|parent| { - parent.spawn_bundle(TextBundle { - text: Text::with_section("Back", button_text_style, Default::default()), - ..default() - }); + parent.spawn_bundle(TextBundle::from_section("Back", button_text_style)); }); }); } diff --git a/examples/ios/src/lib.rs b/examples/ios/src/lib.rs index ed03ad1bbcc57..3240598424a30 100644 --- a/examples/ios/src/lib.rs +++ b/examples/ios/src/lib.rs @@ -108,23 +108,17 @@ fn setup_scene( ..default() }) .with_children(|b| { - b.spawn_bundle(TextBundle { - text: Text { - sections: vec![TextSection { - value: "Test Button".to_string(), - style: TextStyle { - font: asset_server.load("fonts/FiraSans-Bold.ttf"), - font_size: 30.0, - color: Color::BLACK, - }, - }], - alignment: TextAlignment { - vertical: VerticalAlign::Center, - horizontal: HorizontalAlign::Center, + b.spawn_bundle( + TextBundle::from_section( + "Test Button", + TextStyle { + font: asset_server.load("fonts/FiraSans-Bold.ttf"), + font_size: 30.0, + color: Color::BLACK, }, - }, - ..default() - }); + ) + .with_text_alignment(TextAlignment::CENTER), + ); }); } diff --git a/examples/scene/scene.rs b/examples/scene/scene.rs index 4b499a1b819ce..66689e2a8b5f2 100644 --- a/examples/scene/scene.rs +++ b/examples/scene/scene.rs @@ -105,20 +105,18 @@ fn save_scene_system(world: &mut World) { // text example. fn infotext_system(mut commands: Commands, asset_server: Res) { commands.spawn_bundle(Camera2dBundle::default()); - commands.spawn_bundle(TextBundle { - style: Style { - align_self: AlignSelf::FlexEnd, - ..default() - }, - text: Text::with_section( + commands.spawn_bundle( + TextBundle::from_section( "Nothing to see in this window! Check the console output!", TextStyle { font: asset_server.load("fonts/FiraSans-Bold.ttf"), font_size: 50.0, color: Color::WHITE, }, - Default::default(), - ), - ..default() - }); + ) + .with_style(Style { + align_self: AlignSelf::FlexEnd, + ..default() + }), + ); } diff --git a/examples/stress_tests/bevymark.rs b/examples/stress_tests/bevymark.rs index bf3955428b1d9..249e506ce0f15 100644 --- a/examples/stress_tests/bevymark.rs +++ b/examples/stress_tests/bevymark.rs @@ -96,45 +96,36 @@ fn setup(mut commands: Commands, asset_server: Res) { commands.spawn_bundle(Camera2dBundle::default()); commands - .spawn_bundle(TextBundle { - text: Text { - sections: vec![ - TextSection { - value: "Bird Count: ".to_string(), - style: TextStyle { - font: asset_server.load("fonts/FiraSans-Bold.ttf"), - font_size: 40.0, - color: Color::rgb(0.0, 1.0, 0.0), - }, + .spawn_bundle( + TextBundle::from_sections([ + TextSection::new( + "Bird Count: ", + TextStyle { + font: asset_server.load("fonts/FiraSans-Bold.ttf"), + font_size: 40.0, + color: Color::rgb(0.0, 1.0, 0.0), }, - TextSection { - value: "".to_string(), - style: TextStyle { - font: asset_server.load("fonts/FiraSans-Bold.ttf"), - font_size: 40.0, - color: Color::rgb(0.0, 1.0, 1.0), - }, - }, - TextSection { - value: "\nAverage FPS: ".to_string(), - style: TextStyle { - font: asset_server.load("fonts/FiraSans-Bold.ttf"), - font_size: 40.0, - color: Color::rgb(0.0, 1.0, 0.0), - }, - }, - TextSection { - value: "".to_string(), - style: TextStyle { - font: asset_server.load("fonts/FiraSans-Bold.ttf"), - font_size: 40.0, - color: Color::rgb(0.0, 1.0, 1.0), - }, + ), + TextSection::from_style(TextStyle { + font: asset_server.load("fonts/FiraSans-Bold.ttf"), + font_size: 40.0, + color: Color::rgb(0.0, 1.0, 1.0), + }), + TextSection::new( + "\nAverage FPS: ", + TextStyle { + font: asset_server.load("fonts/FiraSans-Bold.ttf"), + font_size: 40.0, + color: Color::rgb(0.0, 1.0, 0.0), }, - ], - ..default() - }, - style: Style { + ), + TextSection::from_style(TextStyle { + font: asset_server.load("fonts/FiraSans-Bold.ttf"), + font_size: 40.0, + color: Color::rgb(0.0, 1.0, 1.0), + }), + ]) + .with_style(Style { position_type: PositionType::Absolute, position: UiRect { top: Val::Px(5.0), @@ -142,9 +133,8 @@ fn setup(mut commands: Commands, asset_server: Res) { ..default() }, ..default() - }, - ..default() - }) + }), + ) .insert(StatsText); commands.insert_resource(BirdTexture(texture)); @@ -265,12 +255,12 @@ fn counter_system( let mut text = query.single_mut(); if counter.is_changed() { - text.sections[1].value = format!("{}", counter.count); + text.sections[1].value = counter.count.to_string(); } if let Some(fps) = diagnostics.get(FrameTimeDiagnosticsPlugin::FPS) { if let Some(average) = fps.average() { - text.sections[3].value = format!("{:.2}", average); + text.sections[3].value = format!("{average:.2}"); } }; } diff --git a/examples/transforms/global_vs_local_translation.rs b/examples/transforms/global_vs_local_translation.rs index 815cdab22f465..5bbaa445eec4c 100644 --- a/examples/transforms/global_vs_local_translation.rs +++ b/examples/transforms/global_vs_local_translation.rs @@ -101,25 +101,18 @@ fn setup( }); // Add text to explain inputs and what is happening. - commands.spawn_bundle(TextBundle { - text: Text::with_section( - "Press the arrow keys to move the cubes. Toggle movement for yellow (1), red (2) and green (3) cubes via number keys. + commands.spawn_bundle(TextBundle::from_section( + "Press the arrow keys to move the cubes. Toggle movement for yellow (1), red (2) and green (3) cubes via number keys. Notice how the green cube will translate further in respect to the yellow in contrast to the red cube. This is due to the use of its LocalTransform that is relative to the yellow cubes transform instead of the GlobalTransform as in the case of the red cube. The red cube is moved through its GlobalTransform and thus is unaffected by the yellows transform.", - TextStyle { - font: asset_server.load("fonts/FiraSans-Bold.ttf"), - font_size: 22.0, - color: Color::WHITE, - }, - TextAlignment { - horizontal: HorizontalAlign::Left, - ..default() - }, - ), - ..default() - }); + TextStyle { + font: asset_server.load("fonts/FiraSans-Bold.ttf"), + font_size: 22.0, + color: Color::WHITE, + }, + )); } // This system will move all cubes that are marked as ChangeGlobal according to their global transform. diff --git a/examples/ui/button.rs b/examples/ui/button.rs index 4a8ea34f11c8b..8007ee86c0b35 100644 --- a/examples/ui/button.rs +++ b/examples/ui/button.rs @@ -62,17 +62,13 @@ fn setup(mut commands: Commands, asset_server: Res) { ..default() }) .with_children(|parent| { - parent.spawn_bundle(TextBundle { - text: Text::with_section( - "Button", - TextStyle { - font: asset_server.load("fonts/FiraSans-Bold.ttf"), - font_size: 40.0, - color: Color::rgb(0.9, 0.9, 0.9), - }, - Default::default(), - ), - ..default() - }); + parent.spawn_bundle(TextBundle::from_section( + "Button", + TextStyle { + font: asset_server.load("fonts/FiraSans-Bold.ttf"), + font_size: 40.0, + color: Color::rgb(0.9, 0.9, 0.9), + }, + )); }); } diff --git a/examples/ui/font_atlas_debug.rs b/examples/ui/font_atlas_debug.rs index 71e9808cdeb68..4cb3862422840 100644 --- a/examples/ui/font_atlas_debug.rs +++ b/examples/ui/font_atlas_debug.rs @@ -67,8 +67,9 @@ fn text_update_system(mut state: ResMut, time: Res