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.iter().find(|e| e.is_moved());
74 let mut removed_from_hovered = FxHashSet::default();
75
76 self.hovered_nodes.retain(|node_key| {
77 let Some(area) = events_measurer.try_area_of(node_key) else {
78 removed_from_hovered.insert(*node_key);
79 return false;
80 };
81
82 let cursor_still_inside = source_movement_event
83 .and_then(|e| e.try_location())
84 .is_none_or(|cursor| events_measurer.is_point_inside(node_key, cursor));
85
86 if cursor_still_inside {
87 return true;
88 }
89
90 let source_event = source_movement_event.unwrap();
92 for derived_event in Name::new_leave().get_derived_events() {
93 if events_measurer.is_listening_to(node_key, &derived_event) {
94 collateral_emmitable_events.push(events_measurer.new_emmitable_event(
95 *node_key,
96 derived_event,
97 source_event.clone(),
98 Some(area),
99 ));
100 }
101 }
102
103 #[cfg(debug_assertions)]
104 tracing::info!("Unmarked as hovered {:?}", node_key);
105
106 removed_from_hovered.insert(*node_key);
107
108 false
109 });
110
111 if let Some(source_event) = source_movement_event {
114 let new_deepest = emmitable_events
115 .iter()
116 .find(|e| e.name().is_exclusive_enter())
117 .map(|e| e.key());
118
119 if let Some(old_entered) = self.entered_node {
120 let deepest_changed = new_deepest != Some(old_entered);
121 let still_hovered = !removed_from_hovered.contains(&old_entered);
122
123 if deepest_changed && still_hovered {
124 let exclusive_leave = Name::new_exclusive_leave();
125 if events_measurer.is_listening_to(&old_entered, &exclusive_leave)
126 && let Some(area) = events_measurer.try_area_of(&old_entered)
127 {
128 collateral_emmitable_events.push(events_measurer.new_emmitable_event(
129 old_entered,
130 exclusive_leave,
131 source_event.clone(),
132 Some(area),
133 ));
134 }
135 }
136 }
137 }
138
139 collateral_emmitable_events
140 }
141
142 pub(crate) fn filter_emmitable_events<
143 Emmitable: EmmitableEvent<Key = Key, Name = Name>,
144 Name: NameOfEvent,
145 >(
146 &mut self,
147 emmitable_events: &mut Vec<Emmitable>,
148 ) {
149 let entered_node = emmitable_events
150 .iter()
151 .rev()
152 .find(|e| e.name().is_moved() || e.name().is_exclusive_enter())
153 .map(|e| e.key());
154
155 emmitable_events.retain(|ev| match ev.name() {
156 _ if ev.name().is_exclusive_enter() => {
158 entered_node.as_ref() == Some(&ev.key()) && entered_node != self.entered_node
159 }
160 _ if ev.name().is_enter() => !self.hovered_nodes.contains(&ev.key()),
162 _ if ev.name().is_released() => self.pressed_nodes.contains(&ev.key()),
164 _ => true,
165 });
166
167 self.entered_node = entered_node;
168 }
169
170 pub fn create_update<Name: NameOfEvent, Source: SourceEvent>(
172 &self,
173 events_measurer: &impl EventsMeasurer<Key = Key, Name = Name>,
174 potential_events: &PotentialEvents<Key, Name, Source>,
175 ) -> NodesStatesUpdate<Key> {
176 let mut hovered_nodes = FxHashSet::default();
177 let mut pressed_nodes = FxHashSet::default();
178
179 for events in potential_events.values() {
180 let mut child_node: Option<Key> = None;
181
182 for PotentialEvent { node_key, name, .. } in events.iter().rev() {
183 if let Some(child_node) = child_node
184 && !events_measurer.is_node_parent_of(&child_node, *node_key)
185 {
186 continue;
187 }
188
189 if !events_measurer.is_node_transparent(node_key) && !name.does_go_through_solid() {
193 child_node = Some(*node_key);
194 }
195
196 match name {
197 name if name.is_moved() => {
198 hovered_nodes.insert(*node_key);
199
200 #[cfg(debug_assertions)]
201 tracing::info!("Marked as hovered {:?}", node_key);
202 }
203 name if name.is_pressed() => {
204 pressed_nodes.insert(*node_key);
205
206 #[cfg(debug_assertions)]
207 tracing::info!("Marked as pressed {:?}", node_key);
208 }
209 _ => {}
210 }
211 }
212 }
213
214 NodesStatesUpdate {
215 pressed_nodes,
216 hovered_nodes,
217 }
218 }
219
220 pub fn apply_update(&mut self, update: NodesStatesUpdate<Key>) {
222 self.hovered_nodes.extend(update.hovered_nodes);
223 self.pressed_nodes.extend(update.pressed_nodes);
224 }
225
226 pub fn is_hovered(&self, key: Key) -> bool {
227 self.hovered_nodes.contains(&key)
228 }
229
230 pub fn is_pressed(&self, key: Key) -> bool {
231 self.pressed_nodes.contains(&key)
232 }
233}
234
235#[derive(Clone, Debug, PartialEq)]
236pub struct NodesStatesUpdate<Key: NodeKey> {
237 pressed_nodes: FxHashSet<Key>,
238 hovered_nodes: FxHashSet<Key>,
239}
240
241impl<Key: NodeKey> Default for NodesStatesUpdate<Key> {
242 fn default() -> Self {
243 Self {
244 pressed_nodes: FxHashSet::default(),
245 hovered_nodes: FxHashSet::default(),
246 }
247 }
248}
249
250impl<Key: NodeKey> NodesStatesUpdate<Key> {
251 pub fn discard<Name: NameOfEvent>(&mut self, name: &Name, node_key: &Key) {
253 match name {
254 _ if name.is_moved() => {
255 self.hovered_nodes.remove(node_key);
256 }
257 _ if name.is_pressed() => {
258 self.pressed_nodes.remove(node_key);
259 }
260 _ => {}
261 }
262 }
263}