diff --git a/crates/bevy_ui/src/lib.rs b/crates/bevy_ui/src/lib.rs index 6aafd6dce8..8bb1bd20a5 100644 --- a/crates/bevy_ui/src/lib.rs +++ b/crates/bevy_ui/src/lib.rs @@ -12,8 +12,6 @@ pub mod widget; use bevy_derive::{Deref, DerefMut}; use bevy_reflect::Reflect; #[cfg(feature = "bevy_text")] -use bevy_text::TextLayoutInfo; -#[cfg(feature = "bevy_text")] mod accessibility; mod focus; mod geometry; @@ -40,8 +38,6 @@ pub mod prelude { }; } -#[cfg(feature = "bevy_text")] -use crate::widget::TextFlags; use bevy_app::prelude::*; use bevy_ecs::prelude::*; use bevy_input::InputSystem; @@ -81,6 +77,14 @@ impl Default for UiScale { } } +// Marks systems that can be ambiguous with [`widget::text_system`] if the `bevy_text` feature is enabled. +// See https://github.com/bevyengine/bevy/pull/11391 for more details. +#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)] +struct AmbiguousWithTextSystem; + +#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)] +struct AmbiguousWithUpdateText2DLayout; + impl Plugin for UiPlugin { fn build(&self, app: &mut App) { app.init_resource::() @@ -129,51 +133,6 @@ impl Plugin for UiPlugin { ui_focus_system.in_set(UiSystem::Focus).after(InputSystem), ); - #[cfg(feature = "bevy_text")] - app.register_type::() - .register_type::(); - // add these systems to front because these must run before transform update systems - #[cfg(feature = "bevy_text")] - app.add_systems( - PostUpdate, - ( - widget::measure_text_system - .before(UiSystem::Layout) - // Potential conflict: `Assets` - // In practice, they run independently since `bevy_render::camera_update_system` - // will only ever observe its own render target, and `widget::measure_text_system` - // will never modify a pre-existing `Image` asset. - .ambiguous_with(bevy_render::camera::CameraUpdateSystem) - // Potential conflict: `Assets` - // 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 UiImage and UiTextureAtlasImage - // FIXME: Add an archetype invariant for this https://github.com/bevyengine/bevy/issues/1481. - .ambiguous_with(widget::update_image_content_size_system), - widget::text_system - .after(UiSystem::Layout) - .after(bevy_text::remove_dropped_font_atlas_sets) - // Text2d and bevy_ui text are entirely on separate entities - .ambiguous_with(bevy_text::update_text2d_layout), - ), - ); - #[cfg(feature = "bevy_text")] - app.add_plugins(accessibility::AccessibilityPlugin); - app.add_systems(PostUpdate, { - let system = widget::update_image_content_size_system.before(UiSystem::Layout); - // Potential conflicts: `Assets` - // They run independently since `widget::image_node_system` will only ever observe - // its own UiImage, and `widget::text_system` & `bevy_text::update_text2d_layout` - // will never modify a pre-existing `Image` asset. - #[cfg(feature = "bevy_text")] - let system = system - .ambiguous_with(bevy_text::update_text2d_layout) - .ambiguous_with(widget::text_system); - - system - }); - app.add_systems( PostUpdate, ( @@ -189,18 +148,29 @@ impl Plugin for UiPlugin { .after(UiSystem::Layout) // clipping doesn't care about outlines .ambiguous_with(update_clipping_system) - .ambiguous_with(widget::text_system), + .in_set(AmbiguousWithTextSystem), ui_stack_system .in_set(UiSystem::Stack) // the systems don't care about stack index .ambiguous_with(update_clipping_system) .ambiguous_with(resolve_outlines_system) .ambiguous_with(ui_layout_system) - .ambiguous_with(widget::text_system), + .in_set(AmbiguousWithTextSystem), update_clipping_system.after(TransformSystem::TransformPropagate), + // Potential conflicts: `Assets` + // They run independently since `widget::image_node_system` will only ever observe + // its own UiImage, and `widget::text_system` & `bevy_text::update_text2d_layout` + // will never modify a pre-existing `Image` asset. + widget::update_image_content_size_system + .before(UiSystem::Layout) + .in_set(AmbiguousWithTextSystem) + .in_set(AmbiguousWithUpdateText2DLayout), ), ); + #[cfg(feature = "bevy_text")] + build_text_interop(app); + build_ui_render(app); } @@ -212,3 +182,50 @@ impl Plugin for UiPlugin { render_app.init_resource::(); } } + +/// A function that should be called from [`UiPlugin::build`] when [`bevy_text`] is enabled. +#[cfg(feature = "bevy_text")] +fn build_text_interop(app: &mut App) { + use crate::widget::TextFlags; + use bevy_text::TextLayoutInfo; + + app.register_type::() + .register_type::(); + + app.add_systems( + PostUpdate, + ( + widget::measure_text_system + .before(UiSystem::Layout) + // Potential conflict: `Assets` + // In practice, they run independently since `bevy_render::camera_update_system` + // will only ever observe its own render target, and `widget::measure_text_system` + // will never modify a pre-existing `Image` asset. + .ambiguous_with(bevy_render::camera::CameraUpdateSystem) + // Potential conflict: `Assets` + // 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 UiImage and UiTextureAtlasImage + // FIXME: Add an archetype invariant for this https://github.com/bevyengine/bevy/issues/1481. + .ambiguous_with(widget::update_image_content_size_system), + widget::text_system + .after(UiSystem::Layout) + .after(bevy_text::remove_dropped_font_atlas_sets) + // Text2d and bevy_ui text are entirely on separate entities + .ambiguous_with(bevy_text::update_text2d_layout), + ), + ); + + app.add_plugins(accessibility::AccessibilityPlugin); + + app.configure_sets( + PostUpdate, + AmbiguousWithTextSystem.ambiguous_with(widget::text_system), + ); + + app.configure_sets( + PostUpdate, + AmbiguousWithUpdateText2DLayout.ambiguous_with(bevy_text::update_text2d_layout), + ); +} diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 7daf85408c..d8f26f95d1 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -14,9 +14,9 @@ pub use render_pass::*; pub use ui_material_pipeline::*; use crate::{ - BackgroundColor, BorderColor, CalculatedClip, ContentSize, Node, Style, UiImage, UiScale, Val, + BackgroundColor, BorderColor, CalculatedClip, ContentSize, DefaultUiCamera, Node, Outline, + Style, TargetCamera, UiImage, UiScale, Val, }; -use crate::{DefaultUiCamera, Outline, TargetCamera}; use bevy_app::prelude::*; use bevy_asset::{load_internal_asset, AssetEvent, AssetId, Assets, Handle}; @@ -34,7 +34,6 @@ use bevy_render::{ view::{ExtractedView, ViewUniforms}, Extract, RenderApp, RenderSet, }; -#[cfg(feature = "bevy_text")] use bevy_sprite::TextureAtlasLayout; #[cfg(feature = "bevy_text")] use bevy_text::{PositionedGlyph, Text, TextLayoutInfo}; diff --git a/crates/bevy_ui/src/widget/image.rs b/crates/bevy_ui/src/widget/image.rs index 715b5f829a..f3758b5643 100644 --- a/crates/bevy_ui/src/widget/image.rs +++ b/crates/bevy_ui/src/widget/image.rs @@ -1,14 +1,6 @@ use crate::{measurement::AvailableSpace, ContentSize, Measure, Node, UiImage, UiScale}; use bevy_asset::Assets; - -use bevy_ecs::change_detection::DetectChanges; -use bevy_ecs::query::Without; -use bevy_ecs::{ - prelude::Component, - query::With, - reflect::ReflectComponent, - system::{Local, Query, Res}, -}; +use bevy_ecs::prelude::*; use bevy_math::Vec2; use bevy_reflect::{std_traits::ReflectDefault, Reflect}; use bevy_render::texture::Image;