Skip to content

Commit

Permalink
[bevy_text] Add offset to TextSection
Browse files Browse the repository at this point in the history
This makes it possible to shift text (such as for animations), while
still laying it out with `cosmic-text`.
  • Loading branch information
zmbush committed Jul 6, 2024
1 parent 09d86bf commit b983261
Show file tree
Hide file tree
Showing 9 changed files with 76 additions and 4 deletions.
2 changes: 1 addition & 1 deletion crates/bevy_text/src/pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ impl TextPipeline {
YAxisOrientation::BottomToTop => box_size.y - y,
};

let position = Vec2::new(x, y);
let position = Vec2::new(x, y) + sections[section_index].offset;

// TODO: recreate the byte index, that keeps track of where a cursor is,
// when glyphs are not limited to single byte representation, relevant for #1319
Expand Down
21 changes: 19 additions & 2 deletions crates/bevy_text/src/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use bevy_asset::Handle;
use bevy_color::Color;
use bevy_derive::{Deref, DerefMut};
use bevy_ecs::{prelude::Component, reflect::ReflectComponent};
use bevy_math::Vec2;
use bevy_reflect::prelude::*;
use bevy_utils::default;
use cosmic_text::{Buffer, Metrics};
Expand Down Expand Up @@ -127,12 +128,24 @@ impl Text {
}

/// Contains the value of the text in a section and how it should be styled.
#[derive(Debug, Default, Clone, Reflect)]
#[derive(Debug, Clone, Reflect)]
pub struct TextSection {
/// The content (in `String` form) of the text in the section.
pub value: String,
/// The style of the text in the section, including the font face, font size, and color.
pub style: TextStyle,
/// An offset to be applied to each glyph in the section.
pub offset: Vec2,
}

impl Default for TextSection {
fn default() -> Self {
Self {
value: Default::default(),
style: Default::default(),
offset: Vec2::new(0., 0.),
}
}
}

