Merge remote-tracking branch 'upstream/master' into fix_nonbubbling_web_events

This commit is contained in:
Evan Almloff committed 2022-06-22 13:59:10 -05:00
commit 11d9a7d013
55 files changed
+5384 -437

No files matched your search

+130 -50
View File
@@ -12,7 +12,7 @@ use dioxus_html::input_data::{MouseButton as DioxusMouseButton, MouseButtonSet};
use dioxus_html::{event_bubbles, on::*, KeyCode};
use std::{
any::Any,
cell::RefCell,
cell::{RefCell, RefMut},
rc::Rc,
sync::Arc,
time::{Duration, Instant},
@@ -20,6 +20,7 @@ use std::{
use taffy::geometry::{Point, Size};
use taffy::{prelude::Layout, Taffy};
use crate::FocusState;
use crate::{Dom, Node};
// a wrapper around the input state for easier access
@@ -36,22 +37,22 @@ use crate::{Dom, Node};
// pub fn mouse(&self) -> Option<MouseData> {
// let data = (**self.0).borrow();
// data.mouse.as_ref().map(|m| m.clone())
// mouse.as_ref().map(|m| m.clone())
// }
// pub fn wheel(&self) -> Option<WheelData> {
// let data = (**self.0).borrow();
// data.wheel.as_ref().map(|w| w.clone())
// wheel.as_ref().map(|w| w.clone())
// }
// pub fn screen(&self) -> Option<(u16, u16)> {
// let data = (**self.0).borrow();
// data.screen.as_ref().map(|m| m.clone())
// screen.as_ref().map(|m| m.clone())
// }
// pub fn last_key_pressed(&self) -> Option<KeyboardData> {
// let data = (**self.0).borrow();
// data.last_key_pressed
// last_key_pressed
// .as_ref()
// .map(|k| &k.0.clone())
// }
@@ -84,6 +85,7 @@ pub struct InnerInputState {
wheel: Option<WheelData>,
last_key_pressed: Option<(KeyboardData, Instant)>,
screen: Option<(u16, u16)>,
pub(crate) focus_state: FocusState,
// subscribers: Vec<Rc<dyn Fn() + 'static>>,
}
@@ -95,6 +97,7 @@ impl InnerInputState {
last_key_pressed: None,
screen: None,
// subscribers: Vec::new(),
focus_state: FocusState::default(),
}
}
@@ -151,7 +154,7 @@ impl InnerInputState {
fn update(
&mut self,
evts: &mut [EventCore],
evts: &mut Vec<EventCore>,
resolved_events: &mut Vec<UserEvent>,
layout: &Taffy,
dom: &mut Dom,
@@ -160,19 +163,57 @@ impl InnerInputState {
self.wheel = None;
let old_focus = self.focus_state.last_focused_id;
evts.retain(|e| match &e.1 {
EventData::Keyboard(k) => match k.key_code {
KeyCode::Tab => !self.focus_state.progress(dom, !k.shift_key),
_ => true,
},
_ => true,
});
for e in evts.iter_mut() {
self.apply_event(e);
}
self.resolve_mouse_events(previous_mouse, resolved_events, layout, dom);
if old_focus != self.focus_state.last_focused_id {
if let Some(id) = self.focus_state.last_focused_id {
resolved_events.push(UserEvent {
scope_id: None,
priority: EventPriority::Medium,
name: "focus",
element: Some(id),
data: Arc::new(FocusData {}),
});
resolved_events.push(UserEvent {
scope_id: None,
priority: EventPriority::Medium,
name: "focusin",
element: Some(id),
data: Arc::new(FocusData {}),
});
}
if let Some(id) = old_focus {
resolved_events.push(UserEvent {
scope_id: None,
priority: EventPriority::Medium,
name: "focusout",
element: Some(id),
data: Arc::new(FocusData {}),
});
}
}
// for s in &self.subscribers {
// s();
// }
}
fn resolve_mouse_events(
&self,
&mut self,
previous_mouse: Option<MouseData>,
resolved_events: &mut Vec<UserEvent>,
layout: &Taffy,
@@ -257,16 +298,16 @@ impl InnerInputState {
if old_pos != Some(new_pos) {
let mut will_bubble = FxHashSet::default();
for node in dom.get_listening_sorted("mousemove") {
let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
let node_layout = get_abs_layout(node, dom, layout);
let previously_contained = old_pos
.filter(|pos| layout_contains_point(node_layout, *pos))
.filter(|pos| layout_contains_point(&node_layout, *pos))
.is_some();
let currently_contains = layout_contains_point(node_layout, new_pos);
let currently_contains = layout_contains_point(&node_layout, new_pos);
if currently_contains && previously_contained {
try_create_event(
"mousemove",
Arc::new(prepare_mouse_data(mouse_data, node_layout)),
Arc::new(prepare_mouse_data(mouse_data, &node_layout)),
&mut will_bubble,
resolved_events,
node,
@@ -281,11 +322,11 @@ impl InnerInputState {
// mouseenter
let mut will_bubble = FxHashSet::default();
for node in dom.get_listening_sorted("mouseenter") {
let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
let node_layout = get_abs_layout(node, dom, layout);
let previously_contained = old_pos
.filter(|pos| layout_contains_point(node_layout, *pos))
.filter(|pos| layout_contains_point(&node_layout, *pos))
.is_some();
let currently_contains = layout_contains_point(node_layout, new_pos);
let currently_contains = layout_contains_point(&node_layout, new_pos);
if currently_contains && !previously_contained {
try_create_event(
@@ -304,16 +345,16 @@ impl InnerInputState {
// mouseover
let mut will_bubble = FxHashSet::default();
for node in dom.get_listening_sorted("mouseover") {
let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
let node_layout = get_abs_layout(node, dom, layout);
let previously_contained = old_pos
.filter(|pos| layout_contains_point(node_layout, *pos))
.filter(|pos| layout_contains_point(&node_layout, *pos))
.is_some();
let currently_contains = layout_contains_point(node_layout, new_pos);
let currently_contains = layout_contains_point(&node_layout, new_pos);
if currently_contains && !previously_contained {
try_create_event(
"mouseover",
Arc::new(prepare_mouse_data(mouse_data, node_layout)),
Arc::new(prepare_mouse_data(mouse_data, &node_layout)),
&mut will_bubble,
resolved_events,
node,
@@ -327,13 +368,13 @@ impl InnerInputState {
if was_pressed {
let mut will_bubble = FxHashSet::default();
for node in dom.get_listening_sorted("mousedown") {
let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
let currently_contains = layout_contains_point(node_layout, new_pos);
let node_layout = get_abs_layout(node, dom, layout);
let currently_contains = layout_contains_point(&node_layout, new_pos);
if currently_contains {
try_create_event(
"mousedown",
Arc::new(prepare_mouse_data(mouse_data, node_layout)),
Arc::new(prepare_mouse_data(mouse_data, &node_layout)),
&mut will_bubble,
resolved_events,
node,
@@ -348,13 +389,13 @@ impl InnerInputState {
if was_released {
let mut will_bubble = FxHashSet::default();
for node in dom.get_listening_sorted("mouseup") {
let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
let currently_contains = layout_contains_point(node_layout, new_pos);
let node_layout = get_abs_layout(node, dom, layout);
let currently_contains = layout_contains_point(&node_layout, new_pos);
if currently_contains {
try_create_event(
"mouseup",
Arc::new(prepare_mouse_data(mouse_data, node_layout)),
Arc::new(prepare_mouse_data(mouse_data, &node_layout)),
&mut will_bubble,
resolved_events,
node,
@@ -370,13 +411,13 @@ impl InnerInputState {
if mouse_data.trigger_button() == Some(DioxusMouseButton::Primary) && was_released {
let mut will_bubble = FxHashSet::default();
for node in dom.get_listening_sorted("click") {
let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
let currently_contains = layout_contains_point(node_layout, new_pos);
let node_layout = get_abs_layout(node, dom, layout);
let currently_contains = layout_contains_point(&node_layout, new_pos);
if currently_contains {
try_create_event(
"click",
Arc::new(prepare_mouse_data(mouse_data, node_layout)),
Arc::new(prepare_mouse_data(mouse_data, &node_layout)),
&mut will_bubble,
resolved_events,
node,
@@ -393,13 +434,13 @@ impl InnerInputState {
{
let mut will_bubble = FxHashSet::default();
for node in dom.get_listening_sorted("contextmenu") {
let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
let currently_contains = layout_contains_point(node_layout, new_pos);
let node_layout = get_abs_layout(node, dom, layout);
let currently_contains = layout_contains_point(&node_layout, new_pos);
if currently_contains {
try_create_event(
"contextmenu",
Arc::new(prepare_mouse_data(mouse_data, node_layout)),
Arc::new(prepare_mouse_data(mouse_data, &node_layout)),
&mut will_bubble,
resolved_events,
node,
@@ -416,9 +457,9 @@ impl InnerInputState {
if wheel_delta != 0.0 {
let mut will_bubble = FxHashSet::default();
for node in dom.get_listening_sorted("wheel") {
let node_layout =
layout.layout(node.state.layout.node.unwrap()).unwrap();
let currently_contains = layout_contains_point(node_layout, new_pos);
let node_layout = get_abs_layout(node, dom, layout);
let currently_contains = layout_contains_point(&node_layout, new_pos);
if currently_contains {
try_create_event(
@@ -439,16 +480,16 @@ impl InnerInputState {
// mouseleave
let mut will_bubble = FxHashSet::default();
for node in dom.get_listening_sorted("mouseleave") {
let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
let node_layout = get_abs_layout(node, dom, layout);
let previously_contained = old_pos
.filter(|pos| layout_contains_point(node_layout, *pos))
.filter(|pos| layout_contains_point(&node_layout, *pos))
.is_some();
let currently_contains = layout_contains_point(node_layout, new_pos);
let currently_contains = layout_contains_point(&node_layout, new_pos);
if !currently_contains && previously_contained {
try_create_event(
"mouseleave",
Arc::new(prepare_mouse_data(mouse_data, node_layout)),
Arc::new(prepare_mouse_data(mouse_data, &node_layout)),
&mut will_bubble,
resolved_events,
node,
@@ -462,16 +503,16 @@ impl InnerInputState {
// mouseout
let mut will_bubble = FxHashSet::default();
for node in dom.get_listening_sorted("mouseout") {
let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
let node_layout = get_abs_layout(node, dom, layout);
let previously_contained = old_pos
.filter(|pos| layout_contains_point(node_layout, *pos))
.filter(|pos| layout_contains_point(&node_layout, *pos))
.is_some();
let currently_contains = layout_contains_point(node_layout, new_pos);
let currently_contains = layout_contains_point(&node_layout, new_pos);
if !currently_contains && previously_contained {
try_create_event(
"mouseout",
Arc::new(prepare_mouse_data(mouse_data, node_layout)),
Arc::new(prepare_mouse_data(mouse_data, &node_layout)),
&mut will_bubble,
resolved_events,
node,
@@ -480,6 +521,22 @@ impl InnerInputState {
}
}
}
// update focus
if was_released {
let mut focus_id = None;
dom.traverse_depth_first(|node| {
let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
let currently_contains = layout_contains_point(node_layout, new_pos);
if currently_contains && node.state.focus.level.focusable() {
focus_id = Some(node.id);
}
});
if let Some(id) = focus_id {
self.focus_state.set_focus(dom, id);
}
}
}
}
@@ -488,6 +545,20 @@ impl InnerInputState {
// }
}
fn get_abs_layout(node: &Node, dom: &Dom, taffy: &Taffy) -> Layout {
let mut node_layout = *taffy.layout(node.state.layout.node.unwrap()).unwrap();
let mut current = node;
while let Some(parent_id) = current.parent {
let parent = &dom[parent_id];
current = parent;
let parent_layout = taffy.layout(parent.state.layout.node.unwrap()).unwrap();
node_layout.location.x += parent_layout.location.x;
node_layout.location.y += parent_layout.location.y;
}
node_layout
}
pub struct RinkInputHandler {
state: Rc<RefCell<InnerInputState>>,
queued_events: Rc<RefCell<Vec<EventCore>>>,
@@ -524,6 +595,10 @@ impl RinkInputHandler {
)
}
pub(crate) fn prune(&self, mutations: &dioxus_core::Mutations, rdom: &Dom) {
self.state.borrow_mut().focus_state.prune(mutations, rdom);
}
pub(crate) fn get_events(&self, layout: &Taffy, dom: &mut Dom) -> Vec<UserEvent> {
let mut resolved_events = Vec::new();
@@ -557,7 +632,6 @@ impl RinkInputHandler {
})
.map(|evt| (evt.0, evt.1.into_any()));
// todo: currently resolves events in all nodes, but once the focus system is added it should filter by focus
let mut hm: FxHashMap<&'static str, Vec<Arc<dyn Any + Send + Sync>>> = FxHashMap::default();
for (event, data) in events {
if let Some(v) = hm.get_mut(event) {
@@ -569,20 +643,26 @@ impl RinkInputHandler {
for (event, datas) in hm {
for node in dom.get_listening_sorted(event) {
for data in &datas {
resolved_events.push(UserEvent {
scope_id: None,
priority: EventPriority::Medium,
name: event,
element: Some(node.id),
data: data.clone(),
bubbles: event_bubbles(event),
});
if node.state.focused {
resolved_events.push(UserEvent {
scope_id: None,
priority: EventPriority::Medium,
name: event,
element: Some(node.id),
data: data.clone(),
bubbles: event_bubbles(event),
});
}
}
}
}
resolved_events
}
pub(crate) fn state(&self) -> RefMut<InnerInputState> {
self.state.borrow_mut()
}
}
// translate crossterm events into dioxus events