1use bevy::{
2 ecs::{component::Component, entity::Entity, query::Changed, system::IntoSystem, world::World},
3 hierarchy::BuildWorldChildren,
4 render::color::Color,
5 text::{Text, TextSection, TextStyle},
6 ui::{
7 node_bundles::{ButtonBundle, NodeBundle, TextBundle},
8 AlignItems, BackgroundColor, FlexDirection, Interaction, JustifyContent, Style, UiRect,
9 Val,
10 },
11 utils::default,
12};
13use std::{any::Any, mem};
14
15pub trait Compose: Send + Sync + 'static {
16 type State: Send + Sync + 'static;
17
18 fn build(&mut self, world: &mut World, children: &mut Vec<Entity>) -> Self::State;
19
20 fn rebuild(
21 &mut self,
22 target: &mut Self,
23 state: &mut Self::State,
24 world: &mut World,
25 children: &mut Vec<Entity>,
26 );
27}
28
29impl Compose for () {
30 type State = ();
31
32 fn build(&mut self, _world: &mut World, _children: &mut Vec<Entity>) -> Self::State {}
33
34 fn rebuild(
35 &mut self,
36 _target: &mut Self,
37 _state: &mut Self::State,
38 _world: &mut World,
39 _children: &mut Vec<Entity>,
40 ) {
41 }
42}
43
44impl Compose for &'static str {
45 type State = Entity;
46
47 fn build(&mut self, world: &mut World, children: &mut Vec<Entity>) -> Self::State {
48 let entity = world.spawn(TextBundle::from_section(
49 self.to_owned(),
50 Default::default(),
51 ));
52 let id = entity.id();
53 children.push(id);
54 id
55 }
56
57 fn rebuild(
58 &mut self,
59 target: &mut Self,
60 state: &mut Self::State,
61 world: &mut World,
62 children: &mut Vec<Entity>,
63 ) {
64 children.push(*state);
65
66 if self != target {
67 world.get_mut::<Text>(*state).unwrap().sections[0] =
68 TextSection::new(self.to_owned(), TextStyle::default());
69 }
70 }
71}
72
73impl Compose for String {
74 type State = Entity;
75
76 fn build(&mut self, world: &mut World, children: &mut Vec<Entity>) -> Self::State {
77 let entity = world.spawn(TextBundle::from_section(self.clone(), Default::default()));
78 let id = entity.id();
79 children.push(id);
80 id
81 }
82
83 fn rebuild(
84 &mut self,
85 target: &mut Self,
86 state: &mut Self::State,
87 world: &mut World,
88 children: &mut Vec<Entity>,
89 ) {
90 children.push(*state);
91
92 if self != target {
93 world.get_mut::<Text>(*state).unwrap().sections[0] =
94 TextSection::new(self.clone(), TextStyle::default());
95 }
96 }
97}
98
99impl<C1: Compose, C2: Compose, C3: Compose> Compose for (C1, C2, C3) {
100 type State = (C1::State, C2::State, C3::State);
101
102 fn build(&mut self, world: &mut World, children: &mut Vec<Entity>) -> Self::State {
103 (
104 self.0.build(world, children),
105 self.1.build(world, children),
106 self.2.build(world, children),
107 )
108 }
109
110 fn rebuild(
111 &mut self,
112 target: &mut Self,
113 state: &mut Self::State,
114 world: &mut World,
115 children: &mut Vec<Entity>,
116 ) {
117 self.0.rebuild(&mut target.0, &mut state.0, world, children);
118 self.1.rebuild(&mut target.1, &mut state.1, world, children);
119 self.2.rebuild(&mut target.2, &mut state.2, world, children);
120 }
121}
122
123pub fn flex<C: Compose>(content: C) -> Flex<C> {
124 Flex {
125 content,
126 on_click: None,
127 }
128}
129
130pub struct Flex<C> {
131 content: C,
132 on_click: Option<Box<dyn FnMut(&mut World) + Send + Sync>>,
133}
134
135impl<C> Flex<C> {
136 pub fn on_click<Marker>(mut self, system: impl IntoSystem<(), (), Marker>) -> Self {
137 let mut cell = Some(IntoSystem::<(), (), Marker>::into_system(system));
138 let mut id_cell = None;
139 self.on_click = Some(Box::new(move |world| {
140 if let Some(system) = cell.take() {
141 let id = world.register_system(system);
142 id_cell = Some(id);
143 }
144
145 let id = id_cell.unwrap();
146 world.run_system(id).unwrap();
147 }));
148 self
149 }
150}
151
152impl<C: Compose> Compose for Flex<C> {
153 type State = (Entity, C::State);
154
155 fn build(&mut self, world: &mut World, children: &mut Vec<Entity>) -> Self::State {
156 let parent_children = mem::take(children);
157 let content_state = self.content.build(world, children);
158 let my_children = mem::replace(children, parent_children);
159
160 let mut entity = world.spawn(ButtonBundle {
161 style: Style {
162 width: Val::Px(150.0),
163 height: Val::Px(65.0),
164 border: UiRect::all(Val::Px(5.0)),
165 justify_content: JustifyContent::Center,
166 align_items: AlignItems::Center,
167 ..default()
168 },
169 background_color: BackgroundColor(Color::BLACK),
170 ..default()
171 });
172 entity.push_children(&my_children);
173
174 let id = entity.id();
175 children.push(id);
176
177 if let Some(handler) = self.on_click.take() {
178 entity.insert(ClickHandler {
179 handler: Some(handler),
180 });
181 }
182
183 (id, content_state)
184 }
185
186 fn rebuild(
187 &mut self,
188 target: &mut Self,
189 state: &mut Self::State,
190 world: &mut World,
191 children: &mut Vec<Entity>,
192 ) {
193 let parent_children = mem::take(children);
194 self.content
195 .rebuild(&mut target.content, &mut state.1, world, children);
196 let _my_children = mem::replace(children, parent_children);
197
198 children.push(state.0);
199 }
200}
201
202#[derive(Component)]
203pub struct ClickHandler {
204 handler: Option<Box<dyn FnMut(&mut World) + Send + Sync>>,
205}
206
207pub fn handler_system(world: &mut World) {
208 let mut query =
209 world.query_filtered::<(&Interaction, &mut ClickHandler), Changed<Interaction>>();
210
211 let mut handlers: Vec<_> = query
212 .iter_mut(world)
213 .map(|(interaction, mut handler)| (*interaction, handler.handler.take()))
214 .collect();
215
216 for (interaction, f) in &mut handlers {
217 match interaction {
218 Interaction::Pressed => {
219 if let Some(ref mut f) = f {
220 f(world)
221 }
222 }
223 _ => {}
224 }
225 }
226
227 for (idx, (_, mut handler)) in query.iter_mut(world).enumerate() {
228 handler.handler = handlers[idx].1.take();
229 }
230}
231
232pub trait AnyCompose: Send + Sync {
233 fn as_any_mut(&mut self) -> &mut dyn Any;
234
235 fn build_any(
236 &mut self,
237 world: &mut World,
238 children: &mut Vec<Entity>,
239 ) -> Box<dyn Any + Send + Sync>;
240
241 fn rebuild_any(
242 &mut self,
243 target: &mut dyn Any,
244 state: &mut dyn Any,
245 world: &mut World,
246 children: &mut Vec<Entity>,
247 );
248}
249
250impl<C: Compose> AnyCompose for C {
251 fn as_any_mut(&mut self) -> &mut dyn Any {
252 self
253 }
254
255 fn build_any(
256 &mut self,
257 world: &mut World,
258 children: &mut Vec<Entity>,
259 ) -> Box<dyn Any + Send + Sync> {
260 Box::new(self.build(world, children))
261 }
262
263 fn rebuild_any(
264 &mut self,
265 target: &mut dyn Any,
266 state: &mut dyn Any,
267 world: &mut World,
268 children: &mut Vec<Entity>,
269 ) {
270 self.rebuild(
271 target.downcast_mut().unwrap(),
272 state.downcast_mut().unwrap(),
273 world,
274 children,
275 )
276 }
277}
278
279#[derive(Component)]
280pub struct Composer {
281 compose: Option<Box<dyn FnMut(&mut World) -> Box<dyn AnyCompose> + Send + Sync>>,
282 state: Option<(Box<dyn AnyCompose>, Box<dyn Any + Send + Sync>)>,
283}
284
285impl Composer {
286 pub fn new<Marker, C: Compose>(compose_fn: impl IntoSystem<(), C, Marker>) -> Self {
287 let mut system_cell = Some(IntoSystem::<(), C, Marker>::into_system(compose_fn));
288 let mut id_cell = None;
289 Self {
290 compose: Some(Box::new(move |world| {
291 if let Some(system) = system_cell.take() {
292 let id = world.register_system(system);
293 id_cell = Some(id);
294 }
295
296 let id = id_cell.unwrap();
297 Box::new(world.run_system(id).unwrap())
298 })),
299 state: None,
300 }
301 }
302}
303
304pub fn compose(world: &mut World) {
305 let mut query = world.query::<&mut Composer>();
306 let mut composers = query
307 .iter_mut(world)
308 .map(|mut composer| (composer.compose.take(), composer.state.take()))
309 .collect::<Vec<_>>();
310
311 for (compose_fn, state) in &mut composers {
312 let mut compose = compose_fn.as_mut().unwrap()(world);
313 let mut children = Vec::new();
314
315 if let Some((target, state)) = state {
316 compose.rebuild_any(target.as_any_mut(), &mut **state, world, &mut children)
317 } else {
318 let s = compose.build_any(world, &mut children);
319 *state = Some((compose, s));
320
321 world
322 .spawn(NodeBundle {
323 style: Style {
324 width: Val::Percent(100.),
325 height: Val::Percent(100.),
326 flex_direction: FlexDirection::Column,
327 align_items: AlignItems::Center,
328 ..Default::default()
329 },
330 background_color: BackgroundColor(Color::BLACK),
331 ..Default::default()
332 })
333 .push_children(&children);
334 }
335 }
336
337 for (idx, mut composer) in query.iter_mut(world).enumerate() {
338 composer.compose = composers[idx].0.take();
339 composer.state = composers[idx].1.take();
340 }
341}
342
343pub fn lazy<C: Compose, Marker>(system: impl IntoSystem<(), C, Marker>) -> Lazy {
344 let mut cell = Some(IntoSystem::<(), C, Marker>::into_system(system));
345
346 let system: Option<
347 Box<
348 dyn FnMut(Option<&mut dyn Any>, &mut World, &mut Option<LazyState>, &mut Vec<Entity>)
349 + Send
350 + Sync,
351 >,
352 > = Some(Box::new(move |target, world, state_cell, children| {
353 if let Some(ref mut state) = state_cell {
354 let target = target.unwrap();
355
356 let mut compose = (state.system)(world);
357 compose.rebuild_any(state.compose.as_any_mut(), &mut *state.state, world, children);
358
359 } else {
360 let system = cell.take().unwrap();
361 let system_id = world.register_system(system);
362
363 let mut compose = world.run_system(system_id).unwrap();
364 let state = compose.build_any(world, children);
365
366 *state_cell = Some(LazyState {
367 system: Box::new(move |world| {
368 let compose = world.run_system(system_id).unwrap();
369 Box::new(compose)
370 }),
371 compose: Box::new(compose),
372 state,
373 })
374 }
375 }));
376
377 Lazy { system }
378}
379
380pub struct LazyState {
381 system: Box<dyn FnMut(&mut World) -> Box<dyn AnyCompose>+ Send + Sync> ,
382 compose: Box<dyn AnyCompose>,
383 state: Box<dyn Any + Send + Sync>,
384}
385
386pub struct Lazy {
387 system: Option<
388 Box<
389 dyn FnMut(Option<&mut dyn Any>, &mut World, &mut Option<LazyState>, &mut Vec<Entity>)
390 + Send
391 + Sync,
392 >,
393 >,
394}
395
396impl Compose for Lazy {
397 type State = Option<LazyState>;
398
399 fn build(&mut self, world: &mut World, children: &mut Vec<Entity>) -> Self::State {
400 let mut state_cell = None;
401 self.system.as_mut().unwrap()(None, world, &mut state_cell, children);
402 state_cell
403 }
404
405 fn rebuild(
406 &mut self,
407 target: &mut Self,
408 state: &mut Self::State,
409 world: &mut World,
410 children: &mut Vec<Entity>,
411 ) {
412 self.system.as_mut().unwrap()(Some(target), world, state, children);
413 }
414}