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}
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 }
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<
39 Emmitable: EmmitableEvent<Key = Key, Name = Name>,
40 Name: NameOfEvent,
41 Source: SourceEvent,
42 >(
43 &mut self,
44 events_measurer: &impl EventsMeasurer<
45 Key = Key,
46 Name = Name,
47 Emmitable = Emmitable,
48 Source = Source,
49 >,
50 emmitable_events: &[Emmitable],
51 source_events: &[Source],
52 ) -> Vec<Emmitable> {
53 let mut collateral_emmitable_events = Vec::default();
54
55 let source_press_event = source_events.iter().any(|e| e.is_pressed());
57
58 #[allow(unused_variables)]
60 self.pressed_nodes.retain(|node_key| {
61 let emmitable_press_event = emmitable_events
63 .iter()
64 .any(|event| event.name().is_pressed() && &event.key() == node_key);
65
66 if !emmitable_press_event && source_press_event {
69 #[cfg(debug_assertions)]
70 tracing::info!("Unmarked as pressed {:?}", node_key);
71
72 return false;
74 }
75
76 true
77 });
78
79 let source_movement_event = source_events.iter().find(|e| e.is_moved());
81
82 self.hovered_nodes.retain(|node_key| {
84 let emmitable_movement_event = emmitable_events.iter().any(|event| {
86 (event.name().is_moved() || event.name().is_enter()) && &event.key() == node_key
87 });
88
89 if !emmitable_movement_event {
90 if let Some(source_event) = source_movement_event {
93 if let Some(area) = events_measurer.try_area_of(node_key) {
94 let event = Name::new_leave();
96 for derived_event in event.get_derived_events() {
97 let is_node_listening =
98 events_measurer.is_listening_to(node_key, &derived_event);
99 if is_node_listening {
100 collateral_emmitable_events.push(
101 events_measurer.new_emmitable_event(
102 *node_key,
103 derived_event,
104 source_event.clone(),
105 Some(area),
106 ),
107 );
108 }
109 }
110
111 #[cfg(debug_assertions)]
112 tracing::info!("Unmarked as hovered {:?}", node_key);
113 }
114
115 return false;
117 }
118 }
119 true
120 });
121
122 collateral_emmitable_events
123 }
124
125 pub(crate) fn filter_emmitable_events<
126 Emmitable: EmmitableEvent<Key = Key, Name = Name>,
127 Name: NameOfEvent,
128 >(
129 &self,
130 emmitable_events: &mut Vec<Emmitable>,
131 ) {
132 emmitable_events.retain(|ev| {
133 match ev.name() {
134 _ if ev.name().is_enter() => !self.hovered_nodes.contains(&ev.key()),
136
137 _ if ev.name().is_released() => self.pressed_nodes.contains(&ev.key()),
139
140 _ => true,
141 }
142 });
143 }
144
145 pub fn create_update<
147 Emmitable: EmmitableEvent<Key = Key, Name = Name>,
148 Name: NameOfEvent,
149 Source: SourceEvent,
150 >(
151 &self,
152 events_measurer: &impl EventsMeasurer<Key = Key, Name = Name>,
153 potential_events: &PotentialEvents<Key, Name, Source>,
154 ) -> NodesStatesUpdate<Key> {
155 let mut hovered_nodes = FxHashSet::default();
156 let mut pressed_nodes = FxHashSet::default();
157
158 for events in potential_events.values() {
160 let mut child_node: Option<Key> = None;
161
162 for PotentialEvent { node_key, name, .. } in events.iter().rev() {
163 if let Some(child_node) = child_node
164 && !events_measurer.is_node_parent_of(&child_node, *node_key)
165 {
166 continue;
167 }
168
169 if !events_measurer.is_node_transparent(node_key) && !name.does_go_through_solid() {
170 child_node = Some(*node_key);
174 }
175
176 match name {
177 name if name.is_moved() => {
179 hovered_nodes.insert(*node_key);
181
182 #[cfg(debug_assertions)]
183 tracing::info!("Marked as hovered {:?}", node_key);
184 }
185
186 name if name.is_pressed() => {
188 pressed_nodes.insert(*node_key);
190
191 #[cfg(debug_assertions)]
192 tracing::info!("Marked as pressed {:?}", node_key);
193 }
194 _ => {}
195 }
196 }
197 }
198 NodesStatesUpdate {
199 pressed_nodes,
200 hovered_nodes,
201 }
202 }
203
204 pub fn apply_update(&mut self, update: NodesStatesUpdate<Key>) {
207 self.hovered_nodes.extend(update.hovered_nodes);
208 self.pressed_nodes.extend(update.pressed_nodes);
209 }
210
211 pub fn is_hovered(&self, key: Key) -> bool {
212 self.hovered_nodes.contains(&key)
213 }
214
215 pub fn is_pressed(&self, key: Key) -> bool {
216 self.pressed_nodes.contains(&key)
217 }
218}
219
220#[derive(Clone, Debug, PartialEq)]
221pub struct NodesStatesUpdate<Key: NodeKey> {
222 pressed_nodes: FxHashSet<Key>,
223 hovered_nodes: FxHashSet<Key>,
224}
225
226impl<Key: NodeKey> Default for NodesStatesUpdate<Key> {
227 fn default() -> Self {
228 Self {
229 pressed_nodes: HashSet::default(),
230 hovered_nodes: HashSet::default(),
231 }
232 }
233}
234
235impl<Key: NodeKey> NodesStatesUpdate<Key> {
236 pub fn discard<Name: NameOfEvent>(&mut self, name: &Name, node_key: &Key) {
238 match name {
239 _ if name.is_moved() => {
241 self.hovered_nodes.remove(node_key);
242 }
243 _ if name.is_pressed() => {
244 self.pressed_nodes.remove(node_key);
245 }
246 _ => {}
247 }
248 }
249}