mirror of
https://github.com/bevyengine/bevy.git
synced 2026-06-29 23:35:35 -04:00
457b91808a
# Objective - When `FontSource` resolution fails because an asset isn't yet loaded, it doesn't attempt to reresolve the `FontSource` again the next frame. - When a `Font` asset is removed, its font data is not unloaded from Parley's font database - The results from font lookups can be inconsistant when using `Handle`s to identify a font. Fixes #24356 ## Solution * In `load_font_assets_into_font_collection`, register each font twice, once with an internal asset-specific alias for handle lookups and once using its embedded family name. * Use `set_changed` on `TextFont` to trigger chain detection, instead of the `needs_rerender` flag on `TextBlock`. Schedule `load_font_assets_into_collection` to run before `detect_text_needs_rerender`, otherwise this would delay updates for a frame. * Store the changed family ids and asset paths, and set any `TextFont`s that refer to them as changed. * Don't update the measure funcs in `update_editable_text_content_size` on font asset changes. Instead rely on the narrower `TextFont` change detection, which is sufficient now because `load_font_assets_into_font_collection` marks affected `TextFont` components as changed when newly loaded font assets can affect font resolution. * Removed the mutable deref of `EditableText` at the start of `update_editable_text_styles`. The editor is only mutable accessed if updates to the styles need to be made. * On unloading a font rebuild the whole font database, minus the unloaded fonts, remap any generic families and relayout all text. * Keep a copy of the registered generic families in `FontCx`, so they can be remapped after unloading a font. ## Testing ```rust use bevy::{ feathers::{controls::FeathersNumberInput, FeathersPlugins}, prelude::*, }; fn main() { App::new() .add_plugins((DefaultPlugins, FeathersPlugins)) .add_systems(Startup, setup) .add_systems(Update, spawn_number_input) .run(); } fn setup(mut commands: Commands) { // ui camera commands.spawn(Camera2d); } fn spawn_number_input(mut commands: Commands, mut is_spawned: Local<bool>) { if *is_spawned { return; } *is_spawned = true; commands.spawn_scene(bsn! { Node { margin: UiRect::all(auto()) } Outline Children [ :FeathersNumberInput Node { width: px(200) } ] }); } ``` --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
97 lines
3.6 KiB
Rust
97 lines
3.6 KiB
Rust
//! This example displays a scrollable list of all available system fonts.
|
|
//! Demonstrates querying system fonts via `FontCx`.
|
|
|
|
use bevy::{
|
|
diagnostic::FrameTimeDiagnosticsPlugin, input::mouse::MouseScrollUnit, prelude::*, text::FontCx,
|
|
};
|
|
|
|
fn main() {
|
|
let mut app = App::new();
|
|
app.add_plugins((DefaultPlugins, FrameTimeDiagnosticsPlugin::default()))
|
|
.add_systems(Startup, setup);
|
|
|
|
app.run();
|
|
}
|
|
|
|
fn setup(mut commands: Commands, mut font_system: ResMut<FontCx>) {
|
|
let mut families: Vec<String> = font_system
|
|
.context
|
|
.collection
|
|
.family_names()
|
|
.map(ToOwned::to_owned)
|
|
.collect();
|
|
families.sort_unstable();
|
|
families.dedup();
|
|
let family_count = families.len();
|
|
|
|
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(move |builder| {
|
|
builder.spawn(Text::new(format!(
|
|
"Total available fonts: {}",
|
|
family_count,
|
|
)));
|
|
|
|
builder
|
|
.spawn(Node {
|
|
flex_direction: FlexDirection::Column,
|
|
row_gap: px(6),
|
|
overflow: Overflow::scroll_y(),
|
|
align_items: AlignItems::Stretch,
|
|
..default()
|
|
})
|
|
.with_children(|builder| {
|
|
for family in families {
|
|
let font = FontSource::Family(family.clone().into());
|
|
builder.spawn((
|
|
Node {
|
|
display: Display::Grid,
|
|
grid_template_columns: vec![
|
|
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, ..default() },
|
|
TextLayout::no_wrap()
|
|
),
|
|
(Text::new(family), TextLayout::no_wrap()),
|
|
],
|
|
));
|
|
}
|
|
})
|
|
.observe(
|
|
|on_scroll: On<Pointer<Scroll>>,
|
|
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);
|
|
}
|
|
},
|
|
);
|
|
});
|
|
}
|