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