Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
261 changes: 140 additions & 121 deletions examples/ui/text/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use bevy::{
color::palettes::css::GOLD,
diagnostic::{DiagnosticsStore, FrameTimeDiagnosticsPlugin},
prelude::*,
text::FontSourceTemplate,
text::{FontFeatureTag, FontFeatures, FontSize, Underline},
};

Expand All @@ -19,158 +20,176 @@ fn main() {
}

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

// Marker struct to help identify the color-changing Text component
#[derive(Component)]
#[derive(Component, Default, Clone)]
struct AnimatedText;

fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
// UI camera
commands.spawn(Camera2d);
// Text with one section
commands.spawn((
fn setup(world: &mut World) -> Result {
world.spawn_scene_list(bsn_list![
Camera2d,
text_with_one_section(),
text_with_multiple_sections(),
text_with_open_type_features(),
])?;

#[cfg(feature = "default_font")]
world.spawn_scene_list(bsn_list![default_font(),])?;

#[cfg(not(feature = "default_font"))]
world.spawn_scene_list(bsn_list![default_font_disabled()])?;
Ok(())
}

fn text_with_one_section() -> impl Scene {
bsn! {
// Accepts a `String` or any type that converts into a `String`, such as `&str`
Text::new("hello\nbevy!"),
Underline,
Text::new("hello\nbevy!")
Underline
TextFont {
// This font is loaded and will be used instead of the default font.
font: asset_server.load("fonts/FiraSans-Bold.ttf").into(),
font: FontSourceTemplate::Handle("fonts/FiraSans-Bold.ttf"),
// The size of the text will be 20% of the viewport height.
font_size: FontSize::Vh(20.0),
..default()
},
TextShadow::default(),
}
TextShadow::default()
// Set the justification of the Text
TextLayout::new_with_justify(Justify::Center),
TextLayout::new_with_justify(Justify::Center)
// Set the style of the Node itself.
Node {
position_type: PositionType::Absolute,
bottom: px(5),
right: px(5),
..default()
},
AnimatedText,
));

// Text with multiple sections
commands
.spawn((
// Create a Text with multiple child spans.
Text::new("FPS: "),
TextFont {
// This font is loaded and will be used instead of the default font.
font: asset_server.load("fonts/FiraSans-Bold.ttf").into(),
font_size: FontSize::Px(42.0),
..default()
},
))
.with_child((
TextSpan::default(),
}
AnimatedText
}
}

fn text_with_multiple_sections() -> impl Scene {
bsn! {
// Create a Text with multiple child spans.
Text::new("FPS: ")
TextFont {
// This font is loaded and will be used instead of the default font.
font: FontSourceTemplate::Handle("fonts/FiraSans-Bold.ttf"),
font_size: FontSize::Px(42.0),
}
Children [
(
TextFont {
// If the "default_font" feature is unavailable, load a font to use instead.
#[cfg(not(feature = "default_font"))]
font: asset_server.load("fonts/FiraMono-Medium.ttf").into(),
font_size: FontSize::Px(33.0),
..Default::default()
},
TextColor(GOLD.into()),
),
FpsText,
));

// Text with OpenType features
let opentype_font_handle: FontSource =
asset_server.load("fonts/EBGaramond12-Regular.otf").into();
commands
.spawn((
Node {
margin: UiRect::all(px(12.0)),
position_type: PositionType::Absolute,
top: px(5.0),
right: px(5.0),
..default()
},
Text::new("Opentype features:\n"),
TextFont {
font: opentype_font_handle.clone(),
font_size: FontSize::Px(32.0),
..default()
},
))
.with_children(|parent| {
let text_rows = [
("Smallcaps: ", FontFeatureTag::SMALL_CAPS, "Hello World"),
(
"Ligatures: ",
FontFeatureTag::STANDARD_LIGATURES,
"fi fl ff ffi ffl",
),
("Fractions: ", FontFeatureTag::FRACTIONS, "12/134"),
("Superscript: ", FontFeatureTag::SUPERSCRIPT, "Up here!"),
("Subscript: ", FontFeatureTag::SUBSCRIPT, "Down here!"),
(
"Oldstyle figures: ",
FontFeatureTag::OLDSTYLE_FIGURES,
"1234567890",
),
(
"Lining figures: ",
FontFeatureTag::LINING_FIGURES,
"1234567890",
),
];

for (title, feature, text) in text_rows {
parent.spawn((
TextSpan::new(title),
TextFont {
font: opentype_font_handle.clone(),
font_size: FontSize::Px(24.0),
..default()
},
));
parent.spawn((
TextSpan::new(format!("{text}\n")),
TextSpan
Children [(
TextFont {
font: opentype_font_handle.clone(),
font_size: FontSize::Px(24.0),
font_features: FontFeatures::builder().enable(feature).build(),
..default()
},
));
}
});
// If the "default_font" feature is unavailable, load a font to use instead.
//#[cfg(not(feature = "default_font"))]
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please suggest something for me here

font: FontSourceTemplate::Handle("fonts/FiraMono-Medium.ttf"),
font_size: FontSize::Px(33.0),
}
)]
TextColor(Color::from(GOLD))
FpsText
)
]
}
}

