1use super::*;
19
20pub fn mark_subtree_dirty(widget: &mut dyn Widget) {
28 widget.mark_dirty();
29 for child in widget.children_mut().iter_mut() {
30 mark_subtree_dirty(child.as_mut());
31 }
32}
33
34pub fn hit_test_subtree(widget: &dyn Widget, local_pos: Point) -> Option<Vec<usize>> {
43 if !widget.is_visible() || !widget.hit_test(local_pos) {
44 return None;
45 }
46 if widget.claims_pointer_exclusively(local_pos) {
49 return Some(vec![]);
50 }
51 for (i, child) in widget.children().iter().enumerate().rev() {
53 let child_local = Point::new(
54 local_pos.x - child.bounds().x,
55 local_pos.y - child.bounds().y,
56 );
57 if let Some(mut sub_path) = hit_test_subtree(child.as_ref(), child_local) {
58 sub_path.insert(0, i);
59 return Some(sub_path);
60 }
61 }
62 Some(vec![]) }
64
65pub fn active_modal_path(widget: &dyn Widget) -> Option<Vec<usize>> {
69 if !widget.is_visible() {
70 return None;
71 }
72 for (i, child) in widget.children().iter().enumerate().rev() {
73 if let Some(mut sub_path) = active_modal_path(child.as_ref()) {
74 sub_path.insert(0, i);
75 return Some(sub_path);
76 }
77 }
78 if widget.has_active_modal() {
79 Some(vec![])
80 } else {
81 None
82 }
83}
84
85pub fn global_overlay_hit_path(widget: &dyn Widget, local_pos: Point) -> Option<Vec<usize>> {
91 if !widget.is_visible() {
92 return None;
93 }
94 for (i, child) in widget.children().iter().enumerate().rev() {
95 let child_local = Point::new(
96 local_pos.x - child.bounds().x,
97 local_pos.y - child.bounds().y,
98 );
99 if let Some(mut sub_path) = global_overlay_hit_path(child.as_ref(), child_local) {
100 sub_path.insert(0, i);
101 return Some(sub_path);
102 }
103 }
104 if widget.hit_test_global_overlay(local_pos) {
105 Some(vec![])
106 } else {
107 None
108 }
109}
110
111pub fn dispatch_event(
117 root: &mut Box<dyn Widget>,
118 path: &[usize],
119 event: &Event,
120 pos_in_root: Point,
121) -> EventResult {
122 if path.is_empty() {
123 let before = crate::animation::invalidation_epoch();
124 let result = root.on_event(event);
125 if result == EventResult::Consumed || before != crate::animation::invalidation_epoch() {
126 root.mark_dirty();
127 }
128 return result;
129 }
130 let idx = path[0];
131 if idx >= root.children().len() {
136 return root.on_event(event);
137 }
138 let child_bounds = root.children()[idx].bounds();
139 let child_pos = Point::new(
140 pos_in_root.x - child_bounds.x,
141 pos_in_root.y - child_bounds.y,
142 );
143 let translated_event = translate_event(event, child_pos);
144
145 let before_child = crate::animation::invalidation_epoch();
146 let child_result = dispatch_event(
147 &mut root.children_mut()[idx],
148 &path[1..],
149 &translated_event,
150 child_pos,
151 );
152 if child_result == EventResult::Consumed {
153 root.mark_dirty();
154 return EventResult::Consumed;
155 }
156 if before_child != crate::animation::invalidation_epoch() {
157 root.mark_dirty();
158 }
159 let before_self = crate::animation::invalidation_epoch();
161 let result = root.on_event(event);
162 if result == EventResult::Consumed || before_self != crate::animation::invalidation_epoch() {
163 root.mark_dirty();
164 }
165 result
166}
167
168pub fn dispatch_event_dyn(
174 root: &mut dyn Widget,
175 path: &[usize],
176 event: &Event,
177 pos_in_root: Point,
178) -> EventResult {
179 if path.is_empty() {
180 let before = crate::animation::invalidation_epoch();
181 let result = root.on_event(event);
182 if result == EventResult::Consumed || before != crate::animation::invalidation_epoch() {
183 root.mark_dirty();
184 }
185 return result;
186 }
187 let idx = path[0];
188 if idx >= root.children().len() {
189 return root.on_event(event);
190 }
191 let child_bounds = root.children()[idx].bounds();
192 let child_pos = Point::new(
193 pos_in_root.x - child_bounds.x,
194 pos_in_root.y - child_bounds.y,
195 );
196 let translated_event = translate_event(event, child_pos);
197
198 let before_child = crate::animation::invalidation_epoch();
199 let child_result = dispatch_event(
202 &mut root.children_mut()[idx],
203 &path[1..],
204 &translated_event,
205 child_pos,
206 );
207 if child_result == EventResult::Consumed {
208 root.mark_dirty();
209 return EventResult::Consumed;
210 }
211 if before_child != crate::animation::invalidation_epoch() {
212 root.mark_dirty();
213 }
214 let before_self = crate::animation::invalidation_epoch();
215 let result = root.on_event(event);
216 if result == EventResult::Consumed || before_self != crate::animation::invalidation_epoch() {
217 root.mark_dirty();
218 }
219 result
220}
221
222pub fn dispatch_unconsumed_key(
226 widget: &mut dyn Widget,
227 key: &Key,
228 modifiers: Modifiers,
229) -> EventResult {
230 if !widget.is_visible() {
231 return EventResult::Ignored;
232 }
233 for child in widget.children_mut().iter_mut().rev() {
234 if dispatch_unconsumed_key(child.as_mut(), key, modifiers) == EventResult::Consumed {
235 widget.mark_dirty();
236 return EventResult::Consumed;
237 }
238 }
239 let before = crate::animation::invalidation_epoch();
240 let result = widget.on_unconsumed_key(key, modifiers);
241 if result == EventResult::Consumed || before != crate::animation::invalidation_epoch() {
242 widget.mark_dirty();
243 }
244 result
245}
246
247fn translate_event(event: &Event, new_pos: Point) -> Event {
250 match event {
251 Event::MouseMove { .. } => Event::MouseMove { pos: new_pos },
252 Event::MouseDown {
253 button, modifiers, ..
254 } => Event::MouseDown {
255 pos: new_pos,
256 button: *button,
257 modifiers: *modifiers,
258 },
259 Event::MouseUp {
260 button, modifiers, ..
261 } => Event::MouseUp {
262 pos: new_pos,
263 button: *button,
264 modifiers: *modifiers,
265 },
266 Event::MouseWheel {
267 delta_y,
268 delta_x,
269 modifiers,
270 ..
271 } => Event::MouseWheel {
272 pos: new_pos,
273 delta_y: *delta_y,
274 delta_x: *delta_x,
275 modifiers: *modifiers,
276 },
277 Event::FileDropped { paths, .. } => Event::FileDropped {
278 pos: new_pos,
279 paths: paths.clone(),
280 },
281 other => other.clone(),
282 }
283}
284
285pub fn dispatch_event_broadcast(
297 root: &mut Box<dyn Widget>,
298 event: &Event,
299 pos_in_root: Point,
300) -> EventResult {
301 if !root.is_visible() {
302 return EventResult::Ignored;
303 }
304 for i in (0..root.children().len()).rev() {
305 let child_bounds = root.children()[i].bounds();
306 let child_pos = Point::new(
307 pos_in_root.x - child_bounds.x,
308 pos_in_root.y - child_bounds.y,
309 );
310 let translated = translate_event(event, child_pos);
311 if dispatch_event_broadcast(&mut root.children_mut()[i], &translated, child_pos)
312 == EventResult::Consumed
313 {
314 root.mark_dirty();
315 return EventResult::Consumed;
316 }
317 }
318 let result = root.on_event(event);
319 if result == EventResult::Consumed {
320 root.mark_dirty();
321 }
322 result
323}