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