#[cfg(feature = "default_font")]
commands.spawn((
type TextRows = (&'static str, FontFeatureTag, &'static str);

fn text_with_open_type_features() -> impl Scene {
let text_rows: [TextRows; 7] = [
("Smallcaps: ", FontFeatureTag::SMALL_CAPS, "Hello World"),
(
"Ligatures: ",
FontFeatureTag::STANDARD_LIGATURES,
"fi fl ff ffi ffl",
),
("Fractions: ", FontFeatureTag::FRACTIONS, "12/134"),
("Superscript: ", FontFeatureTag::SUPERSCRIPT, "Up here!"),
("Subscript: ", FontFeatureTag::SUBSCRIPT, "Down here!"),
(
"Oldstyle figures: ",
FontFeatureTag::OLDSTYLE_FIGURES,
"1234567890",
),
(
"Lining figures: ",
FontFeatureTag::LINING_FIGURES,
"1234567890",
),
];

bsn! {
Node {
margin: UiRect::all(px(12.0)),
position_type: PositionType::Absolute,
top: px(5.0),
right: px(5.0),
}
Text::new("Opentype features:\n")
TextFont {
font: FontSourceTemplate::Handle("fonts/EBGaramond12-Regular.otf"),
font_size: FontSize::Px(32.0),
}
Children [
title(text_rows[0]), text(text_rows[0]),
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please suggest something for me here

title(text_rows[1]), text(text_rows[1]),
title(text_rows[2]), text(text_rows[2]),
title(text_rows[3]), text(text_rows[3]),
title(text_rows[4]), text(text_rows[4]),
title(text_rows[5]), text(text_rows[5]),
title(text_rows[6]), text(text_rows[6]),
]
}
}

fn title(row: TextRows) -> impl Scene {
bsn! {
TextSpan::new(row.0)
TextFont {
font: FontSourceTemplate::Handle("fonts/EBGaramond12-Regular.otf"),
font_size: FontSize::Px(24.0),
}
}
}

fn text(row: TextRows) -> impl Scene {
bsn! {
TextSpan::new(format!("{0}\n", row.2))
TextFont {
font: FontSourceTemplate::Handle("fonts/EBGaramond12-Regular.otf"),
font_size: FontSize::Px(24.0),
font_features: { FontFeatures::builder().enable(row.1).build() },
}
}
}

fn default_font() -> impl Scene {
bsn! {
// Here we are able to call the `From` method instead of creating a new `TextSection`.
// This will use the default font (a minimal subset of FiraMono) and apply the default styling.
Text::new("From an &str into a Text with the default font!"),
Text::new("From an &str into a Text with the default font!")
Node {
position_type: PositionType::Absolute,
bottom: px(5),
left: px(15),
..default()
},
));
}
}
}

#[cfg(not(feature = "default_font"))]
commands.spawn((
Text::new("Default font disabled"),
#[expect(dead_code, reason = "demonstration purpose")]
fn default_font_disabled() -> impl Scene {
bsn! {
Text::new("Default font disabled")
TextFont {
font: asset_server.load("fonts/FiraMono-Medium.ttf"),
..default()
},
font: FontSourceTemplate::Handle("fonts/FiraMono-Medium.ttf"),
}
Node {
position_type: PositionType::Absolute,
bottom: px(5),
left: px(15),
..default()
},
));
}
}
}

fn text_color_system(time: Res<Time>, mut query: Query<&mut TextColor, With<AnimatedText>>) {
Expand Down