1use std::collections::HashSet;
2
3use rustc_hash::{
4 FxHashMap,
5 FxHashSet,
6};
7
8use crate::{
9 EmmitableEvent,
10 EventsMeasurer,
11 NameOfEvent,
12 NodeKey,
13 PotentialEvent,
14 SourceEvent,
15};
16
17pub struct NodesState<Key: NodeKey> {
19 pressed_nodes: FxHashSet<Key>,
20 hovered_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 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());
58
59 #[allow(unused_variables)]
61 self.pressed_nodes.retain(|node_key| {
62 let emmitable_press_event = emmitable_events
64 .iter()
65 .any(|event| event.name().is_pressed() && &event.key() == node_key);
66
67 if !emmitable_press_event && source_press_event {
70 #[cfg(debug_assertions)]
71 tracing::info!("Unmarked as pressed {:?}", node_key);
72
73 return false;
75 }
76
77 true
78 });
79
80 let source_movement_event = source_events.iter().find(|e| e.is_moved());
82 let mut removed_from_hovered = FxHashSet::default();
83
84 self.hovered_nodes.retain(|node_key| {
86 let emmitable_movement_event = emmitable_events.iter().any(|event| {
88 (event.name().is_moved() || event.name().is_enter()) && &event.key() == node_key
89 });
90
91 if !emmitable_movement_event {
92 if let Some(source_event) = source_movement_event {
95 if let Some(area) = events_measurer.try_area_of(node_key) {
96 let event = Name::new_leave();
98 for derived_event in event.get_derived_events() {
99 let is_node_listening =
100 events_measurer.is_listening_to(node_key, &derived_event);
101 if is_node_listening {
102 collateral_emmitable_events.push(
103 events_measurer.new_emmitable_event(
104 *node_key,
105 derived_event,
106 source_event.clone(),
107 Some(area),
108 ),
109 );
110 }
111 }
112
113 #[cfg(debug_assertions)]
114 tracing::info!("Unmarked as hovered {:?}", node_key);
115 }
116
117 removed_from_hovered.insert(*node_key);
118
119 return false;
120 }
121 }
122 true
123 });
124
125 if source_movement_event.is_some() {
128 let new_deepest = emmitable_events
129 .iter()
130 .find(|e| e.name().is_exclusive_enter())
131 .map(|e| e.key());
132
133 if let Some(old_entered) = self.entered_node {
134 let deepest_changed = new_deepest != Some(old_entered);
135 let still_hovered = !removed_from_hovered.contains(&old_entered);
136
137 if deepest_changed
138 && still_hovered
139 && let Some(source_event) = source_movement_event
140 {
141 let exclusive_leave = Name::new_exclusive_leave();
142 let is_node_listening =
143 events_measurer.is_listening_to(&old_entered, &exclusive_leave);
144 if is_node_listening
145 && let Some(area) = events_measurer.try_area_of(&old_entered)
146 {
147 collateral_emmitable_events.push(events_measurer.new_emmitable_event(
148 old_entered,
149 exclusive_leave,
150 source_event.clone(),
151 Some(area),
152 ));
153 }
154 }
155 }
156 }
157
158 collateral_emmitable_events
159 }
160
161 pub(crate) fn filter_emmitable_events<
162 Emmitable: EmmitableEvent<Key = Key, Name = Name>,
163 Name: NameOfEvent,
164 >(
165 &self,
166 emmitable_events: &mut Vec<Emmitable>,
167 ) {
168 emmitable_events.retain(|ev| {
169 match ev.name() {
170 _ if ev.name().is_exclusive_enter() => {
172 self.entered_node.as_ref() != Some(&ev.key())
173 }
174
175 _ if ev.name().is_enter() => !self.hovered_nodes.contains(&ev.key()),
177
178 _ if ev.name().is_released() => self.pressed_nodes.contains(&ev.key()),
180
181 _ => true,
182 }
183 });
184 }
185
186 pub fn create_update<
188 Emmitable: EmmitableEvent<Key = Key, Name = Name>,
189 Name: NameOfEvent,
190 Source: SourceEvent,
191 >(
192 &self,
193 events_measurer: &impl EventsMeasurer<Key = Key, Name = Name>,
194 potential_events: &PotentialEvents<Key, Name, Source>,
195 ) -> NodesStatesUpdate<Key> {
196 let mut hovered_nodes = FxHashSet::default();
197 let mut pressed_nodes = FxHashSet::default();
198 let mut entered_node: Option<Key> = None;
199
200 for events in potential_events.values() {
202 let mut child_node: Option<Key> = None;
203
204 for PotentialEvent { node_key, name, .. } in events.iter().rev() {
205 if let Some(child_node) = child_node
206 && !events_measurer.is_node_parent_of(&child_node, *node_key)
207 {
208 continue;
209 }
210
211 if !events_measurer.is_node_transparent(node_key) && !name.does_go_through_solid() {
212 child_node = Some(*node_key);
216 }
217
218 match name {
219 name if name.is_moved() => {
221 hovered_nodes.insert(*node_key);
223
224 if entered_node.is_none()
225 && events_measurer
226 .is_listening_to(node_key, &Name::new_exclusive_enter())
227 {
228 entered_node = Some(*node_key);
229 }
230
231 #[cfg(debug_assertions)]
232 tracing::info!("Marked as hovered {:?}", node_key);
233 }
234
235 name if name.is_pressed() => {
237 pressed_nodes.insert(*node_key);
239
240 #[cfg(debug_assertions)]
241 tracing::info!("Marked as pressed {:?}", node_key);
242 }
243 _ => {}
244 }
245 }
246 }
247 NodesStatesUpdate {
248 pressed_nodes,
249 hovered_nodes,
250 entered_node,
251 }
252 }
253
254 pub fn apply_update(&mut self, update: NodesStatesUpdate<Key>) {
256 self.hovered_nodes.extend(update.hovered_nodes);
257 self.pressed_nodes.extend(update.pressed_nodes);
258
259 if let Some(entered_node) = self.entered_node
260 && !self.hovered_nodes.contains(&entered_node)
261 {
262 self.entered_node = None;
263 }
264
265 if update.entered_node.is_some() {
266 self.entered_node = update.entered_node;
267 }
268 }
269
270 pub fn is_hovered(&self, key: Key) -> bool {
271 self.hovered_nodes.contains(&key)
272 }
273
274 pub fn is_pressed(&self, key: Key) -> bool {
275 self.pressed_nodes.contains(&key)
276 }
277}
278
279#[derive(Clone, Debug, PartialEq)]
280pub struct NodesStatesUpdate<Key: NodeKey> {
281 pressed_nodes: FxHashSet<Key>,
282 hovered_nodes: FxHashSet<Key>,
283 entered_node: Option<Key>,
284}
285
286impl<Key: NodeKey> Default for NodesStatesUpdate<Key> {
287 fn default() -> Self {
288 Self {
289 pressed_nodes: HashSet::default(),
290 hovered_nodes: HashSet::default(),
291 entered_node: None,
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}