bevy_ui_dsl/
widgets.rs

1use bevy_asset::AssetServer;
2use bevy_ecs::prelude::Bundle;
3use bevy_text::{TextStyle, TextSection};
4use bevy_ecs::entity::Entity;
5use bevy_ecs::system::Commands;
6use bevy_ui::{Val, FlexWrap, Style, JustifyContent, AlignItems};
7use bevy_ui::node_bundles::{NodeBundle, TextBundle, ButtonBundle, ImageBundle};
8use bevy_hierarchy::BuildChildren;
9use super::{Class, AssetClass, UiChildBuilder};
10
11
12/// Spawns a [`NodeBundle`] as the root with children.
13pub fn root(
14    class: impl Class<NodeBundle>,
15    assets: &AssetServer,
16    commands: &mut Commands,
17    children: impl FnOnce(&mut UiChildBuilder)
18) -> Entity {
19    rooti(class, assets, commands, (), children)
20}
21
22/// Spawns a [`NodeBundle`] as the root with children.
23pub fn rooti(
24    class: impl Class<NodeBundle>,
25    assets: &AssetServer,
26    commands: &mut Commands,
27    extras: impl Bundle,
28    children: impl FnOnce(&mut UiChildBuilder)
29) -> Entity {
30    let mut bundle = NodeBundle::default();
31    class.apply(&mut bundle);
32    commands
33        .spawn((bundle, extras))
34        .with_children(|builder| {
35            children(&mut UiChildBuilder {
36                builder,
37                assets
38            });
39        })
40        .id()
41}
42
43
44/// Spawns a clear [`NodeBundle`] that takes up the full space of its parent.
45/// Often required for embedding other widgets after the initial widget is spawned.
46pub fn blank(
47    parent: Entity,
48    class: impl Class<NodeBundle>,
49    assets: &AssetServer,
50    commands: &mut Commands,
51    children: impl FnOnce(&mut UiChildBuilder)
52) -> Entity {
53    blanki(parent, class, assets, commands, (), children)
54}
55
56/// Spawns a clear [`NodeBundle`] that takes up the full space of its parent.
57/// Often required for embedding other widgets after the initial widget is spawned.
58pub fn blanki(
59    parent: Entity,
60    class: impl Class<NodeBundle>,
61    assets: &AssetServer,
62    commands: &mut Commands,
63    extras: impl Bundle,
64    children: impl FnOnce(&mut UiChildBuilder)
65) -> Entity {
66    commands
67        .entity(parent)
68        .with_children(|builder| {
69            let mut bundle = NodeBundle::default();
70            class.apply(&mut bundle);
71            let mut builder = UiChildBuilder { builder, assets };
72            builder.spawn((bundle, extras)).with_children(children);
73        })
74        .id()
75}
76
77/// Spawns a [`NodeBundle`] with children.
78pub fn node(
79    class: impl Class<NodeBundle>,
80    parent: &mut UiChildBuilder,
81    children: impl FnOnce(&mut UiChildBuilder)
82) -> Entity {
83    nodei(class, (), parent, children)
84}
85
86
87/// Spawns a [`NodeBundle`] with children.
88pub fn nodei(
89    class: impl Class<NodeBundle>,
90    extras: impl Bundle,
91    parent: &mut UiChildBuilder,
92    children: impl FnOnce(&mut UiChildBuilder)
93) -> Entity {
94    let mut bundle = NodeBundle::default();
95    class.apply(&mut bundle);
96    
97    let mut commands = parent.spawn(bundle);
98    commands.insert(extras);
99    commands.with_children(children).id()
100}
101
102/// Spawns a [`TextBundle`].
103pub fn text(
104    text: impl Into<String>,
105    class: impl AssetClass<TextBundle>,
106    text_class: impl AssetClass<TextStyle>,
107    parent: &mut UiChildBuilder
108) -> Entity {
109    texti(text, class, text_class, (), parent)
110}
111
112/// Spawns a [`TextBundle`].
113pub fn texti(
114    text: impl Into<String>,
115    class: impl AssetClass<TextBundle>,
116    text_class: impl AssetClass<TextStyle>,
117    extras: impl Bundle,
118    parent: &mut UiChildBuilder
119) -> Entity {
120    let mut bundle = TextBundle::default();
121    class.apply(parent.assets, &mut bundle);
122    let sections = &mut bundle.text.sections;
123    let mut style = TextStyle::default();
124    text_class.apply(parent.assets, &mut style);
125    sections.push(TextSection {
126        value: text.into(),
127        style,
128    });
129    parent.spawn((bundle, extras)).id()
130}
131
132/// Spawns a [`ButtonBundle`] with children.
133pub fn button(
134    class: impl AssetClass<ButtonBundle>,
135    parent: &mut UiChildBuilder,
136    children: impl FnOnce(&mut UiChildBuilder)
137) -> Entity {
138    buttoni(class, (), parent, children)
139}
140
141/// Spawns a [`ButtonBundle`] with children.
142pub fn buttoni(
143    class: impl AssetClass<ButtonBundle>,
144    extras: impl Bundle,
145    parent: &mut UiChildBuilder,
146    children: impl FnOnce(&mut UiChildBuilder)
147) -> Entity {
148    let mut bundle = ButtonBundle::default();
149    class.apply(parent.assets, &mut bundle);
150    parent
151        .spawn((bundle, extras))
152        .with_children(children).id()
153}
154
155/// Spawns a [`ButtonBundle`] without children.
156pub fn simple_button(
157    class: impl AssetClass<ButtonBundle>,
158    parent: &mut UiChildBuilder
159) -> Entity {
160    simple_buttoni(class, (), parent)
161}
162
163/// Spawns a [`ButtonBundle`] without children.
164pub fn simple_buttoni(
165    class: impl AssetClass<ButtonBundle>,
166    extras: impl Bundle,
167    parent: &mut UiChildBuilder
168) -> Entity {
169    let mut bundle = ButtonBundle::default();
170    class.apply(parent.assets, &mut bundle);
171    parent.spawn((bundle, extras)).id()
172}
173
174/// Spawns a [`ButtonBundle`] with a single [`TextBundle`] as its child.
175pub fn text_button(
176    txt: impl Into<String>,
177    class: impl AssetClass<ButtonBundle>,
178    text_style: impl AssetClass<TextStyle>,
179    parent: &mut UiChildBuilder
180) -> Entity {
181    text_buttoni(txt, class, text_style, (), parent)
182}
183
184/// Spawns a [`ButtonBundle`] with a single [`TextBundle`] as its child.
185pub fn text_buttoni(
186    txt: impl Into<String>,
187    class: impl AssetClass<ButtonBundle>,
188    text_style: impl AssetClass<TextStyle>,
189    extras: impl Bundle,
190    parent: &mut UiChildBuilder
191) -> Entity {
192    buttoni(class, extras, parent, |p| {
193        text(txt, (), text_style, p);
194    })
195}
196
197/// Spawns an [`ImageBundle`].
198pub fn image(
199    class: impl AssetClass<ImageBundle>,
200    parent: &mut UiChildBuilder
201) -> Entity {
202    imagei(class, (), parent)
203}
204
205/// Spawns an [`ImageBundle`].
206pub fn imagei(
207    class: impl AssetClass<ImageBundle>,
208    extras: impl Bundle,
209    parent: &mut UiChildBuilder
210) -> Entity {
211    let mut bundle = ImageBundle::default();
212    class.apply(parent.assets, &mut bundle);
213    parent.spawn((bundle, extras)).id()
214}
215
216/// Spawns an [`ImageBundle`] with children.
217pub fn image_pane(
218    class: impl AssetClass<ImageBundle>,
219    parent: &mut UiChildBuilder,
220    children: impl FnOnce(&mut UiChildBuilder)
221) -> Entity {
222    image_panei(class, parent, (), children)
223}
224
225/// Spawns an [`ImageBundle`] with children.
226pub fn image_panei(
227    class: impl AssetClass<ImageBundle>,
228    parent: &mut UiChildBuilder,
229    extras: impl Bundle,
230    children: impl FnOnce(&mut UiChildBuilder)
231) -> Entity {
232    let mut bundle = ImageBundle::default();
233    class.apply(parent.assets, &mut bundle);
234    parent
235        .spawn((bundle, extras))
236        .with_children(children).id()
237}
238
239/// Spawns a [`NodeBundle`] composed of [`NodeBundle`] cells in the form of a grid.
240/// The callback function argument spawns the contents of those cells.
241pub fn grid(
242    rows: usize,
243    columns: usize,
244    class: impl Class<NodeBundle>,
245    parent: &mut UiChildBuilder,
246    children: impl FnMut(&mut UiChildBuilder, usize, usize)
247) -> Entity {
248    gridi(rows, columns, class, (), parent, children)
249}
250
251/// Spawns a [`NodeBundle`] composed of [`NodeBundle`] cells in the form of a grid.
252/// The callback function argument spawns the contents of those cells.
253pub fn gridi(
254    rows: usize,
255    columns: usize,
256    class: impl Class<NodeBundle>,
257    extras: impl Bundle,
258    parent: &mut UiChildBuilder,
259    mut children: impl FnMut(&mut UiChildBuilder, usize, usize)
260) -> Entity {
261    // Spawns container
262    let mut container_bundle = NodeBundle::default();
263    class.apply(&mut container_bundle);
264    container_bundle.style.flex_wrap = FlexWrap::Wrap;
265    let mut container = parent.spawn((container_bundle, extras));
266
267    // Spawns cells as children of the container
268    let cell_bundle = NodeBundle {
269        style: Style {
270            width: Val::Percent(100.0 / columns as f32),
271            height: Val::Percent(100.0 / rows as f32),
272            justify_content: JustifyContent::Center,
273            align_items: AlignItems::Center,
274            ..Default::default()
275        },
276        ..Default::default()
277    };
278    for row in 0..rows {
279        for col in 0..columns {
280            container = container.with_children(|container| {
281                container
282                    .spawn(cell_bundle.clone())
283                    .with_children(|cell| children(cell, row, col));
284            });
285        }
286    }
287    container.id()
288}