use super::*;
pub fn hit_test_subtree(widget: &dyn Widget, local_pos: Point) -> Option<Vec<usize>> {
if !widget.is_visible() || !widget.hit_test(local_pos) {
return None;
}
if widget.claims_pointer_exclusively(local_pos) {
return Some(vec![]);
}
for (i, child) in widget.children().iter().enumerate().rev() {
let child_local = Point::new(
local_pos.x - child.bounds().x,
local_pos.y - child.bounds().y,
);
if let Some(mut sub_path) = hit_test_subtree(child.as_ref(), child_local) {
sub_path.insert(0, i);
return Some(sub_path);
}
}
Some(vec![]) }
pub fn active_modal_path(widget: &dyn Widget) -> Option<Vec<usize>> {
if !widget.is_visible() {
return None;
}
for (i, child) in widget.children().iter().enumerate().rev() {
if let Some(mut sub_path) = active_modal_path(child.as_ref()) {
sub_path.insert(0, i);
return Some(sub_path);
}
}
if widget.has_active_modal() {
Some(vec![])
} else {
None
}
}
pub fn global_overlay_hit_path(widget: &dyn Widget, local_pos: Point) -> Option<Vec<usize>> {
if !widget.is_visible() {
return None;
}
for (i, child) in widget.children().iter().enumerate().rev() {
let child_local = Point::new(
local_pos.x - child.bounds().x,
local_pos.y - child.bounds().y,
);
if let Some(mut sub_path) = global_overlay_hit_path(child.as_ref(), child_local) {
sub_path.insert(0, i);
return Some(sub_path);
}
}
if widget.hit_test_global_overlay(local_pos) {
Some(vec![])
} else {
None
}
}
pub fn dispatch_event(
root: &mut Box<dyn Widget>,
path: &[usize],
event: &Event,
pos_in_root: Point,
) -> EventResult {
if path.is_empty() {
let before = crate::animation::invalidation_epoch();
let result = root.on_event(event);
if result == EventResult::Consumed || before != crate::animation::invalidation_epoch() {
root.mark_dirty();
}
return result;
}
let idx = path[0];
if idx >= root.children().len() {
return root.on_event(event);
}
let child_bounds = root.children()[idx].bounds();
let child_pos = Point::new(
pos_in_root.x - child_bounds.x,
pos_in_root.y - child_bounds.y,
);
let translated_event = translate_event(event, child_pos);
let before_child = crate::animation::invalidation_epoch();
let child_result = dispatch_event(
&mut root.children_mut()[idx],
&path[1..],
&translated_event,
child_pos,
);
if child_result == EventResult::Consumed {
root.mark_dirty();
return EventResult::Consumed;
}
if before_child != crate::animation::invalidation_epoch() {
root.mark_dirty();
}
let before_self = crate::animation::invalidation_epoch();
let result = root.on_event(event);
if result == EventResult::Consumed || before_self != crate::animation::invalidation_epoch() {
root.mark_dirty();
}
result
}
pub fn dispatch_unconsumed_key(
widget: &mut dyn Widget,
key: &Key,
modifiers: Modifiers,
) -> EventResult {
if !widget.is_visible() {
return EventResult::Ignored;
}
for child in widget.children_mut().iter_mut().rev() {
if dispatch_unconsumed_key(child.as_mut(), key, modifiers) == EventResult::Consumed {
widget.mark_dirty();
return EventResult::Consumed;
}
}
let before = crate::animation::invalidation_epoch();
let result = widget.on_unconsumed_key(key, modifiers);
if result == EventResult::Consumed || before != crate::animation::invalidation_epoch() {
widget.mark_dirty();
}
result
}
fn translate_event(event: &Event, new_pos: Point) -> Event {
match event {
Event::MouseMove { .. } => Event::MouseMove { pos: new_pos },
Event::MouseDown {
button, modifiers, ..
} => Event::MouseDown {
pos: new_pos,
button: *button,
modifiers: *modifiers,
},
Event::MouseUp {
button, modifiers, ..
} => Event::MouseUp {
pos: new_pos,
button: *button,
modifiers: *modifiers,
},
Event::MouseWheel {
delta_y,
delta_x,
modifiers,
..
} => Event::MouseWheel {
pos: new_pos,
delta_y: *delta_y,
delta_x: *delta_x,
modifiers: *modifiers,
},
other => other.clone(),
}
}
#[derive(Clone)]
pub struct InspectorNode {
pub type_name: &'static str,
pub screen_bounds: Rect,
pub depth: usize,
pub properties: Vec<(&'static str, String)>,
}
thread_local! {
static CURRENT_MOUSE_WORLD: std::cell::Cell<Option<Point>> =
std::cell::Cell::new(None);
static CURRENT_VIEWPORT: std::cell::Cell<Size> =
std::cell::Cell::new(Size::new(1.0, 1.0));
}
pub fn set_current_mouse_world(p: Point) {
CURRENT_MOUSE_WORLD.with(|c| c.set(Some(p)));
}
pub fn current_mouse_world() -> Option<Point> {
CURRENT_MOUSE_WORLD.with(|c| c.get())
}
pub fn set_current_viewport(s: Size) {
CURRENT_VIEWPORT.with(|c| c.set(s));
}
pub fn current_viewport() -> Size {
CURRENT_VIEWPORT.with(|c| c.get())
}
pub fn find_widget_by_id<'a>(widget: &'a dyn Widget, id: &str) -> Option<&'a dyn Widget> {
if widget.id() == Some(id) {
return Some(widget);
}
for child in widget.children() {
if let Some(found) = find_widget_by_id(child.as_ref(), id) {
return Some(found);
}
}
None
}
pub fn find_widget_by_id_mut<'a>(
widget: &'a mut dyn Widget,
id: &str,
) -> Option<&'a mut dyn Widget> {
if widget.id() == Some(id) {
return Some(widget);
}
for child in widget.children_mut().iter_mut() {
if let Some(found) = find_widget_by_id_mut(child.as_mut(), id) {
return Some(found);
}
}
None
}
pub fn find_widget_by_type<'a>(widget: &'a dyn Widget, type_name: &str) -> Option<&'a dyn Widget> {
if widget.type_name() == type_name {
return Some(widget);
}
for child in widget.children() {
if let Some(found) = find_widget_by_type(child.as_ref(), type_name) {
return Some(found);
}
}
None
}
pub fn collect_inspector_nodes(
widget: &dyn Widget,
depth: usize,
screen_origin: Point,
out: &mut Vec<InspectorNode>,
) {
if !widget.is_visible() {
return;
}
if !widget.show_in_inspector() {
return;
}
let b = widget.bounds();
let abs = Rect::new(
screen_origin.x + b.x,
screen_origin.y + b.y,
b.width,
b.height,
);
let mut props = vec![(
"backbuffer",
if widget.has_backbuffer() {
"true".to_string()
} else {
"false".to_string()
},
)];
props.extend(widget.properties());
out.push(InspectorNode {
type_name: widget.type_name(),
screen_bounds: abs,
depth,
properties: props,
});
if !widget.contributes_children_to_inspector() {
return;
}
let child_origin = Point::new(abs.x, abs.y);
for child in widget.children() {
collect_inspector_nodes(child.as_ref(), depth + 1, child_origin, out);
}
}