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