1use super::*;
2
3pub fn hit_test_subtree(widget: &dyn Widget, local_pos: Point) -> Option<Vec<usize>> {
12 if !widget.is_visible() || !widget.hit_test(local_pos) {
13 return None;
14 }
15 if widget.claims_pointer_exclusively(local_pos) {
18 return Some(vec![]);
19 }
20 for (i, child) in widget.children().iter().enumerate().rev() {
22 let child_local = Point::new(
23 local_pos.x - child.bounds().x,
24 local_pos.y - child.bounds().y,
25 );
26 if let Some(mut sub_path) = hit_test_subtree(child.as_ref(), child_local) {
27 sub_path.insert(0, i);
28 return Some(sub_path);
29 }
30 }
31 Some(vec![]) }
33
34pub fn active_modal_path(widget: &dyn Widget) -> Option<Vec<usize>> {
38 if !widget.is_visible() {
39 return None;
40 }
41 for (i, child) in widget.children().iter().enumerate().rev() {
42 if let Some(mut sub_path) = active_modal_path(child.as_ref()) {
43 sub_path.insert(0, i);
44 return Some(sub_path);
45 }
46 }
47 if widget.has_active_modal() {
48 Some(vec![])
49 } else {
50 None
51 }
52}
53
54pub fn global_overlay_hit_path(widget: &dyn Widget, local_pos: Point) -> Option<Vec<usize>> {
60 if !widget.is_visible() {
61 return None;
62 }
63 for (i, child) in widget.children().iter().enumerate().rev() {
64 let child_local = Point::new(
65 local_pos.x - child.bounds().x,
66 local_pos.y - child.bounds().y,
67 );
68 if let Some(mut sub_path) = global_overlay_hit_path(child.as_ref(), child_local) {
69 sub_path.insert(0, i);
70 return Some(sub_path);
71 }
72 }
73 if widget.hit_test_global_overlay(local_pos) {
74 Some(vec![])
75 } else {
76 None
77 }
78}
79
80pub fn dispatch_event(
86 root: &mut Box<dyn Widget>,
87 path: &[usize],
88 event: &Event,
89 pos_in_root: Point,
90) -> EventResult {
91 if path.is_empty() {
92 let before = crate::animation::invalidation_epoch();
93 let result = root.on_event(event);
94 if result == EventResult::Consumed || before != crate::animation::invalidation_epoch() {
95 root.mark_dirty();
96 }
97 return result;
98 }
99 let idx = path[0];
100 if idx >= root.children().len() {
105 return root.on_event(event);
106 }
107 let child_bounds = root.children()[idx].bounds();
108 let child_pos = Point::new(
109 pos_in_root.x - child_bounds.x,
110 pos_in_root.y - child_bounds.y,
111 );
112 let translated_event = translate_event(event, child_pos);
113
114 let before_child = crate::animation::invalidation_epoch();
115 let child_result = dispatch_event(
116 &mut root.children_mut()[idx],
117 &path[1..],
118 &translated_event,
119 child_pos,
120 );
121 if child_result == EventResult::Consumed {
122 root.mark_dirty();
123 return EventResult::Consumed;
124 }
125 if before_child != crate::animation::invalidation_epoch() {
126 root.mark_dirty();
127 }
128 let before_self = crate::animation::invalidation_epoch();
130 let result = root.on_event(event);
131 if result == EventResult::Consumed || before_self != crate::animation::invalidation_epoch() {
132 root.mark_dirty();
133 }
134 result
135}
136
137pub fn dispatch_unconsumed_key(
141 widget: &mut dyn Widget,
142 key: &Key,
143 modifiers: Modifiers,
144) -> EventResult {
145 if !widget.is_visible() {
146 return EventResult::Ignored;
147 }
148 for child in widget.children_mut().iter_mut().rev() {
149 if dispatch_unconsumed_key(child.as_mut(), key, modifiers) == EventResult::Consumed {
150 widget.mark_dirty();
151 return EventResult::Consumed;
152 }
153 }
154 let before = crate::animation::invalidation_epoch();
155 let result = widget.on_unconsumed_key(key, modifiers);
156 if result == EventResult::Consumed || before != crate::animation::invalidation_epoch() {
157 widget.mark_dirty();
158 }
159 result
160}
161
162fn translate_event(event: &Event, new_pos: Point) -> Event {
165 match event {
166 Event::MouseMove { .. } => Event::MouseMove { pos: new_pos },
167 Event::MouseDown {
168 button, modifiers, ..
169 } => Event::MouseDown {
170 pos: new_pos,
171 button: *button,
172 modifiers: *modifiers,
173 },
174 Event::MouseUp {
175 button, modifiers, ..
176 } => Event::MouseUp {
177 pos: new_pos,
178 button: *button,
179 modifiers: *modifiers,
180 },
181 Event::MouseWheel {
182 delta_y,
183 delta_x,
184 modifiers,
185 ..
186 } => Event::MouseWheel {
187 pos: new_pos,
188 delta_y: *delta_y,
189 delta_x: *delta_x,
190 modifiers: *modifiers,
191 },
192 other => other.clone(),
193 }
194}
195
196#[derive(Clone)]
202pub struct InspectorNode {
203 pub type_name: &'static str,
204 pub screen_bounds: Rect,
206 pub depth: usize,
207 pub properties: Vec<(&'static str, String)>,
209}
210
211thread_local! {
215 static CURRENT_MOUSE_WORLD: std::cell::Cell<Option<Point>> =
216 std::cell::Cell::new(None);
217 static CURRENT_VIEWPORT: std::cell::Cell<Size> =
218 std::cell::Cell::new(Size::new(1.0, 1.0));
219}
220
221pub fn set_current_mouse_world(p: Point) {
224 CURRENT_MOUSE_WORLD.with(|c| c.set(Some(p)));
225}
226
227pub fn current_mouse_world() -> Option<Point> {
234 CURRENT_MOUSE_WORLD.with(|c| c.get())
235}
236
237pub fn set_current_viewport(s: Size) {
239 CURRENT_VIEWPORT.with(|c| c.set(s));
240}
241
242pub fn current_viewport() -> Size {
244 CURRENT_VIEWPORT.with(|c| c.get())
245}
246
247pub fn find_widget_by_id<'a>(widget: &'a dyn Widget, id: &str) -> Option<&'a dyn Widget> {
252 if widget.id() == Some(id) {
253 return Some(widget);
254 }
255 for child in widget.children() {
256 if let Some(found) = find_widget_by_id(child.as_ref(), id) {
257 return Some(found);
258 }
259 }
260 None
261}
262
263pub fn find_widget_by_id_mut<'a>(
267 widget: &'a mut dyn Widget,
268 id: &str,
269) -> Option<&'a mut dyn Widget> {
270 if widget.id() == Some(id) {
271 return Some(widget);
272 }
273 for child in widget.children_mut().iter_mut() {
274 if let Some(found) = find_widget_by_id_mut(child.as_mut(), id) {
275 return Some(found);
276 }
277 }
278 None
279}
280
281pub fn find_widget_by_type<'a>(widget: &'a dyn Widget, type_name: &str) -> Option<&'a dyn Widget> {
286 if widget.type_name() == type_name {
287 return Some(widget);
288 }
289 for child in widget.children() {
290 if let Some(found) = find_widget_by_type(child.as_ref(), type_name) {
291 return Some(found);
292 }
293 }
294 None
295}
296
297pub fn collect_inspector_nodes(
302 widget: &dyn Widget,
303 depth: usize,
304 screen_origin: Point,
305 out: &mut Vec<InspectorNode>,
306) {
307 if !widget.is_visible() {
310 return;
311 }
312 if !widget.show_in_inspector() {
314 return;
315 }
316
317 let b = widget.bounds();
318 let abs = Rect::new(
319 screen_origin.x + b.x,
320 screen_origin.y + b.y,
321 b.width,
322 b.height,
323 );
324 let mut props = vec![(
328 "backbuffer",
329 if widget.has_backbuffer() {
330 "true".to_string()
331 } else {
332 "false".to_string()
333 },
334 )];
335 props.extend(widget.properties());
336 out.push(InspectorNode {
337 type_name: widget.type_name(),
338 screen_bounds: abs,
339 depth,
340 properties: props,
341 });
342
343 if !widget.contributes_children_to_inspector() {
348 return;
349 }
350
351 let child_origin = Point::new(abs.x, abs.y);
352 for child in widget.children() {
353 collect_inspector_nodes(child.as_ref(), depth + 1, child_origin, out);
354 }
355}