impl TextSection {
Expand All @@ -141,14 +154,18 @@ impl TextSection {
Self {
value: value.into(),
style,

..Default::default()
}
}

/// 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,

value: String::new(),
offset: Vec2::new(0., 0.),
}
}
}
Expand Down
1 change: 1 addition & 0 deletions examples/asset/multi_asset_sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ fn setup_ui(mut commands: Commands) {
color: Color::BLACK,
..Default::default()
},
..Default::default()
}],
justify: JustifyText::Right,
..Default::default()
Expand Down
6 changes: 6 additions & 0 deletions examples/input/text_input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ fn setup_scene(mut commands: Commands, asset_server: Res<AssetServer>) {
font: font.clone_weak(),
..default()
},
..default()
},
TextSection {
value: "false\n".to_string(),
Expand All @@ -51,13 +52,15 @@ fn setup_scene(mut commands: Commands, asset_server: Res<AssetServer>) {
font_size: 30.0,
..default()
},
..default()
},
TextSection {
value: "IME Active: ".to_string(),
style: TextStyle {
font: font.clone_weak(),
..default()
},
..default()
},
TextSection {
value: "false\n".to_string(),
Expand All @@ -66,6 +69,7 @@ fn setup_scene(mut commands: Commands, asset_server: Res<AssetServer>) {
font_size: 30.0,
..default()
},
..default()
},
TextSection {
value: "click to toggle IME, press return to start a new line\n\n".to_string(),
Expand All @@ -74,6 +78,7 @@ fn setup_scene(mut commands: Commands, asset_server: Res<AssetServer>) {
font_size: 18.0,
..default()
},
..default()
},
TextSection {
value: "".to_string(),
Expand All @@ -82,6 +87,7 @@ fn setup_scene(mut commands: Commands, asset_server: Res<AssetServer>) {
font_size: 25.0,
..default()
},
..default()
},
])
.with_style(Style {
Expand Down
1 change: 1 addition & 0 deletions examples/stress_tests/many_glyphs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ fn setup(mut commands: Commands) {
font_size: 4.,
..default()
},
..default()
}],
justify: JustifyText::Left,
linebreak_behavior: BreakLineOn::AnyCharacter,
Expand Down
2 changes: 2 additions & 0 deletions examples/stress_tests/text_pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ fn spawn(mut commands: Commands, asset_server: Res<AssetServer>) {
font_size: (4 + i % 10) as f32,
color: BLUE.into(),
},
..default()
},
TextSection {
value: "pipeline".repeat(i),
Expand All @@ -57,6 +58,7 @@ fn spawn(mut commands: Commands, asset_server: Res<AssetServer>) {
font_size: (4 + i % 11) as f32,
color: YELLOW.into(),
},
..default()
},
]
})
Expand Down
5 changes: 5 additions & 0 deletions examples/tools/gamepad_viewer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,14 +321,17 @@ fn setup_sticks(
TextSection {
value: format!("{:.3}", 0.),
style: style.clone(),
..default()
},
TextSection {
value: ", ".to_string(),
style: style.clone(),
..default()
},
TextSection {
value: format!("{:.3}", 0.),
style,
..default()
},
]),
text_anchor: Anchor::BottomCenter,
Expand Down Expand Up @@ -424,10 +427,12 @@ fn setup_connected(mut commands: Commands) {
TextSection {
value: "Connected Gamepads:\n".to_string(),
style: text_style.clone(),
..default()
},
TextSection {
value: "None".to_string(),
style: text_style,
..default()
},
]),
style: Style {
Expand Down
41 changes: 40 additions & 1 deletion examples/ui/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,21 @@ fn main() {
App::new()
.add_plugins((DefaultPlugins, FrameTimeDiagnosticsPlugin))
.add_systems(Startup, setup)
.add_systems(Update, (text_update_system, text_color_system))
.add_systems(
Update,
(text_update_system, text_color_system, text_wave_system),
)
.run();
}

// A unit struct to help identify the FPS UI component, since there may be many Text components
#[derive(Component)]
struct FpsText;

// A unit struct to help identify the wavy Text component
#[derive(Component)]
struct WavyText;

// A unit struct to help identify the color-changing Text component
#[derive(Component)]
struct ColorText;
Expand Down Expand Up @@ -84,6 +91,28 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
FpsText,
));

commands.spawn((
TextBundle {
text: Text::from_sections((0..100).map(|i| TextSection {
value: (i % 10).to_string(),
style: TextStyle {
font: asset_server.load("fonts/FiraMono-Medium.ttf"),
font_size: 10.0,
color: GOLD.into(),
},
offset: Vec2::new(0., i as f32),
})),
style: Style {
position_type: PositionType::Absolute,
bottom: Val::Px(60.0),
left: Val::Px(15.0),
..default()
},
..default()
},
WavyText,
));

#[cfg(feature = "default_font")]
commands.spawn(
// Here we are able to call the `From` method instead of creating a new `TextSection`.
Expand Down Expand Up @@ -142,3 +171,13 @@ fn text_update_system(
}
}
}

fn text_wave_system(time: Res<Time>, mut query: Query<&mut Text, With<WavyText>>) {
for mut text in &mut query {
for (i, section) in text.sections.iter_mut().enumerate() {
let seconds = (time.elapsed_seconds() + (i as f32 / 10.0)) % 2.0;
let seconds = f32::sin(seconds * std::f32::consts::PI);
section.offset = Vec2::new(0.0, seconds * 40.0);
}
}
}
1 change: 1 addition & 0 deletions examples/ui/text_wrap_debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ fn spawn(mut commands: Commands, asset_server: Res<AssetServer>) {
sections: vec![TextSection {
value: message.clone(),
style: text_style.clone(),
..Default::default()
}],
justify: JustifyText::Left,
linebreak_behavior,
Expand Down

0 comments on commit b983261

Please sign in to comment.