Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ui/src/lib.rs
6598 views
1
#![expect(missing_docs, reason = "Not all docs are written yet, see #3492.")]
2
#![cfg_attr(docsrs, feature(doc_auto_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
8
//! This crate contains Bevy's UI system, which can be used to create UI for both 2D and 3D games
9
//! # Basic usage
10
//! Spawn UI elements with [`widget::Button`], [`ImageNode`](widget::ImageNode), [`Text`](prelude::Text) and [`Node`]
11
//! This UI is laid out with the Flexbox and CSS Grid layout models (see <https://cssreference.io/flexbox/>)
12
13
pub mod interaction_states;
14
pub mod measurement;
15
pub mod update;
16
pub mod widget;
17
18
pub mod gradients;
19
#[cfg(feature = "bevy_ui_picking_backend")]
20
pub mod picking_backend;
21
pub mod ui_transform;
22
23
use bevy_derive::{Deref, DerefMut};
24
#[cfg(feature = "bevy_ui_picking_backend")]
25
use bevy_picking::PickingSystems;
26
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
27
mod accessibility;
28
// This module is not re-exported, but is instead made public.
29
// This is intended to discourage accidental use of the experimental API.
30
pub mod experimental;
31
mod focus;
32
mod geometry;
33
mod layout;
34
mod stack;
35
mod ui_node;
36
37
pub use focus::*;
38
pub use geometry::*;
39
pub use gradients::*;
40
pub use interaction_states::{Checkable, Checked, InteractionDisabled, Pressed};
41
pub use layout::*;
42
pub use measurement::*;
43
pub use ui_node::*;
44
pub use ui_transform::*;
45
46
/// The UI prelude.
47
///
48
/// This includes the most common types in this crate, re-exported for your convenience.
49
pub 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` re-exports for texture slicing
66
bevy_sprite::{BorderRect, SliceScaleMode, SpriteImageMode, TextureSlicer},
67
bevy_text::TextBackgroundColor,
68
};
69
}
70
71
use bevy_app::{prelude::*, AnimationSystems, HierarchyPropagatePlugin, PropagateSet};
72
use bevy_camera::CameraUpdateSystems;
73
use bevy_ecs::prelude::*;
74
use bevy_input::InputSystems;
75
use bevy_transform::TransformSystems;
76
use layout::ui_surface::UiSurface;
77
use stack::ui_stack_system;
78
pub use stack::UiStack;
79
use update::{propagate_ui_target_cameras, update_clipping_system};
80
81
/// The basic plugin for Bevy UI
82
#[derive(Default)]
83
pub struct UiPlugin;
84
85
/// The label enum labeling the types of systems in the Bevy UI
86
#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)]
87
pub enum UiSystems {
88
/// After this label, input interactions with UI entities have been updated for this frame.
89
///
90
/// Runs in [`PreUpdate`].
91
Focus,
92
/// All UI systems in [`PostUpdate`] will run in or after this label.
93
Prepare,
94
/// Propagate UI component values needed by layout.
95
Propagate,
96
/// Update content requirements before layout.
97
Content,
98
/// After this label, the ui layout state has been updated.
99
///
100
/// Runs in [`PostUpdate`].
101
Layout,
102
/// UI systems ordered after [`UiSystems::Layout`].
103
///
104
/// Runs in [`PostUpdate`].
105
PostLayout,
106
/// After this label, the [`UiStack`] resource has been updated.
107
///
108
/// Runs in [`PostUpdate`].
109
Stack,
110
}
111
112
/// Deprecated alias for [`UiSystems`].
113
#[deprecated(since = "0.17.0", note = "Renamed to `UiSystems`.")]
114
pub type UiSystem = UiSystems;
115
116
/// The current scale of the UI.
117
///
118
/// A multiplier to fixed-sized ui values.
119
/// **Note:** This will only affect fixed ui values like [`Val::Px`]
120
#[derive(Debug, Reflect, Resource, Deref, DerefMut)]
121
#[reflect(Resource, Debug, Default)]
122
pub struct UiScale(pub f32);
123
124
impl Default for UiScale {
125
fn default() -> Self {
126
Self(1.0)
127
}
128
}
129
130
// Marks systems that can be ambiguous with [`widget::text_system`] if the `bevy_text` feature is enabled.
131
// See https://github.com/bevyengine/bevy/pull/11391 for more details.
132
#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)]
133
struct AmbiguousWithText;
134
135
#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)]
136
struct AmbiguousWithUpdateText2dLayout;
137
138
impl 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
// Text and Text2D operate on disjoint sets of entities
187
.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
// These systems don't care about stack index
198
.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
// Potential conflicts: `Assets<Image>`
205
// They run independently since `widget::image_node_system` will only ever observe
206
// its own ImageNode, and `widget::text_system` & `bevy_text::update_text2d_layout`
207
// will never modify a pre-existing `Image` asset.
208
widget::update_image_content_size_system
209
.in_set(UiSystems::Content)
210
.in_set(AmbiguousWithText)
211
.in_set(AmbiguousWithUpdateText2dLayout),
212
// Potential conflicts: `Assets<Image>`
213
// `widget::text_system` and `bevy_text::update_text2d_layout` run independently
214
// since this system will only ever update viewport images.
215
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
226
fn 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
// Text and Text2d are independent.
239
.ambiguous_with(bevy_text::detect_text_needs_rerender::<bevy_sprite::Text2d>)
240
// Potential conflict: `Assets<Image>`
241
// Since both systems will only ever insert new [`Image`] assets,
242
// they will never observe each other's effects.
243
.ambiguous_with(bevy_sprite::update_text2d_layout)
244
// We assume Text is on disjoint UI entities to ImageNode and UiTextureAtlasImage
245
// FIXME: Add an archetype invariant for this https://github.com/bevyengine/bevy/issues/1481.
246
.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
// Text2d and bevy_ui text are entirely on separate entities
252
.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
}
277
278