1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
use std::sync::{Arc, RwLock};
use bevy::{ecs::system::IntoObserverSystem, prelude::*};
use crate::{context::Widget, prelude::WidgetMapper, CurrentWidget, ObserverCache, ParentWidget};
/// A component to pass children down the tree
/// while also having children of its own.
#[derive(Component, Default, Clone, Deref, DerefMut, PartialEq)]
pub struct PassedChildren(pub WidgetChildren);
/// A commponent to pass children down the tree
/// while also having children of its own.
#[derive(Component, Default, Clone)]
pub struct Mounted;
type ObserverList = Vec<(
CurrentWidget,
Arc<dyn Fn(&mut World, Entity, Entity) -> Option<Entity> + Sync + Send>,
)>;
/// A bevy component that keeps track of Woodpecker UI widget children.
///
/// This is very similar to bevy commands as in it lets you spawn bundles
/// but it does not create an entity until
/// WidgetChildren::process_world is called.
#[derive(Component, Default, Clone)]
pub struct WidgetChildren {
// Strings here are widget type names.
// First children are stored in a queue.
children_queue: Vec<(
String,
Arc<
dyn Fn(
&mut World,
&mut WidgetMapper,
&mut ObserverCache,
ParentWidget,
usize,
String,
ObserverList,
Option<String>, // Child key
) + Sync
+ Send,
>,
ObserverList,
Option<String>, // Child key
)>,
// When a widget is processed onto a parent they get stored here and removed from the queue.
children: Vec<(
String,
Arc<
dyn Fn(
&mut World,
&mut WidgetMapper,
&mut ObserverCache,
ParentWidget,
usize,
String,
ObserverList,
Option<String>, // Child key
) + Sync
+ Send,
>,
ObserverList,
Option<String>, // Child key
)>,
/// A collection of observers attached to the parent widget not the children
self_observers: ObserverList,
/// Stores a list of previous children.
prev_children: Vec<(String, Option<String>)>,
/// Lets the system know who the parent is.
/// We need this because childen can be passed around until they
/// are committed to a parent.
parent_widget: Option<ParentWidget>,
}
impl std::fmt::Debug for WidgetChildren {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("WidgetChildren").finish()
}
}
impl PartialEq for WidgetChildren {
fn eq(&self, other: &Self) -> bool {
let queue = self
.children_queue
.iter()
.map(|(wn, _, _, child_key)| (wn.clone(), child_key.clone()))
.collect::<Vec<_>>();
let other_queue = other
.children_queue
.iter()
.map(|(wn, _, _, child_key)| (wn.clone(), child_key.clone()))
.collect::<Vec<_>>();
let children = self
.children
.iter()
.map(|(wn, _, _, child_key)| (wn.clone(), child_key.clone()))
.collect::<Vec<_>>();
let other_children = other
.children
.iter()
.map(|(wn, _, _, child_key)| (wn.clone(), child_key.clone()))
.collect::<Vec<_>>();
queue == other_queue && children == other_children
}
}
impl WidgetChildren {
/// Builder pattern for adding children when you initially create the component.
pub fn with_child<T: Widget + Component + Default>(
mut self,
bundle: impl Bundle + Clone,
) -> Self {
self.add::<T>(bundle);
self
}
/// Adds a key to the last child widget entity added
pub fn with_key(mut self, key: impl Into<String>) -> Self {
self.add_key(key);
self
}
/// Adds a key to the last child widget entity added
pub fn add_key(&mut self, key: impl Into<String>) {
if let Some((_, _, _, child_key)) = self.children_queue.last_mut() {
*child_key = Some(key.into());
}
}
/// Builder pattern for adding observers when you initially create a child.
/// - spawn_location: Widget entity where the observer was created.
pub fn with_observe<E: Event, B: Bundle, M>(
mut self,
spawn_location: CurrentWidget,
observer: impl IntoObserverSystem<E, B, M>,
) -> Self {
self.observe(spawn_location, observer);
self
}
/// Clears out all children.
pub fn clear(&mut self) {
self.children.clear();
self.parent_widget = None;
}
/// Add a new widget to the list of children. The widget should be a bevy bundle and T should implement widget.
///
/// Note: Make sure to call [`WidgetChildren::apply`] in the render system of the parent
/// otherwise the entities will not be spawned! This will NOT spawn the bundles.
pub fn add<T: Widget + Component + Default>(
&mut self,
bundle: impl Bundle + Clone,
) -> &mut Self {
let widget_type = T::get_name();
self.children_queue.push((
widget_type,
Arc::new(
move |world: &mut World,
widget_mapper: &mut WidgetMapper,
observer_cache: &mut ObserverCache,
parent: ParentWidget,
index: usize,
widget_type: String,
observer_list: ObserverList,
child_key: Option<String>| {
let type_name_without_path =
widget_type.clone().split("::").last().unwrap().to_string();
let child_widget = widget_mapper.get_or_insert_entity_world(
world,
observer_cache,
widget_type,
parent,
child_key,
index,
);
world
.entity_mut(child_widget)
.insert(T::default())
.insert(bundle.clone())
.insert(Mounted)
.insert(Name::new(type_name_without_path.clone()));
for (id, (spawn_entity, ob)) in observer_list.iter().enumerate() {
if !observer_cache.contains(spawn_entity.0, id, child_widget) {
if let Some(observer_entity) = (ob)(world, **spawn_entity, child_widget)
{
observer_cache.add(
spawn_entity.0,
id,
child_widget,
observer_entity,
);
} else {
panic!("Attempted to add an observer when its already been used. This is considered a bug please open a ticket.");
}
}
}
},
),
vec![],
None,
));
self
}
/// Add a bevy observer system to the last added widget if no widget was added the observer
/// is added to the widget entity who has ownership of the `WidgetChildren` component.
/// - spawn_location: Widget entity where the observer was created.
pub fn observe<E: Event, B: Bundle, M>(
&mut self,
spawn_location: CurrentWidget,
observer: impl IntoObserverSystem<E, B, M>,
) -> &mut Self {
let o = Arc::new(RwLock::new(Some(Observer::new(observer))));
if let Some((_, _, observers, _)) = self.children_queue.last_mut() {
observers.push((
spawn_location,
Arc::new(move |world, _parent, target_entity| {
// Last we attempt to spawn the observer.
// We need to do this funkyness to get around observer not being cloneable.
// Instead we can just reuse it!
if let Some(ob) = o.write().unwrap().take() {
trace!("Adding new observer for {}", target_entity);
let observer_entity = world
.spawn((ob.with_entity(target_entity), ChildOf(target_entity)))
.id();
Some(observer_entity)
} else {
None
}
}),
));
} else {
// Treat like parent observer
self.self_observers.push((
spawn_location,
Arc::new(move |world, _parent, target_entity| {
// Last we attempt to spawn the observer.
// We need to do this funkyness to get around observer not being cloneable.
// Instead we can just reuse it!
if let Some(ob) = o.write().unwrap().take() {
trace!("Adding new observer for {}", target_entity);
let observer_entity = world
.spawn((ob.with_entity(target_entity), ChildOf(target_entity)))
.id();
Some(observer_entity)
} else {
None
}
}),
));
}
self
}
/// Lets you know if the children have changed between now and when they were last rendered.
pub fn children_changed(&self) -> bool {
self.children
.iter()
.map(|(n, _, _, child_key)| (n, child_key))
.collect::<Vec<_>>()
!= self
.prev_children
.iter()
.map(|t| (&t.0, &t.1))
.collect::<Vec<_>>()
}
/// Attaches the children to a parent widget.
/// Note: This doesn't actually spawn the children
/// that occurs when the parent widget finishes rendering.
pub fn apply(&mut self, parent_widget: ParentWidget) {
self.parent_widget = Some(parent_widget);
}
pub(crate) fn process_world(&mut self, world: &mut World) {
let Some(parent_widget) = self.parent_widget else {
return;
};
// If our queue isn't empty drain it into the children
// This ensures we remove previous children.
if !self.children_queue.is_empty() {
self.children = self.children_queue.drain(..).collect::<Vec<_>>();
}
// Process self observers
world.resource_scope(
|world: &mut World, mut observer_cache: Mut<ObserverCache>| {
for (id, (spawn_entity, ob)) in self.self_observers.iter().enumerate() {
if !observer_cache.contains(spawn_entity.0, id, parent_widget.entity()) {
if let Some(observer_entity) = (ob)(world, **spawn_entity, parent_widget.entity()) {
observer_cache.add(spawn_entity.0, id, parent_widget.entity(), observer_entity);
} else {
panic!("Attempted to add an observer when its already been used. This is considered a bug please open a ticket.");
}
}
}
});
world.resource_scope(|world: &mut World, mut widget_mapper: Mut<WidgetMapper>| {
world.resource_scope(
|world: &mut World, mut observer_cache: Mut<ObserverCache>| {
// Loop through each child and spawn the bundles.
// The widget mapper helps keep track of which entities go with which child.
// They are ensured to have the same entity id for a given child index and
// widget type name. The type name is passed in here from the children vec.
for (i, (widget_type, child, observers, child_key)) in
self.children.iter().enumerate()
{
trace!("Adding as child: {}", widget_type);
child(
world,
&mut widget_mapper,
&mut observer_cache,
parent_widget,
i,
widget_type.clone(),
observers.clone(),
child_key.clone(),
);
}
},
);
});
// Remove the parent widget.
// [`Self::apply`] should be called if this parent re-renders.
// If its not then we assume no children.
self.parent_widget = None;
// Throw the children type names into the previous children list.
self.prev_children = self
.children
.iter()
.map(|(n, _, _, child_key)| (n.clone(), child_key.clone()))
.collect::<Vec<_>>()
}
}