1use crate::{
2 dyn_compose::DynCompose,
3 keyed::Keyed,
4 state::{GetStateId, SetState, TypedStateId},
5 Compose,
6};
7use bevy_ecs::{
8 bundle::Bundle,
9 entity::Entity,
10 event::Event,
11 observer::{Observer, Trigger},
12 system::{EntityCommands, IntoObserverSystem},
13};
14use bevy_picking::events::{Out, Over, Pointer};
15use std::{hash::Hash, sync::Arc};
16
17type ObserverGeneratorFn = Arc<dyn (Fn(&mut EntityCommands) -> Entity) + Send + Sync>;
20
21#[derive(Clone)]
22pub(crate) struct ObserverGenerator(ObserverGeneratorFn);
23
24impl ObserverGenerator {
25 fn new<E: Event, B: Bundle, M>(
26 observer: impl IntoObserverSystem<E, B, M> + Clone + Sync,
27 ) -> Self {
28 let f = Arc::new(move |entity: &mut EntityCommands| {
29 let target_entity = entity.id();
30 let commands = entity.commands_mut();
31 let o = Observer::new(observer.clone()).with_entity(target_entity);
32 commands.spawn(o).id()
33 });
34
35 Self(f)
36 }
37
38 pub fn generate(&self, entity: &mut EntityCommands) -> Entity {
39 self.0(entity)
40 }
41}
42
43#[derive(Clone, Default)]
82#[allow(clippy::type_complexity)]
83pub struct Modifier {
84 pub(crate) children: DynCompose,
85 pub(crate) bundle_modifiers: Vec<Arc<dyn Fn(&mut EntityCommands) + Send + Sync>>,
86 pub(crate) temporary_observers: Vec<ObserverGenerator>,
87 pub(crate) retained_observers: Vec<ObserverGenerator>,
88}
89
90impl Modifier {
91 pub fn join(&mut self, other: &Modifier) {
93 self.children = match other.children.is_empty() {
94 true => self.children.clone(),
95 false => other.children.clone(),
96 };
97 self.bundle_modifiers
98 .extend(other.bundle_modifiers.iter().cloned());
99 self.temporary_observers
100 .extend(other.temporary_observers.iter().cloned());
101 self.retained_observers
102 .extend(other.retained_observers.iter().cloned());
103 }
104}
105
106pub trait Modify: Sized {
109 fn modifier(&mut self) -> &mut Modifier;
110}
111
112impl<T: Modify + Compose> ModifyFunctions<T> for T {
113 type Target = T;
114
115 fn use_modifier(mut self, modifier: &Modifier) -> Self {
116 self.modifier().join(modifier);
117 self
118 }
119
120 fn children(mut self, children: impl Compose + 'static) -> Self {
121 let modifier = self.modifier();
122 modifier.children = DynCompose::new(children);
123 self
124 }
125
126 fn with_bundle<B: Bundle + Clone>(mut self, bundle: B) -> Self::Target {
127 let bundle_modifier = Arc::new(move |entity: &mut EntityCommands| {
128 entity.try_insert(bundle.clone());
129 });
130
131 let modifier = self.modifier();
132 modifier.bundle_modifiers.push(bundle_modifier);
133
134 self
135 }
136
137 fn with_bundle_if<B: Bundle + Clone>(mut self, condition: bool, bundle: B) -> Self::Target {
138 let bundle_modifier = Arc::new(move |entity: &mut EntityCommands| {
139 if condition {
140 entity.try_insert(bundle.clone());
141 } else {
142 entity.remove::<B>();
143 }
144 });
145
146 let modifier = self.modifier();
147 modifier.bundle_modifiers.push(bundle_modifier);
148
149 self
150 }
151
152 fn to_dyn(self) -> DynCompose
153 where
154 Self: 'static,
155 {
156 DynCompose::new(self)
157 }
158
159 fn some(self) -> Option<Self::Target> {
160 Some(self)
161 }
162
163 fn keyed<H: Hash + Send + Sync>(self, key: H) -> Keyed<H>
164 where
165 Self: 'static,
166 {
167 Keyed::new(key, self)
168 }
169
170 fn observe<E: Event, B2: Bundle, M>(
171 mut self,
172 observer: impl IntoObserverSystem<E, B2, M> + Clone + Sync,
173 ) -> Self {
174 let observer_generator = ObserverGenerator::new(observer);
175 let modifier = self.modifier();
176 modifier.temporary_observers.push(observer_generator);
177
178 self
179 }
180
181 fn observe_retained<E: Event, B2: Bundle, M>(
182 mut self,
183 observer: impl IntoObserverSystem<E, B2, M> + Clone + Sync,
184 ) -> Self {
185 let observer_generator = ObserverGenerator::new(observer);
186 let modifier = self.modifier();
187 modifier.retained_observers.push(observer_generator);
188
189 self
190 }
191
192 fn bind_hover(self, hover_state: impl GetStateId<bool>) -> Self {
193 let typed_state_id = TypedStateId::from_state_id(hover_state.get_id());
194
195 self.observe_retained(move |_: Trigger<Pointer<Over>>, mut state: SetState| {
196 state.set_neq(typed_state_id, true)
197 })
198 .observe_retained(move |_: Trigger<Pointer<Out>>, mut state: SetState| {
199 state.set_neq(typed_state_id, false)
200 })
201 }
202}
203
204pub trait ModifyFunctions<T>: Sized {
211 type Target: Compose;
212 fn use_modifier(self, modifier: &Modifier) -> Self::Target;
214
215 fn children(self, children: impl Compose + 'static) -> Self::Target;
217
218 fn with_bundle<B: Bundle + Clone>(self, bundle: B) -> Self::Target;
228
229 fn with_bundle_if<B: Bundle + Clone>(self, condition: bool, bundle: B) -> Self::Target;
235
236 fn to_dyn(self) -> DynCompose
238 where
239 Self::Target: 'static;
240
241 fn some(self) -> Option<Self::Target>;
243
244 fn some_if(self, condition: bool) -> Option<Self::Target> {
246 match condition {
247 true => self.some(),
248 false => None,
249 }
250 }
251
252 fn keyed<H: Hash + Send + Sync>(self, key: H) -> Keyed<H>
254 where
255 Self::Target: 'static;
256
257 fn observe<E: Event, B2: Bundle, M>(
260 self,
261 observer: impl IntoObserverSystem<E, B2, M> + Clone + Sync,
262 ) -> Self::Target;
263
264 fn observe_retained<E: Event, B2: Bundle, M>(
266 self,
267 observer: impl IntoObserverSystem<E, B2, M> + Clone + Sync,
268 ) -> Self::Target;
269
270 fn bind_hover(self, hover_state: impl GetStateId<bool>) -> Self::Target;
272}