diff --git a/Cargo.toml b/Cargo.toml index c5632881e1dcc..71236cbd0a842 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5238,6 +5238,17 @@ description = "Demonstrates use of core scrollbar in Bevy UI" category = "UI (User Interface)" wasm = true +[[example]] +name = "system_fonts" +path = "examples/ui/system_fonts.rs" +doc-scrape-examples = true + +[package.metadata.example.system_fonts] +name = "system_fonts" +description = "Demonstrates how to use system fonts" +category = "UI (User Interface)" +wasm = true + [[example]] name = "feathers" path = "examples/ui/feathers.rs" diff --git a/examples/README.md b/examples/README.md index 594eaf16081fe..487832ecb3543 100644 --- a/examples/README.md +++ b/examples/README.md @@ -614,6 +614,7 @@ Example | Description [Viewport Node](../examples/ui/viewport_node.rs) | Demonstrates how to create a viewport node with picking support [Virtual Keyboard](../examples/ui/virtual_keyboard.rs) | Example demonstrating a virtual keyboard widget [Window Fallthrough](../examples/ui/window_fallthrough.rs) | Illustrates how to access `winit::window::Window`'s `hittest` functionality. +[system_fonts](../examples/ui/system_fonts.rs) | Demonstrates how to use system fonts ### Usage diff --git a/examples/ui/system_fonts.rs b/examples/ui/system_fonts.rs new file mode 100644 index 0000000000000..f8aea3847e4e3 --- /dev/null +++ b/examples/ui/system_fonts.rs @@ -0,0 +1,111 @@ +//! This example displays a scrollable list of all available system fonts. +//! Demonstrates loading and querying system fonts via cosmic-text. + +use bevy::{ + diagnostic::FrameTimeDiagnosticsPlugin, input::mouse::MouseScrollUnit, prelude::*, + text::CosmicFontSystem, +}; + +fn main() { + let mut app = App::new(); + app.add_plugins((DefaultPlugins, FrameTimeDiagnosticsPlugin::default())) + .add_systems(Startup, setup); + + app.world_mut() + .resource_mut::() + .db_mut() + .load_system_fonts(); + + app.run(); +} + +fn setup(mut commands: Commands, font_system: Res) { + commands.spawn(Camera2d); + + commands + .spawn(( + Node { + flex_direction: FlexDirection::Column, + width: percent(100), + height: percent(100), + align_items: AlignItems::Center, + row_gap: px(10.), + ..default() + }, + BackgroundColor(Color::srgb(0.1, 0.1, 0.1)), + )) + .with_children(|builder| { + builder.spawn(Text::new(format!( + "Total available fonts: {}", + font_system.db().len(), + ))); + + builder + .spawn(Node { + flex_direction: FlexDirection::Column, + row_gap: px(6), + overflow: Overflow::scroll_y(), + align_items: AlignItems::Stretch, + ..default() + }) + .with_children(|builder| { + let mut families: Vec<(String, String)> = Vec::new(); + for face in font_system.db().faces() { + for (name, lang) in &face.families { + families.push((name.to_string(), lang.to_string())); + } + } + families.sort_unstable(); + families.dedup(); + for (family, language) in families { + builder.spawn(( + Node { + display: Display::Grid, + grid_template_columns: vec![ + GridTrack::flex(1.), + GridTrack::flex(1.), + GridTrack::flex(1.), + ], + padding: px(6).all(), + column_gap: px(50.), + ..default() + }, + BackgroundColor(Color::srgb(0.2, 0.2, 0.25)), + children![ + ( + Text::new(&family), + TextFont { + font: FontSource::Family(family.as_str().into()), + ..default() + }, + TextLayout::new_with_no_wrap() + ), + (Text::new(family), TextLayout::new_with_no_wrap()), + ( + Text::new(language), + TextLayout::new_with_no_wrap(), + Node { + justify_self: JustifySelf::End, + ..default() + } + ) + ], + )); + } + }) + .observe( + |on_scroll: On>, + mut query: Query<(&mut ScrollPosition, &ComputedNode)>| { + if let Ok((mut scroll_position, node)) = query.get_mut(on_scroll.entity) { + let dy = match on_scroll.unit { + MouseScrollUnit::Line => on_scroll.y * 20., + MouseScrollUnit::Pixel => on_scroll.y, + }; + let range = (node.content_size.y - node.size.y).max(0.) + * node.inverse_scale_factor; + scroll_position.y = (scroll_position.y - dy).clamp(0., range); + } + }, + ); + }); +}