1use alloc::vec::Vec;
2
3use crate::{
4 EmmitableEvent,
5 EventsMeasurer,
6 NameOfEvent,
7 NodeKey,
8 PotentialEvent,
9 SourceEvent,
10 collections::{
11 FxHashMap,
12 FxHashSet,
13 },
14};
15
16pub struct NodesState<Key: NodeKey> {
18 pressed_nodes: FxHashSet<Key>,
19 hovered_nodes: FxHashSet<Key>,
20 visible_nodes: FxHashSet<Key>,
21 entered_node: Option<Key>,
22}
23
24impl<Key: NodeKey> Default for NodesState<Key> {
25 fn default() -> Self {
26 Self {
27 pressed_nodes: FxHashSet::default(),
28 hovered_nodes: FxHashSet::default(),
29 visible_nodes: FxHashSet::default(),
30 entered_node: None,
31 }
32 }
33}
34
35pub type PotentialEvents<Key, Name, Source> =
36 FxHashMap<Name, Vec<PotentialEvent<Key, Name, Source>>>;
37
38impl<Key: NodeKey> NodesState<Key> {
39 pub(crate) fn retain_states<
41 Emmitable: EmmitableEvent<Key = Key, Name = Name>,
42 Name: NameOfEvent,
43 Source: SourceEvent,
44 >(
45 &mut self,
46 events_measurer: &impl EventsMeasurer<
47 Key = Key,
48 Name = Name,
49 Emmitable = Emmitable,
50 Source = Source,
51 >,
52 emmitable_events: &[Emmitable],
53 source_events: &[Source],
54 ) -> Vec<Emmitable> {
55 let mut collateral_emmitable_events = Vec::default();
56
57 let source_press_event = source_events.iter().any(|e| e.is_pressed());
58
59 #[allow(unused_variables)]
60 self.pressed_nodes.retain(|node_key| {
61 let emmitable_press_event = emmitable_events
62 .iter()
63 .any(|event| event.name().is_pressed() && &event.key() == node_key);
64
65 if !emmitable_press_event && source_press_event {
67 #[cfg(debug_assertions)]
68 tracing::info!("Unmarked as pressed {:?}", node_key);
69
70 return false;
71 }
72
73 true
74 });
75
76 let source_movement_event = source_events
77 .iter()
78 .find(|e| e.is_moved() || e.is_touch_released() || e.is_pointer_exit());
79 let mut removed_from_hovered = FxHashSet::default();
80
81 self.hovered_nodes.retain(|node_key| {
82 let Some(area) = events_measurer.try_area_of(node_key) else {
83 removed_from_hovered.insert(*node_key);
84 return false;
85 };
86
87 let cursor_still_inside = source_movement_event.is_none_or(|event| {
88 !event.is_pointer_exit()
89 && !event.is_touch_released()
90 && event
91 .try_location()
92 .is_none_or(|cursor| events_measurer.is_point_inside(node_key, cursor))
93 });
94
95 if cursor_still_inside {
96 return true;
97 }
98
99 let source_event = source_movement_event.unwrap();
101 for derived_event in Name::new_leave().get_derived_events() {
102 if events_measurer.is_listening_to(node_key, &derived_event) {
103 collateral_emmitable_events.push(events_measurer.new_emmitable_event(
104 *node_key,
105 derived_event,
106 source_event.clone(),
107 Some(area),
108 ));
109 }
110 }
111
112 #[cfg(debug_assertions)]
113 tracing::info!("Unmarked as hovered {:?}", node_key);
114
115 removed_from_hovered.insert(*node_key);
116
117 false
118 });
119
120 if let Some(source_event) = source_movement_event {
123 let new_deepest = emmitable_events
124 .iter()
125 .find(|e| e.name().is_exclusive_enter())
126 .or_else(|| emmitable_events.iter().rev().find(|e| e.name().is_moved()))
127 .map(|e| e.key());
128
129 if let Some(old_entered) = self.entered_node {
130 let deepest_changed = new_deepest != Some(old_entered);
131 let still_hovered = !removed_from_hovered.contains(&old_entered);
132
133 if deepest_changed && still_hovered {
134 let exclusive_leave = Name::new_exclusive_leave();
135 if events_measurer.is_listening_to(&old_entered, &exclusive_leave)
136 && let Some(area) = events_measurer.try_area_of(&old_entered)
137 {
138 collateral_emmitable_events.push(events_measurer.new_emmitable_event(
139 old_entered,
140 exclusive_leave,
141 source_event.clone(),
142 Some(area),
143 ));
144 }
145 }
146 }
147 }
148
149 collateral_emmitable_events
150 }
151
152 pub(crate) fn filter_emmitable_events<
153 Emmitable: EmmitableEvent<Key = Key, Name = Name>,
154 Name: NameOfEvent,
155 >(
156 &mut self,
157 emmitable_events: &mut Vec<Emmitable>,
158 ) {
159 let entered_node = emmitable_events
161 .iter()
162 .find(|e| e.name().is_exclusive_enter())
163 .or_else(|| emmitable_events.iter().rev().find(|e| e.name().is_moved()))
164 .map(|e| e.key());
165
166 emmitable_events.retain(|ev| match ev.name() {
167 _ if ev.name().is_exclusive_enter() => {
169 entered_node.as_ref() == Some(&ev.key()) && entered_node != self.entered_node
170 }
171 _ if ev.name().is_enter() => !self.hovered_nodes.contains(&ev.key()),
173 _ if ev.name().is_released() => self.pressed_nodes.contains(&ev.key()),
175 _ => true,
176 });
177
178 self.entered_node = entered_node;
179 }
180
181 pub fn create_update<Name: NameOfEvent, Source: SourceEvent>(
183 &self,
184 events_measurer: &impl EventsMeasurer<Key = Key, Name = Name>,
185 potential_events: &PotentialEvents<Key, Name, Source>,
186 ) -> NodesStatesUpdate<Key> {
187 let mut hovered_nodes = FxHashSet::default();
188 let mut pressed_nodes = FxHashSet::default();
189
190 for events in potential_events.values() {
191 let mut child_node: Option<Key> = None;
192
193 for PotentialEvent { node_key, name, .. } in events.iter().rev() {
194 if let Some(child_node) = child_node
195 && !events_measurer.is_node_parent_of(&child_node, *node_key)
196 {
197 continue;
198 }
199
200 if !events_measurer.is_node_transparent(node_key) && !name.does_go_through_solid() {
204 child_node = Some(*node_key);
205 }
206
207 match name {
208 name if name.is_moved() => {
209 hovered_nodes.insert(*node_key);
210
211 #[cfg(debug_assertions)]
212 tracing::info!("Marked as hovered {:?}", node_key);
213 }
214 name if name.is_pressed() => {
215 hovered_nodes.insert(*node_key);
216 pressed_nodes.insert(*node_key);
217
218 #[cfg(debug_assertions)]
219 {
220 tracing::info!("Marked as hovered {:?}", node_key);
221 tracing::info!("Marked as pressed {:?}", node_key);
222 }
223 }
224 _ => {}
225 }
226 }
227 }
228
229 NodesStatesUpdate {
230 pressed_nodes,
231 hovered_nodes,
232 }
233 }
234
235 pub fn apply_update(&mut self, update: NodesStatesUpdate<Key>) {
237 self.hovered_nodes.extend(update.hovered_nodes);
238 self.pressed_nodes.extend(update.pressed_nodes);
239 }
240
241 pub fn is_hovered(&self, key: Key) -> bool {
242 self.hovered_nodes.contains(&key)
243 }
244
245 pub fn hovered_nodes(&self) -> impl Iterator<Item = &Key> {
247 self.hovered_nodes.iter()
248 }
249
250 pub fn is_pressed(&self, key: Key) -> bool {
251 self.pressed_nodes.contains(&key)
252 }
253
254 pub fn is_visible(&self, key: Key) -> bool {
255 self.visible_nodes.contains(&key)
256 }
257
258 pub fn set_visible_nodes(&mut self, visible_nodes: FxHashSet<Key>) {
260 self.visible_nodes = visible_nodes;
261 }
262}
263
264#[derive(Clone, Debug, PartialEq)]
265pub struct NodesStatesUpdate<Key: NodeKey> {
266 pressed_nodes: FxHashSet<Key>,
267 hovered_nodes: FxHashSet<Key>,
268}
269
270impl<Key: NodeKey> Default for NodesStatesUpdate<Key> {
271 fn default() -> Self {
272 Self {
273 pressed_nodes: FxHashSet::default(),
274 hovered_nodes: FxHashSet::default(),
275 }
276 }
277}
278
279impl<Key: NodeKey> NodesStatesUpdate<Key> {
280 pub fn discard<Name: NameOfEvent>(&mut self, name: &Name, node_key: &Key) {
282 match name {
283 _ if name.is_moved() => {
284 self.hovered_nodes.remove(node_key);
285 }
286 _ if name.is_pressed() => {
287 self.pressed_nodes.remove(node_key);
288 }
289 _ => {}
290 }
291 }
292}