Merge 03b5d3a2e7
into f964ee1e3a
This commit is contained in:
commit
4f50daf682
@ -117,19 +117,25 @@ impl Plugin for TextPlugin {
|
||||
.add_systems(
|
||||
PostUpdate,
|
||||
(
|
||||
remove_dropped_font_atlas_sets.before(AssetEventSystems),
|
||||
detect_text_needs_rerender::<Text2d>,
|
||||
update_text2d_layout
|
||||
// Potential conflict: `Assets<Image>`
|
||||
// In practice, they run independently since `bevy_render::camera_update_system`
|
||||
// will only ever observe its own render target, and `update_text2d_layout`
|
||||
// will never modify a pre-existing `Image` asset.
|
||||
.ambiguous_with(CameraUpdateSystems),
|
||||
calculate_bounds_text2d.in_set(VisibilitySystems::CalculateBounds),
|
||||
)
|
||||
.chain()
|
||||
.in_set(Text2dUpdateSystems)
|
||||
.after(AnimationSystems),
|
||||
(
|
||||
remove_dropped_font_atlas_sets.before(AssetEventSystems),
|
||||
detect_text_root_needs_rerender::<Text2d>,
|
||||
update_text2d_layout
|
||||
// Potential conflict: `Assets<Image>`
|
||||
// In practice, they run independently since `bevy_render::camera_update_system`
|
||||
// will only ever observe its own render target, and `update_text2d_layout`
|
||||
// will never modify a pre-existing `Image` asset.
|
||||
.ambiguous_with(CameraUpdateSystems),
|
||||
calculate_bounds_text2d.in_set(VisibilitySystems::CalculateBounds),
|
||||
)
|
||||
.chain()
|
||||
.in_set(Text2dUpdateSystems)
|
||||
.after(AnimationSystems),
|
||||
detect_text_span_needs_rerender
|
||||
.before(Text2dUpdateSystems)
|
||||
.ambiguous_with(CameraUpdateSystems)
|
||||
.after(AnimationSystems),
|
||||
),
|
||||
)
|
||||
.add_systems(Last, trim_cosmic_cache);
|
||||
|
||||
|
@ -76,7 +76,7 @@ impl ComputedTextBlock {
|
||||
|
||||
/// Indicates if the text needs to be refreshed in [`TextLayoutInfo`].
|
||||
///
|
||||
/// Updated automatically by [`detect_text_needs_rerender`] and cleared
|
||||
/// Updated automatically by [`detect_text_root_needs_rerender`] and [`detect_text_span_needs_rerender`], and cleared
|
||||
/// by [`TextPipeline`](crate::TextPipeline) methods.
|
||||
pub fn needs_rerender(&self) -> bool {
|
||||
self.needs_rerender
|
||||
@ -472,11 +472,10 @@ pub enum FontSmoothing {
|
||||
|
||||
/// System that detects changes to text blocks and sets `ComputedTextBlock::should_rerender`.
|
||||
///
|
||||
/// Generic over the root text component and text span component. For example, [`Text2d`](crate::Text2d)/[`TextSpan`] for
|
||||
/// 2d or `Text`/[`TextSpan`] for UI.
|
||||
pub fn detect_text_needs_rerender<Root: Component>(
|
||||
changed_roots: Query<
|
||||
Entity,
|
||||
/// Generic over the root text component.
|
||||
pub fn detect_text_root_needs_rerender<Root: Component>(
|
||||
mut changed_roots: Query<
|
||||
&mut ComputedTextBlock,
|
||||
(
|
||||
Or<(
|
||||
Changed<Root>,
|
||||
@ -489,6 +488,30 @@ pub fn detect_text_needs_rerender<Root: Component>(
|
||||
With<TextLayout>,
|
||||
),
|
||||
>,
|
||||
roots_without_computed_block: Query<Entity, (With<Root>, Without<ComputedTextBlock>)>,
|
||||
) {
|
||||
// Root entity:
|
||||
// - Root component changed.
|
||||
// - TextFont on root changed.
|
||||
// - TextLayout changed.
|
||||
// - Root children changed (can include additions and removals).
|
||||
for mut computed in changed_roots.iter_mut() {
|
||||
computed.needs_rerender = true;
|
||||
}
|
||||
|
||||
for entity in roots_without_computed_block.iter() {
|
||||
// If the root entity does not have a ComputedTextBlock, then it needs one.
|
||||
// This can happen if the root was spawned without a ComputedTextBlock, or if it was removed.
|
||||
once!(warn!(
|
||||
"found entity {} with a root text component ({}) that has no ComputedTextBlock; this warning only prints once",
|
||||
entity,
|
||||
core::any::type_name::<Root>()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// System that detects changes to text spans and sets `ComputedTextBlock::should_rerender`.
|
||||
pub fn detect_text_span_needs_rerender(
|
||||
changed_spans: Query<
|
||||
(Entity, Option<&ChildOf>, Has<TextLayout>),
|
||||
(
|
||||
@ -509,20 +532,6 @@ pub fn detect_text_needs_rerender<Root: Component>(
|
||||
Has<TextSpan>,
|
||||
)>,
|
||||
) {
|
||||
// Root entity:
|
||||
// - Root component changed.
|
||||
// - TextFont on root changed.
|
||||
// - TextLayout changed.
|
||||
// - Root children changed (can include additions and removals).
|
||||
for root in changed_roots.iter() {
|
||||
let Ok((_, Some(mut computed), _)) = computed.get_mut(root) else {
|
||||
once!(warn!("found entity {} with a root text component ({}) but no ComputedTextBlock; this warning only \
|
||||
prints once", root, core::any::type_name::<Root>()));
|
||||
continue;
|
||||
};
|
||||
computed.needs_rerender = true;
|
||||
}
|
||||
|
||||
// Span entity:
|
||||
// - Span component changed.
|
||||
// - Span TextFont changed.
|
||||
@ -530,16 +539,15 @@ pub fn detect_text_needs_rerender<Root: Component>(
|
||||
for (entity, maybe_span_child_of, has_text_block) in changed_spans.iter() {
|
||||
if has_text_block {
|
||||
once!(warn!("found entity {} with a TextSpan that has a TextLayout, which should only be on root \
|
||||
text entities (that have {}); this warning only prints once",
|
||||
entity, core::any::type_name::<Root>()));
|
||||
text entities; this warning only prints once",
|
||||
entity));
|
||||
}
|
||||
|
||||
let Some(span_child_of) = maybe_span_child_of else {
|
||||
once!(warn!(
|
||||
"found entity {} with a TextSpan that has no parent; it should have an ancestor \
|
||||
with a root text component ({}); this warning only prints once",
|
||||
entity,
|
||||
core::any::type_name::<Root>()
|
||||
with a root text component; this warning only prints once",
|
||||
entity
|
||||
));
|
||||
continue;
|
||||
};
|
||||
@ -568,9 +576,8 @@ pub fn detect_text_needs_rerender<Root: Component>(
|
||||
let Some(next_child_of) = maybe_child_of else {
|
||||
once!(warn!(
|
||||
"found entity {} with a TextSpan that has no ancestor with the root text \
|
||||
component ({}); this warning only prints once",
|
||||
component; this warning only prints once",
|
||||
entity,
|
||||
core::any::type_name::<Root>()
|
||||
));
|
||||
break;
|
||||
};
|
||||
|
@ -389,7 +389,9 @@ mod tests {
|
||||
use bevy_asset::{load_internal_binary_asset, Handle};
|
||||
use bevy_ecs::schedule::IntoScheduleConfigs;
|
||||
|
||||
use crate::{detect_text_needs_rerender, TextIterScratch};
|
||||
use crate::{
|
||||
detect_text_root_needs_rerender, detect_text_span_needs_rerender, TextIterScratch,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
@ -409,7 +411,8 @@ mod tests {
|
||||
.add_systems(
|
||||
Update,
|
||||
(
|
||||
detect_text_needs_rerender::<Text2d>,
|
||||
detect_text_root_needs_rerender::<Text2d>,
|
||||
detect_text_span_needs_rerender,
|
||||
update_text2d_layout,
|
||||
calculate_bounds_text2d,
|
||||
)
|
||||
|
@ -34,6 +34,7 @@ mod layout;
|
||||
mod stack;
|
||||
mod ui_node;
|
||||
|
||||
use bevy_text::detect_text_span_needs_rerender;
|
||||
pub use focus::*;
|
||||
pub use geometry::*;
|
||||
pub use gradients::*;
|
||||
@ -201,7 +202,7 @@ impl Plugin for UiPlugin {
|
||||
let ui_layout_system_config = ui_layout_system_config
|
||||
// Text and Text2D operate on disjoint sets of entities
|
||||
.ambiguous_with(bevy_text::update_text2d_layout)
|
||||
.ambiguous_with(bevy_text::detect_text_needs_rerender::<bevy_text::Text2d>);
|
||||
.ambiguous_with(bevy_text::detect_text_root_needs_rerender::<bevy_text::Text2d>);
|
||||
|
||||
app.add_systems(
|
||||
PostUpdate,
|
||||
@ -252,26 +253,27 @@ fn build_text_interop(app: &mut App) {
|
||||
PostUpdate,
|
||||
(
|
||||
(
|
||||
bevy_text::detect_text_needs_rerender::<Text>,
|
||||
bevy_text::detect_text_root_needs_rerender::<Text>,
|
||||
widget::measure_text_system,
|
||||
)
|
||||
.chain()
|
||||
.in_set(UiSystems::Content)
|
||||
// Text and Text2d are independent.
|
||||
.ambiguous_with(bevy_text::detect_text_needs_rerender::<bevy_text::Text2d>)
|
||||
.ambiguous_with(bevy_text::detect_text_root_needs_rerender::<bevy_text::Text2d>)
|
||||
// Potential conflict: `Assets<Image>`
|
||||
// Since both systems will only ever insert new [`Image`] assets,
|
||||
// they will never observe each other's effects.
|
||||
.ambiguous_with(bevy_text::update_text2d_layout)
|
||||
// We assume Text is on disjoint UI entities to ImageNode and UiTextureAtlasImage
|
||||
// FIXME: Add an archetype invariant for this https://github.com/bevyengine/bevy/issues/1481.
|
||||
.ambiguous_with(widget::update_image_content_size_system),
|
||||
.ambiguous_with(widget::update_image_content_size_system)
|
||||
.after(detect_text_span_needs_rerender),
|
||||
widget::text_system
|
||||
.in_set(UiSystems::PostLayout)
|
||||
.after(bevy_text::remove_dropped_font_atlas_sets)
|
||||
.before(bevy_asset::AssetEventSystems)
|
||||
// Text2d and bevy_ui text are entirely on separate entities
|
||||
.ambiguous_with(bevy_text::detect_text_needs_rerender::<bevy_text::Text2d>)
|
||||
.ambiguous_with(bevy_text::detect_text_root_needs_rerender::<bevy_text::Text2d>)
|
||||
.ambiguous_with(bevy_text::update_text2d_layout)
|
||||
.ambiguous_with(bevy_text::calculate_bounds_text2d),
|
||||
),
|
||||
|
@ -111,7 +111,7 @@ fn main() {
|
||||
}
|
||||
|
||||
if args.recompute_text {
|
||||
app.add_systems(Update, |mut text_query: Query<&mut Text>| {
|
||||
app.add_systems(Update, |mut text_query: Query<&mut TextSpan>| {
|
||||
text_query
|
||||
.iter_mut()
|
||||
.for_each(|mut text| text.set_changed());
|
||||
|
Loading…
Reference in New Issue
Block a user