1#![expect(missing_docs, reason = "Not all docs are written yet, see #3492.")]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![doc(
4 html_logo_url = "https://bevy.org/assets/icon.png",
5 html_favicon_url = "https://bevy.org/assets/icon.png"
6)]
7
8pub mod interaction_states;
14pub mod measurement;
15pub mod update;
16pub mod widget;
17
18pub mod gradients;
19#[cfg(feature = "bevy_ui_picking_backend")]
20pub mod picking_backend;
21pub mod ui_transform;
22
23use bevy_derive::{Deref, DerefMut};
24#[cfg(feature = "bevy_ui_picking_backend")]
25use bevy_picking::PickingSystems;
26use bevy_reflect::{std_traits::ReflectDefault, Reflect};
27mod accessibility;
28pub mod experimental;
31mod focus;
32mod geometry;
33mod layout;
34mod stack;
35mod ui_node;
36
37pub use focus::*;
38pub use geometry::*;
39pub use gradients::*;
40pub use interaction_states::{Checkable, Checked, InteractionDisabled, Pressed};
41pub use layout::*;
42pub use measurement::*;
43pub use ui_node::*;
44pub use ui_transform::*;
45
46pub mod prelude {
50 #[doc(hidden)]
51 #[cfg(feature = "bevy_ui_picking_backend")]
52 pub use crate::picking_backend::{UiPickingCamera, UiPickingPlugin, UiPickingSettings};
53 #[doc(hidden)]
54 pub use crate::widget::{Text, TextShadow, TextUiReader, TextUiWriter};
55 #[doc(hidden)]
56 pub use {
57 crate::{
58 geometry::*,
59 gradients::*,
60 ui_node::*,
61 ui_transform::*,
62 widget::{Button, ImageNode, Label, NodeImageMode, ViewportNode},
63 Interaction, UiScale,
64 },
65 bevy_sprite::{BorderRect, SliceScaleMode, SpriteImageMode, TextureSlicer},
67 bevy_text::TextBackgroundColor,
68 };
69}
70
71use bevy_app::{prelude::*, AnimationSystems, HierarchyPropagatePlugin, PropagateSet};
72use bevy_camera::CameraUpdateSystems;
73use bevy_ecs::prelude::*;
74use bevy_input::InputSystems;
75use bevy_transform::TransformSystems;
76use layout::ui_surface::UiSurface;
77use stack::ui_stack_system;
78pub use stack::UiStack;
79use update::{propagate_ui_target_cameras, update_clipping_system};
80
81#[derive(Default)]
83pub struct UiPlugin;
84
85#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)]
87pub enum UiSystems {
88 Focus,
92 Prepare,
94 Propagate,
96 Content,
98 Layout,
102 PostLayout,
106 Stack,
110}
111
112#[deprecated(since = "0.17.0", note = "Renamed to `UiSystems`.")]
114pub type UiSystem = UiSystems;
115
116#[derive(Debug, Reflect, Resource, Deref, DerefMut)]
121#[reflect(Resource, Debug, Default)]
122pub struct UiScale(pub f32);
123
124impl Default for UiScale {
125 fn default() -> Self {
126 Self(1.0)
127 }
128}
129
130#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)]
133struct AmbiguousWithText;
134
135#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)]
136struct AmbiguousWithUpdateText2dLayout;
137
138impl Plugin for UiPlugin {
139 fn build(&self, app: &mut App) {
140 app.init_resource::<UiSurface>()
141 .init_resource::<UiScale>()
142 .init_resource::<UiStack>()
143 .configure_sets(
144 PostUpdate,
145 (
146 CameraUpdateSystems,
147 UiSystems::Prepare.after(AnimationSystems),
148 UiSystems::Propagate,
149 UiSystems::Content,
150 UiSystems::Layout,
151 UiSystems::PostLayout,
152 )
153 .chain(),
154 )
155 .configure_sets(
156 PostUpdate,
157 PropagateSet::<ComputedUiTargetCamera>::default().in_set(UiSystems::Propagate),
158 )
159 .add_plugins(HierarchyPropagatePlugin::<ComputedUiTargetCamera>::new(
160 PostUpdate,
161 ))
162 .configure_sets(
163 PostUpdate,
164 PropagateSet::<ComputedUiRenderTargetInfo>::default().in_set(UiSystems::Propagate),
165 )
166 .add_plugins(HierarchyPropagatePlugin::<ComputedUiRenderTargetInfo>::new(
167 PostUpdate,
168 ))
169 .add_systems(
170 PreUpdate,
171 ui_focus_system.in_set(UiSystems::Focus).after(InputSystems),
172 );
173
174 #[cfg(feature = "bevy_ui_picking_backend")]
175 app.add_plugins(picking_backend::UiPickingPlugin)
176 .add_systems(
177 First,
178 widget::viewport_picking.in_set(PickingSystems::PostInput),
179 );
180
181 let ui_layout_system_config = ui_layout_system
182 .in_set(UiSystems::Layout)
183 .before(TransformSystems::Propagate);
184
185 let ui_layout_system_config = ui_layout_system_config
186 .ambiguous_with(bevy_sprite::update_text2d_layout)
188 .ambiguous_with(bevy_text::detect_text_needs_rerender::<bevy_sprite::Text2d>);
189
190 app.add_systems(
191 PostUpdate,
192 (
193 propagate_ui_target_cameras.in_set(UiSystems::Prepare),
194 ui_layout_system_config,
195 ui_stack_system
196 .in_set(UiSystems::Stack)
197 .ambiguous_with(widget::measure_text_system)
199 .ambiguous_with(update_clipping_system)
200 .ambiguous_with(ui_layout_system)
201 .ambiguous_with(widget::update_viewport_render_target_size)
202 .in_set(AmbiguousWithText),
203 update_clipping_system.after(TransformSystems::Propagate),
204 widget::update_image_content_size_system
209 .in_set(UiSystems::Content)
210 .in_set(AmbiguousWithText)
211 .in_set(AmbiguousWithUpdateText2dLayout),
212 widget::update_viewport_render_target_size
216 .in_set(UiSystems::PostLayout)
217 .in_set(AmbiguousWithText)
218 .in_set(AmbiguousWithUpdateText2dLayout),
219 ),
220 );
221
222 build_text_interop(app);
223 }
224}
225
226fn build_text_interop(app: &mut App) {
227 use widget::Text;
228
229 app.add_systems(
230 PostUpdate,
231 (
232 (
233 bevy_text::detect_text_needs_rerender::<Text>,
234 widget::measure_text_system,
235 )
236 .chain()
237 .in_set(UiSystems::Content)
238 .ambiguous_with(bevy_text::detect_text_needs_rerender::<bevy_sprite::Text2d>)
240 .ambiguous_with(bevy_sprite::update_text2d_layout)
244 .ambiguous_with(widget::update_image_content_size_system),
247 widget::text_system
248 .in_set(UiSystems::PostLayout)
249 .after(bevy_text::remove_dropped_font_atlas_sets)
250 .before(bevy_asset::AssetEventSystems)
251 .ambiguous_with(bevy_text::detect_text_needs_rerender::<bevy_sprite::Text2d>)
253 .ambiguous_with(bevy_sprite::update_text2d_layout)
254 .ambiguous_with(bevy_sprite::calculate_bounds_text2d),
255 ),
256 );
257
258 app.add_plugins(accessibility::AccessibilityPlugin);
259
260 app.add_observer(interaction_states::on_add_disabled)
261 .add_observer(interaction_states::on_remove_disabled)
262 .add_observer(interaction_states::on_add_checkable)
263 .add_observer(interaction_states::on_remove_checkable)
264 .add_observer(interaction_states::on_add_checked)
265 .add_observer(interaction_states::on_remove_checked);
266
267 app.configure_sets(
268 PostUpdate,
269 AmbiguousWithText.ambiguous_with(widget::text_system),
270 );
271
272 app.configure_sets(
273 PostUpdate,
274 AmbiguousWithUpdateText2dLayout.ambiguous_with(bevy_sprite::update_text2d_layout),
275 );
276}