use super::*;
pub fn mark_subtree_dirty(widget: &mut dyn Widget) {
widget.mark_dirty();
for child in widget.children_mut().iter_mut() {
mark_subtree_dirty(child.as_mut());
}
}
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_event_dyn(
root: &mut 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,
},
Event::FileDropped { paths, .. } => Event::FileDropped {
pos: new_pos,
paths: paths.clone(),
},
other => other.clone(),
}
}
pub fn dispatch_event_broadcast(
root: &mut Box<dyn Widget>,
event: &Event,
pos_in_root: Point,
) -> EventResult {
if !root.is_visible() {
return EventResult::Ignored;
}
for i in (0..root.children().len()).rev() {
let child_bounds = root.children()[i].bounds();
let child_pos = Point::new(
pos_in_root.x - child_bounds.x,
pos_in_root.y - child_bounds.y,
);
let translated = translate_event(event, child_pos);
if dispatch_event_broadcast(&mut root.children_mut()[i], &translated, child_pos)
== EventResult::Consumed
{
root.mark_dirty();
return EventResult::Consumed;
}
}
let result = root.on_event(event);
if result == EventResult::Consumed {
root.mark_dirty();
}
result
}