diff --git a/packages/native-core-macro/src/lib.rs b/packages/native-core-macro/src/lib.rs index 6174e756a..6c0cdb2d0 100644 --- a/packages/native-core-macro/src/lib.rs +++ b/packages/native-core-macro/src/lib.rs @@ -493,7 +493,7 @@ impl<'a> StateMember<'a> { let mask = self .dep_mems .iter() - .map(|m| 1 << m.id) + .map(|m| 1u64 << m.id) .fold(1 << self.mem.id, |a, b| a | b); quote! { #[derive(Clone, Copy)] diff --git a/packages/native-core/Cargo.toml b/packages/native-core/Cargo.toml index 0dc7e0d6e..f15a743f3 100644 --- a/packages/native-core/Cargo.toml +++ b/packages/native-core/Cargo.toml @@ -15,7 +15,7 @@ dioxus-core = { path = "../core", version = "^0.2.1" } dioxus-html = { path = "../html", version = "^0.2.1" } dioxus-core-macro = { path = "../core-macro", version = "^0.2.1" } -taffy = "0.2.0" +taffy = "0.2.1" smallvec = "1.6" rustc-hash = "1.1.0" anymap = "0.12.1" diff --git a/packages/native-core/src/lib.rs b/packages/native-core/src/lib.rs index 5db3a3609..ae739af86 100644 --- a/packages/native-core/src/lib.rs +++ b/packages/native-core/src/lib.rs @@ -18,8 +18,8 @@ pub mod utils; /// A id for a node that lives in the real dom. pub type RealNodeId = NodeId; -pub(crate) type FxDashMap = dashmap::DashMap>; -pub(crate) type FxDashSet = dashmap::DashSet>; +pub type FxDashMap = dashmap::DashMap>; +pub type FxDashSet = dashmap::DashSet>; pub type SendAnyMap = anymap::Map; /// Used in derived state macros diff --git a/packages/native-core/src/real_dom.rs b/packages/native-core/src/real_dom.rs index 5ef100082..f6b58a933 100644 --- a/packages/native-core/src/real_dom.rs +++ b/packages/native-core/src/real_dom.rs @@ -151,184 +151,180 @@ impl RealDom { } /// Updates the dom with some mutations and return a set of nodes that were updated. Pass the dirty nodes to update_state. - pub fn apply_mutations(&mut self, mutations_vec: Vec) -> DirtyNodeStates { + pub fn apply_mutations(&mut self, mutations: Mutations) -> DirtyNodeStates { let mut nodes_updated: FxHashMap = FxHashMap::default(); - for mutations in mutations_vec { - for template in mutations.templates { - let mut template_root_ids = Vec::new(); - for root in template.roots { - if let Some(id) = self.create_template_node(root, &mut nodes_updated) { - template_root_ids.push(id); + for template in mutations.templates { + let mut template_root_ids = Vec::new(); + for root in template.roots { + if let Some(id) = self.create_template_node(root, &mut nodes_updated) { + template_root_ids.push(id); + } + } + self.templates + .insert(template.name.to_string(), template_root_ids); + } + for e in mutations.edits { + use dioxus_core::Mutation::*; + match e { + AppendChildren { id, m } => { + let children = self.stack.split_off(m); + let parent = self.element_to_node_id(id); + for child in children { + self.add_child(parent, child); + mark_dirty(parent, NodeMask::ALL, &mut nodes_updated); } } - self.templates - .insert(template.name.to_string(), template_root_ids); - } - for e in mutations.edits { - use dioxus_core::Mutation::*; - match e { - AppendChildren { id, m } => { - let children = self.stack.split_off(m); - let parent = self.element_to_node_id(id); - for child in children { - self.add_child(parent, child); - mark_dirty(parent, NodeMask::ALL, &mut nodes_updated); - } + AssignId { path, id } => { + self.set_element_id(self.load_child(path), id); + } + CreatePlaceholder { id } => { + let node = Node::new(NodeType::Placeholder); + let node_id = self.create_node(node); + self.set_element_id(node_id, id); + self.stack.push(node_id); + mark_dirty(node_id, NodeMask::ALL, &mut nodes_updated); + } + CreateTextNode { value, id } => { + let node = Node::new(NodeType::Text { + text: value.to_string(), + }); + let node_id = self.create_node(node); + let node = self.tree.get_mut(node_id).unwrap(); + node.node_data.element_id = Some(id); + self.stack.push(node_id); + mark_dirty(node_id, NodeMask::new().with_text(), &mut nodes_updated); + } + HydrateText { path, value, id } => { + let node_id = self.load_child(path); + self.set_element_id(node_id, id); + let node = self.tree.get_mut(node_id).unwrap(); + if let NodeType::Text { text } = &mut node.node_data.node_type { + *text = value.to_string(); } - AssignId { path, id } => { - self.set_element_id(self.load_child(path), id); + mark_dirty(node_id, NodeMask::new().with_text(), &mut nodes_updated); + } + LoadTemplate { name, index, id } => { + let template_id = self.templates[name][index]; + let clone_id = self.clone_node(template_id, &mut nodes_updated); + self.set_element_id(clone_id, id); + } + ReplaceWith { id, m } => { + let new_nodes = self.stack.split_off(m); + let old_node_id = self.element_to_node_id(id); + for new in new_nodes { + self.tree.insert_after(old_node_id, new); + mark_dirty(new, NodeMask::ALL, &mut nodes_updated); } - CreatePlaceholder { id } => { - let node = Node::new(NodeType::Placeholder); - let node_id = self.create_node(node); - self.set_element_id(node_id, id); - self.stack.push(node_id); - mark_dirty(node_id, NodeMask::ALL, &mut nodes_updated); + self.tree.remove(old_node_id); + } + ReplacePlaceholder { path, m } => { + let new_nodes = self.stack.split_off(m); + let old_node_id = self.load_child(path); + for new in new_nodes { + self.tree.insert_after(old_node_id, new); + mark_dirty(new, NodeMask::ALL, &mut nodes_updated); } - CreateTextNode { value, id } => { - let node = Node::new(NodeType::Text { - text: value.to_string(), - }); - let node_id = self.create_node(node); - let node = self.tree.get_mut(node_id).unwrap(); - node.node_data.element_id = Some(id); - self.stack.push(node_id); - mark_dirty(node_id, NodeMask::new().with_text(), &mut nodes_updated); + self.tree.remove(old_node_id); + } + InsertAfter { id, m } => { + let new_nodes = self.stack.split_off(m); + let old_node_id = self.element_to_node_id(id); + for new in new_nodes { + self.tree.insert_after(old_node_id, new); + mark_dirty(new, NodeMask::ALL, &mut nodes_updated); } - HydrateText { path, value, id } => { - let node_id = self.load_child(path); - self.set_element_id(node_id, id); - let node = self.tree.get_mut(node_id).unwrap(); - if let NodeType::Text { text } = &mut node.node_data.node_type { - *text = value.to_string(); - } - mark_dirty(node_id, NodeMask::new().with_text(), &mut nodes_updated); + } + InsertBefore { id, m } => { + let new_nodes = self.stack.split_off(m); + let old_node_id = self.element_to_node_id(id); + for new in new_nodes { + self.tree.insert_before(old_node_id, new); + mark_dirty(new, NodeMask::ALL, &mut nodes_updated); } - LoadTemplate { name, index, id } => { - let template_id = self.templates[name][index]; - let clone_id = self.clone_node(template_id, &mut nodes_updated); - self.set_element_id(clone_id, id); + } + SetAttribute { + name, + value, + id, + ns, + } => { + let node_id = self.element_to_node_id(id); + let node = self.tree.get_mut(node_id).unwrap(); + if let NodeType::Element { attributes, .. } = &mut node.node_data.node_type { + attributes.insert( + OwnedAttributeDiscription { + name: name.to_string(), + namespace: ns.map(|s| s.to_string()), + volatile: false, + }, + crate::node::OwnedAttributeValue::Text(value.to_string()), + ); + mark_dirty( + node_id, + NodeMask::new_with_attrs(AttributeMask::single(name)), + &mut nodes_updated, + ); } - ReplaceWith { id, m } => { - let new_nodes = self.stack.split_off(m); - let old_node_id = self.element_to_node_id(id); - for new in new_nodes { - self.tree.insert_after(old_node_id, new); - mark_dirty(new, NodeMask::ALL, &mut nodes_updated); - } - self.tree.remove(old_node_id); + } + SetBoolAttribute { name, value, id } => { + let node_id = self.element_to_node_id(id); + let node = self.tree.get_mut(node_id).unwrap(); + if let NodeType::Element { attributes, .. } = &mut node.node_data.node_type { + attributes.insert( + OwnedAttributeDiscription { + name: name.to_string(), + namespace: None, + volatile: false, + }, + crate::node::OwnedAttributeValue::Bool(value), + ); + mark_dirty( + node_id, + NodeMask::new_with_attrs(AttributeMask::single(name)), + &mut nodes_updated, + ); } - ReplacePlaceholder { path, m } => { - let new_nodes = self.stack.split_off(m); - let old_node_id = self.load_child(path); - for new in new_nodes { - self.tree.insert_after(old_node_id, new); - mark_dirty(new, NodeMask::ALL, &mut nodes_updated); - } - self.tree.remove(old_node_id); + } + SetText { value, id } => { + let node_id = self.element_to_node_id(id); + let node = self.tree.get_mut(node_id).unwrap(); + if let NodeType::Text { text } = &mut node.node_data.node_type { + *text = value.to_string(); } - InsertAfter { id, m } => { - let new_nodes = self.stack.split_off(m); - let old_node_id = self.element_to_node_id(id); - for new in new_nodes { - self.tree.insert_after(old_node_id, new); - mark_dirty(new, NodeMask::ALL, &mut nodes_updated); - } - } - InsertBefore { id, m } => { - let new_nodes = self.stack.split_off(m); - let old_node_id = self.element_to_node_id(id); - for new in new_nodes { - self.tree.insert_before(old_node_id, new); - mark_dirty(new, NodeMask::ALL, &mut nodes_updated); - } - } - SetAttribute { - name, - value, - id, - ns, - } => { - let node_id = self.element_to_node_id(id); - let node = self.tree.get_mut(node_id).unwrap(); - if let NodeType::Element { attributes, .. } = &mut node.node_data.node_type - { - attributes.insert( - OwnedAttributeDiscription { - name: name.to_string(), - namespace: ns.map(|s| s.to_string()), - volatile: false, - }, - crate::node::OwnedAttributeValue::Text(value.to_string()), - ); - mark_dirty( - node_id, - NodeMask::new_with_attrs(AttributeMask::single(name)), - &mut nodes_updated, - ); - } - } - SetBoolAttribute { name, value, id } => { - let node_id = self.element_to_node_id(id); - let node = self.tree.get_mut(node_id).unwrap(); - if let NodeType::Element { attributes, .. } = &mut node.node_data.node_type - { - attributes.insert( - OwnedAttributeDiscription { - name: name.to_string(), - namespace: None, - volatile: false, - }, - crate::node::OwnedAttributeValue::Bool(value), - ); - mark_dirty( - node_id, - NodeMask::new_with_attrs(AttributeMask::single(name)), - &mut nodes_updated, - ); - } - } - SetText { value, id } => { - let node_id = self.element_to_node_id(id); - let node = self.tree.get_mut(node_id).unwrap(); - if let NodeType::Text { text } = &mut node.node_data.node_type { - *text = value.to_string(); - } - mark_dirty(node_id, NodeMask::new().with_text(), &mut nodes_updated); - } - NewEventListener { name, scope: _, id } => { - let node_id = self.element_to_node_id(id); - let node = self.tree.get_mut(node_id).unwrap(); - if let NodeType::Element { listeners, .. } = &mut node.node_data.node_type { - match self.nodes_listening.get_mut(name) { - Some(hs) => { - hs.insert(node_id); - } - None => { - let mut hs = FxHashSet::default(); - hs.insert(node_id); - self.nodes_listening.insert(name.to_string(), hs); - } + mark_dirty(node_id, NodeMask::new().with_text(), &mut nodes_updated); + } + NewEventListener { name, scope: _, id } => { + let node_id = self.element_to_node_id(id); + let node = self.tree.get_mut(node_id).unwrap(); + if let NodeType::Element { listeners, .. } = &mut node.node_data.node_type { + match self.nodes_listening.get_mut(name) { + Some(hs) => { + hs.insert(node_id); + } + None => { + let mut hs = FxHashSet::default(); + hs.insert(node_id); + self.nodes_listening.insert(name.to_string(), hs); } - listeners.insert(name.to_string()); } + listeners.insert(name.to_string()); } - RemoveEventListener { id, name } => { - let node_id = self.element_to_node_id(id); - let node = self.tree.get_mut(node_id).unwrap(); - if let NodeType::Element { listeners, .. } = &mut node.node_data.node_type { - listeners.remove(name); - } - self.nodes_listening.get_mut(name).unwrap().remove(&node_id); - } - Remove { id } => { - let node_id = self.element_to_node_id(id); - self.tree.remove(node_id); - } - PushRoot { id } => { - let node_id = self.element_to_node_id(id); - self.stack.push(node_id); + } + RemoveEventListener { id, name } => { + let node_id = self.element_to_node_id(id); + let node = self.tree.get_mut(node_id).unwrap(); + if let NodeType::Element { listeners, .. } = &mut node.node_data.node_type { + listeners.remove(name); } + self.nodes_listening.get_mut(name).unwrap().remove(&node_id); + } + Remove { id } => { + let node_id = self.element_to_node_id(id); + self.tree.remove(node_id); + } + PushRoot { id } => { + let node_id = self.element_to_node_id(id); + self.stack.push(node_id); } } } diff --git a/packages/tui/Cargo.toml b/packages/tui/Cargo.toml index 10f005bbc..116784c7b 100644 --- a/packages/tui/Cargo.toml +++ b/packages/tui/Cargo.toml @@ -23,10 +23,11 @@ crossterm = "0.23.0" anyhow = "1.0.42" tokio = { version = "1.15.0", features = ["full"] } futures = "0.3.19" -taffy = "0.1.0" +taffy = "0.2.1" smallvec = "1.6" rustc-hash = "1.1.0" anymap = "0.12.1" +futures-channel = "0.3.25" [dev-dependencies] dioxus = { path = "../dioxus" } diff --git a/packages/tui/src/focus.rs b/packages/tui/src/focus.rs index 9c070bc00..90d9e9da0 100644 --- a/packages/tui/src/focus.rs +++ b/packages/tui/src/focus.rs @@ -1,6 +1,7 @@ -use crate::{node::PreventDefault, Dom}; +use crate::{node::PreventDefault, TuiDom}; use dioxus_native_core::{ + tree::TreeView, utils::{ElementProduced, PersistantElementIter}, RealNodeId, }; @@ -10,7 +11,6 @@ use std::{cmp::Ordering, num::NonZeroU16}; use dioxus_native_core::{ node_ref::{AttributeMask, NodeMask, NodeView}, - real_dom::NodeType, state::NodeDepState, }; @@ -64,7 +64,8 @@ pub(crate) struct Focus { pub level: FocusLevel, } -impl NodeDepState<()> for Focus { +impl NodeDepState for Focus { + type DepState = (); type Ctx = (); const NODE_MASK: NodeMask = NodeMask::new_with_attrs(AttributeMask::Static(FOCUS_ATTRIBUTES)).with_listeners(); @@ -77,7 +78,7 @@ impl NodeDepState<()> for Focus { { if let Some(index) = a .value - .as_int32() + .as_int() .or_else(|| a.value.as_text().and_then(|v| v.parse::().ok())) { match index.cmp(&0) { @@ -126,7 +127,7 @@ pub(crate) struct FocusState { impl FocusState { /// Returns true if the focus has changed. - pub fn progress(&mut self, rdom: &mut Dom, forward: bool) -> bool { + pub fn progress(&mut self, rdom: &mut TuiDom, forward: bool) -> bool { if let Some(last) = self.last_focused_id { if rdom[last].state.prevent_default == PreventDefault::KeyDown { return false; @@ -234,10 +235,10 @@ impl FocusState { false } - pub(crate) fn prune(&mut self, mutations: &dioxus_core::Mutations, rdom: &Dom) { + pub(crate) fn prune(&mut self, mutations: &dioxus_core::Mutations, rdom: &TuiDom) { fn remove_children( to_prune: &mut [&mut Option], - rdom: &Dom, + rdom: &TuiDom, removed: RealNodeId, ) { for opt in to_prune.iter_mut() { @@ -247,8 +248,8 @@ impl FocusState { } } } - if let NodeType::Element { children, .. } = &rdom[removed].node_data.node_type { - for child in children { + if let Some(children) = &rdom.children_ids(removed) { + for child in *children { remove_children(to_prune, rdom, *child); } } @@ -258,22 +259,22 @@ impl FocusState { } for m in &mutations.edits { match m { - dioxus_core::DomEdit::ReplaceWith { root, .. } => remove_children( + dioxus_core::Mutation::ReplaceWith { id, .. } => remove_children( &mut [&mut self.last_focused_id], rdom, - rdom.resolve_maybe_id(*root), + rdom.element_to_node_id(*id), ), - dioxus_core::DomEdit::Remove { root } => remove_children( + dioxus_core::Mutation::Remove { id } => remove_children( &mut [&mut self.last_focused_id], rdom, - rdom.resolve_maybe_id(*root), + rdom.element_to_node_id(*id), ), _ => (), } } } - pub(crate) fn set_focus(&mut self, rdom: &mut Dom, id: RealNodeId) { + pub(crate) fn set_focus(&mut self, rdom: &mut TuiDom, id: RealNodeId) { if let Some(old) = self.last_focused_id.replace(id) { rdom[old].state.focused = false; } diff --git a/packages/tui/src/hooks.rs b/packages/tui/src/hooks.rs index 44ac276cc..197c7ea79 100644 --- a/packages/tui/src/hooks.rs +++ b/packages/tui/src/hooks.rs @@ -2,7 +2,8 @@ use crossterm::event::{ Event as TermEvent, KeyCode as TermKeyCode, KeyModifiers, MouseButton, MouseEventKind, }; use dioxus_core::*; -use dioxus_native_core::RealNodeId; +use dioxus_native_core::tree::TreeView; +use dioxus_native_core::NodeId; use rustc_hash::{FxHashMap, FxHashSet}; use dioxus_html::geometry::euclid::{Point2D, Rect, Size2D}; @@ -12,19 +13,25 @@ use dioxus_html::geometry::{ use dioxus_html::input_data::keyboard_types::{Code, Key, Location, Modifiers}; use dioxus_html::input_data::MouseButtonSet as DioxusMouseButtons; use dioxus_html::input_data::{MouseButton as DioxusMouseButton, MouseButtonSet}; -use dioxus_html::{event_bubbles, on::*}; +use dioxus_html::{event_bubbles, FocusData, KeyboardData, MouseData, WheelData}; use std::{ any::Any, cell::{RefCell, RefMut}, rc::Rc, - sync::Arc, time::{Duration, Instant}, }; use taffy::geometry::{Point, Size}; use taffy::{prelude::Layout, Taffy}; use crate::FocusState; -use crate::{Dom, Node}; +use crate::{TuiDom, TuiNode}; + +pub(crate) struct Event { + pub id: ElementId, + pub name: &'static str, + pub data: Rc, + pub bubbles: bool, +} // a wrapper around the input state for easier access // todo: fix loop @@ -71,12 +78,12 @@ enum EventData { Keyboard(KeyboardData), } impl EventData { - fn into_any(self) -> Arc { + fn into_any(self) -> Rc { match self { - Self::Mouse(m) => Arc::new(m), - Self::Wheel(w) => Arc::new(w), - Self::Screen(s) => Arc::new(s), - Self::Keyboard(k) => Arc::new(k), + Self::Mouse(m) => Rc::new(m), + Self::Wheel(w) => Rc::new(w), + Self::Screen(s) => Rc::new(s), + Self::Keyboard(k) => Rc::new(k), } } } @@ -164,9 +171,9 @@ impl InnerInputState { fn update( &mut self, evts: &mut Vec, - resolved_events: &mut Vec, + resolved_events: &mut Vec, layout: &Taffy, - dom: &mut Dom, + dom: &mut TuiDom, ) { let previous_mouse = self.mouse.clone(); @@ -192,33 +199,33 @@ impl InnerInputState { if old_focus != self.focus_state.last_focused_id { // elements with listeners will always have a element id - if let Some(RealNodeId::ElementId(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 {}), - bubbles: event_bubbles("focus"), - }); - resolved_events.push(UserEvent { - scope_id: None, - priority: EventPriority::Medium, - name: "focusin", - element: Some(id), - data: Arc::new(FocusData {}), - bubbles: event_bubbles("focusin"), - }); + if let Some(id) = self.focus_state.last_focused_id { + let element = dom.tree.get(id).unwrap(); + if let Some(id) = element.node_data.element_id { + resolved_events.push(Event { + name: "focus", + id, + data: Rc::new(FocusData {}), + bubbles: event_bubbles("focus"), + }); + resolved_events.push(Event { + name: "focusin", + id, + data: Rc::new(FocusData {}), + bubbles: event_bubbles("focusin"), + }); + } } - if let Some(RealNodeId::ElementId(id)) = old_focus { - resolved_events.push(UserEvent { - scope_id: None, - priority: EventPriority::Medium, - name: "focusout", - element: Some(id), - data: Arc::new(FocusData {}), - bubbles: event_bubbles("focusout"), - }); + if let Some(id) = old_focus { + let element = dom.tree.get(id).unwrap(); + if let Some(id) = element.node_data.element_id { + resolved_events.push(Event { + name: "focusout", + id, + data: Rc::new(FocusData {}), + bubbles: event_bubbles("focusout"), + }); + } } } @@ -230,9 +237,9 @@ impl InnerInputState { fn resolve_mouse_events( &mut self, previous_mouse: Option, - resolved_events: &mut Vec, + resolved_events: &mut Vec, layout: &Taffy, - dom: &mut Dom, + dom: &mut TuiDom, ) { fn layout_contains_point(layout: &Layout, point: ScreenPoint) -> bool { let Point { x, y } = layout.location; @@ -244,28 +251,29 @@ impl InnerInputState { fn try_create_event( name: &'static str, - data: Arc, - will_bubble: &mut FxHashSet, - resolved_events: &mut Vec, - node: &Node, - dom: &Dom, + data: Rc, + will_bubble: &mut FxHashSet, + resolved_events: &mut Vec, + node: &TuiNode, + dom: &TuiDom, ) { // only trigger event if the event was not triggered already by a child - let id = node.mounted_id(); + let id = node.node_data.node_id; if will_bubble.insert(id) { - let mut parent = node.node_data.parent; - while let Some(parent_id) = parent { + let mut parent = dom.parent(id); + while let Some(current_parent) = parent { + let parent_id = current_parent.node_data.node_id; will_bubble.insert(parent_id); - parent = dom[parent_id].node_data.parent; + parent = dom.parent(parent_id); + } + if let Some(id) = node.mounted_id() { + resolved_events.push(Event { + name, + id, + data, + bubbles: event_bubbles(name), + }) } - resolved_events.push(UserEvent { - scope_id: None, - priority: EventPriority::Medium, - name, - element: Some(id.as_element_id()), - data, - bubbles: event_bubbles(name), - }) } } @@ -326,7 +334,7 @@ impl InnerInputState { if currently_contains && previously_contained { try_create_event( "mousemove", - Arc::new(prepare_mouse_data(mouse_data, &node_layout)), + Rc::new(prepare_mouse_data(mouse_data, &node_layout)), &mut will_bubble, resolved_events, node, @@ -350,7 +358,7 @@ impl InnerInputState { if currently_contains && !previously_contained { try_create_event( "mouseenter", - Arc::new(mouse_data.clone()), + Rc::new(mouse_data.clone()), &mut will_bubble, resolved_events, node, @@ -373,7 +381,7 @@ impl InnerInputState { if currently_contains && !previously_contained { try_create_event( "mouseover", - Arc::new(prepare_mouse_data(mouse_data, &node_layout)), + Rc::new(prepare_mouse_data(mouse_data, &node_layout)), &mut will_bubble, resolved_events, node, @@ -393,7 +401,7 @@ impl InnerInputState { if currently_contains { try_create_event( "mousedown", - Arc::new(prepare_mouse_data(mouse_data, &node_layout)), + Rc::new(prepare_mouse_data(mouse_data, &node_layout)), &mut will_bubble, resolved_events, node, @@ -414,7 +422,7 @@ impl InnerInputState { if currently_contains { try_create_event( "mouseup", - Arc::new(prepare_mouse_data(mouse_data, &node_layout)), + Rc::new(prepare_mouse_data(mouse_data, &node_layout)), &mut will_bubble, resolved_events, node, @@ -436,7 +444,7 @@ impl InnerInputState { if currently_contains { try_create_event( "click", - Arc::new(prepare_mouse_data(mouse_data, &node_layout)), + Rc::new(prepare_mouse_data(mouse_data, &node_layout)), &mut will_bubble, resolved_events, node, @@ -459,7 +467,7 @@ impl InnerInputState { if currently_contains { try_create_event( "contextmenu", - Arc::new(prepare_mouse_data(mouse_data, &node_layout)), + Rc::new(prepare_mouse_data(mouse_data, &node_layout)), &mut will_bubble, resolved_events, node, @@ -483,7 +491,7 @@ impl InnerInputState { if currently_contains { try_create_event( "wheel", - Arc::new(w.clone()), + Rc::new(w.clone()), &mut will_bubble, resolved_events, node, @@ -508,7 +516,7 @@ impl InnerInputState { if !currently_contains && previously_contained { try_create_event( "mouseleave", - Arc::new(prepare_mouse_data(mouse_data, &node_layout)), + Rc::new(prepare_mouse_data(mouse_data, &node_layout)), &mut will_bubble, resolved_events, node, @@ -531,7 +539,7 @@ impl InnerInputState { if !currently_contains && previously_contained { try_create_event( "mouseout", - Arc::new(prepare_mouse_data(mouse_data, &node_layout)), + Rc::new(prepare_mouse_data(mouse_data, &node_layout)), &mut will_bubble, resolved_events, node, @@ -549,7 +557,7 @@ impl InnerInputState { let currently_contains = layout_contains_point(node_layout, new_pos); if currently_contains && node.state.focus.level.focusable() { - focus_id = Some(node.mounted_id()); + focus_id = Some(node.node_data.node_id); } }); if let Some(id) = focus_id { @@ -564,12 +572,11 @@ impl InnerInputState { // } } -fn get_abs_layout(node: &Node, dom: &Dom, taffy: &Taffy) -> Layout { +fn get_abs_layout(node: &TuiNode, dom: &TuiDom, 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.node_data.parent { - let parent = &dom[parent_id]; + while let Some(parent) = dom.parent(current.node_data.node_id) { current = parent; let parent_layout = taffy.layout(parent.state.layout.node.unwrap()).unwrap(); node_layout.location.x += parent_layout.location.x; @@ -614,11 +621,11 @@ impl RinkInputHandler { ) } - pub(crate) fn prune(&self, mutations: &dioxus_core::Mutations, rdom: &Dom) { + pub(crate) fn prune(&self, mutations: &dioxus_core::Mutations, rdom: &TuiDom) { self.state.borrow_mut().focus_state.prune(mutations, rdom); } - pub(crate) fn get_events(&self, layout: &Taffy, dom: &mut Dom) -> Vec { + pub(crate) fn get_events(&self, layout: &Taffy, dom: &mut TuiDom) -> Vec { let mut resolved_events = Vec::new(); (*self.state).borrow_mut().update( @@ -651,7 +658,7 @@ impl RinkInputHandler { }) .map(|evt| (evt.0, evt.1.into_any())); - let mut hm: FxHashMap<&'static str, Vec>> = FxHashMap::default(); + let mut hm: FxHashMap<&'static str, Vec>> = FxHashMap::default(); for (event, data) in events { if let Some(v) = hm.get_mut(event) { v.push(data); @@ -663,14 +670,14 @@ impl RinkInputHandler { for node in dom.get_listening_sorted(event) { for data in &datas { if node.state.focused { - resolved_events.push(UserEvent { - scope_id: None, - priority: EventPriority::Medium, - name: event, - element: Some(node.mounted_id().as_element_id()), - data: data.clone(), - bubbles: event_bubbles(event), - }); + if let Some(id) = node.mounted_id() { + resolved_events.push(Event { + name: event, + id, + data: data.clone(), + bubbles: event_bubbles(event), + }); + } } } } diff --git a/packages/tui/src/layout.rs b/packages/tui/src/layout.rs index e65e5b2df..2abebe856 100644 --- a/packages/tui/src/layout.rs +++ b/packages/tui/src/layout.rs @@ -1,12 +1,10 @@ -use std::cell::RefCell; -use std::rc::Rc; +use std::sync::{Arc, Mutex}; use dioxus_core::*; use dioxus_native_core::layout_attributes::apply_layout_attributes; +use dioxus_native_core::node::OwnedAttributeView; use dioxus_native_core::node_ref::{AttributeMask, NodeMask, NodeView}; -use dioxus_native_core::real_dom::OwnedAttributeView; use dioxus_native_core::state::ChildDepState; -use dioxus_native_core::RealNodeId; use dioxus_native_core_macro::sorted_str_slice; use taffy::prelude::*; @@ -42,8 +40,8 @@ pub(crate) struct TaffyLayout { } impl ChildDepState for TaffyLayout { - type Ctx = Rc>; - type DepState = Self; + type Ctx = Arc>; + type DepState = (Self,); // use tag to force this to be called when a node is built const NODE_MASK: NodeMask = NodeMask::new_with_attrs(AttributeMask::Static(SORTED_LAYOUT_ATTRS)) @@ -54,14 +52,14 @@ impl ChildDepState for TaffyLayout { fn reduce<'a>( &mut self, node: NodeView, - children: impl Iterator, + children: impl Iterator, ctx: &Self::Ctx, ) -> bool where Self::DepState: 'a, { let mut changed = false; - let mut taffy = ctx.borrow_mut(); + let mut taffy = ctx.lock().expect("poisoned taffy"); let mut style = Style::default(); if let Some(text) = node.text() { let char_len = text.chars().count(); @@ -81,7 +79,7 @@ impl ChildDepState for TaffyLayout { taffy.set_style(n, style).unwrap(); } } else { - self.node = PossiblyUninitalized::Initialized(taffy.new_node(style, &[]).unwrap()); + self.node = PossiblyUninitalized::Initialized(taffy.new_leaf(style).unwrap()); changed = true; } } else { @@ -101,14 +99,14 @@ impl ChildDepState for TaffyLayout { } // the root node fills the entire area - if node.id() == RealNodeId::ElementId(ElementId(0)) { + if node.id() == Some(ElementId(0)) { apply_layout_attributes("width", "100%", &mut style); apply_layout_attributes("height", "100%", &mut style); } // Set all direct nodes as our children let mut child_layout = vec![]; - for l in children { + for (l,) in children { child_layout.push(l.node.unwrap()); } @@ -121,7 +119,7 @@ impl ChildDepState for TaffyLayout { } } else { self.node = PossiblyUninitalized::Initialized( - taffy.new_node(style, &child_layout).unwrap(), + taffy.new_with_children(style, &child_layout).unwrap(), ); changed = true; } diff --git a/packages/tui/src/lib.rs b/packages/tui/src/lib.rs index 70d90ef0a..6b514492f 100644 --- a/packages/tui/src/lib.rs +++ b/packages/tui/src/lib.rs @@ -1,24 +1,23 @@ use anyhow::Result; -use anymap::AnyMap; use crossterm::{ event::{DisableMouseCapture, EnableMouseCapture, Event as TermEvent, KeyCode, KeyModifiers}, execute, terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, }; -use dioxus_core::exports::futures_channel::mpsc::unbounded; +use futures_channel::mpsc::unbounded; use dioxus_core::*; -use dioxus_native_core::{real_dom::RealDom, RealNodeId}; +use dioxus_native_core::{real_dom::RealDom, NodeId, SendAnyMap, FxDashSet}; use focus::FocusState; use futures::{ channel::mpsc::{UnboundedReceiver, UnboundedSender}, pin_mut, StreamExt, }; use query::Query; -use std::cell::RefCell; +use std::{cell::RefCell, sync::{Mutex, Arc}}; use std::rc::Rc; use std::{io, time::Duration}; use taffy::Taffy; -pub use taffy::{geometry::Point, prelude::Size}; +pub use taffy::{geometry::Point, prelude::*}; use tui::{backend::CrosstermBackend, layout::Rect, Terminal}; mod config; @@ -80,10 +79,10 @@ pub fn launch_cfg(app: Component<()>, cfg: Config) { let cx = dom.base_scope(); let rdom = Rc::new(RefCell::new(RealDom::new())); - let taffy = Rc::new(RefCell::new(Taffy::new())); - cx.provide_root_context(state); - cx.provide_root_context(TuiContext { tx: event_tx_clone }); - cx.provide_root_context(Query { + let taffy = Arc::new(Mutex::new(Taffy::new())); + cx.provide_context(state); + cx.provide_context(TuiContext { tx: event_tx_clone }); + cx.provide_context(Query { rdom: rdom.clone(), stretch: taffy.clone(), }); @@ -91,8 +90,8 @@ pub fn launch_cfg(app: Component<()>, cfg: Config) { { let mut rdom = rdom.borrow_mut(); let mutations = dom.rebuild(); - let to_update = rdom.apply_mutations(vec![mutations]); - let mut any_map = AnyMap::new(); + let to_update = rdom.apply_mutations(mutations); + let mut any_map = SendAnyMap::new(); any_map.insert(taffy.clone()); let _to_rerender = rdom.update_state(to_update, any_map); } @@ -114,8 +113,8 @@ fn render_vdom( mut event_reciever: UnboundedReceiver, handler: RinkInputHandler, cfg: Config, - rdom: Rc>, - taffy: Rc>, + rdom: Rc>, + taffy: Arc>, mut register_event: impl FnMut(crossterm::event::Event), ) -> Result<()> { tokio::runtime::Builder::new_current_thread() @@ -133,10 +132,8 @@ fn render_vdom( terminal.clear().unwrap(); } - let mut to_rerender: rustc_hash::FxHashSet = - vec![RealNodeId::ElementId(ElementId(0))] - .into_iter() - .collect(); + let mut to_rerender =FxDashSet::default(); + to_rerender.insert(NodeId(0)); let mut updated = true; loop { @@ -153,17 +150,17 @@ fn render_vdom( if !to_rerender.is_empty() || updated { updated = false; - fn resize(dims: Rect, taffy: &mut Taffy, rdom: &Dom) { + fn resize(dims: Rect, taffy: &mut Taffy, rdom: &TuiDom) { let width = dims.width; let height = dims.height; - let root_node = rdom[ElementId(0)].state.layout.node.unwrap(); + let root_node = rdom[NodeId(0)].state.layout.node.unwrap(); taffy .compute_layout( root_node, Size { - width: taffy::prelude::Number::Defined((width - 1) as f32), - height: taffy::prelude::Number::Defined((height - 1) as f32), + width: AvailableSpace::Definite((width - 1) as f32), + height: AvailableSpace::Definite((height - 1) as f32), }, ) .unwrap(); @@ -172,15 +169,15 @@ fn render_vdom( terminal.draw(|frame| { let rdom = rdom.borrow(); // size is guaranteed to not change when rendering - resize(frame.size(), &mut taffy.borrow_mut(), &rdom); - let root = &rdom[ElementId(0)]; + resize(frame.size(), &mut taffy.lock().expect("taffy lock poisoned"), &rdom); + let root = &rdom[NodeId(0)]; render::render_vnode( frame, - &taffy.borrow(), + &taffy.lock().expect("taffy lock poisoned"), &rdom, root, cfg, - Point::zero(), + Point::ZERO, ); })?; } else { @@ -192,7 +189,7 @@ fn render_vdom( width: 100, height: 100, }, - &mut taffy.borrow_mut(), + &mut taffy.lock().expect("taffy lock poisoned"), &rdom, ); } @@ -234,23 +231,21 @@ fn render_vdom( { let evts = { let mut rdom = rdom.borrow_mut(); - handler.get_events(&taffy.borrow(), &mut rdom) + handler.get_events(&taffy.lock().expect("taffy lock poisoned"), &mut rdom) }; { updated |= handler.state().focus_state.clean(); } for e in evts { - vdom.handle_message(SchedulerMsg::Event(e)); + vdom.handle_event(e.name, e.data, e.id, e.bubbles) } let mut rdom = rdom.borrow_mut(); - let mutations = vdom.work_with_deadline(|| false); - for m in &mutations { - handler.prune(m, &rdom); - } + let mutations = vdom.render_immediate(); + handler.prune(&mutations, &rdom); // updates the dom's nodes let to_update = rdom.apply_mutations(mutations); // update the style and layout - let mut any_map = AnyMap::new(); + let mut any_map = SendAnyMap::new(); any_map.insert(taffy.clone()); to_rerender = rdom.update_state(to_update, any_map); } diff --git a/packages/tui/src/node.rs b/packages/tui/src/node.rs index daa85500e..33f74a011 100644 --- a/packages/tui/src/node.rs +++ b/packages/tui/src/node.rs @@ -4,12 +4,12 @@ use crate::style_attributes::StyleModifier; use dioxus_native_core::{real_dom::RealDom, state::*}; use dioxus_native_core_macro::{sorted_str_slice, State}; -pub(crate) type Dom = RealDom; -pub(crate) type Node = dioxus_native_core::real_dom::Node; +pub(crate) type TuiDom = RealDom; +pub(crate) type TuiNode = dioxus_native_core::node::Node; #[derive(Debug, Clone, State, Default)] pub(crate) struct NodeState { - #[child_dep_state(layout, RefCell)] + #[child_dep_state(layout, Mutex)] pub layout: TaffyLayout, #[parent_dep_state(style)] pub style: StyleModifier, @@ -45,7 +45,8 @@ impl Default for PreventDefault { } } -impl NodeDepState<()> for PreventDefault { +impl NodeDepState for PreventDefault { + type DepState = (); type Ctx = (); const NODE_MASK: dioxus_native_core::node_ref::NodeMask = diff --git a/packages/tui/src/query.rs b/packages/tui/src/query.rs index 0a8a886cc..15b7fd7f2 100644 --- a/packages/tui/src/query.rs +++ b/packages/tui/src/query.rs @@ -1,6 +1,7 @@ use std::{ cell::{Ref, RefCell}, rc::Rc, + sync::{Arc, Mutex, MutexGuard}, }; use dioxus_core::ElementId; @@ -10,7 +11,7 @@ use taffy::{ Taffy, }; -use crate::Dom; +use crate::TuiDom; /// Allows querying the layout of nodes after rendering. It will only provide a correct value after a node is rendered. /// Provided as a root context for all tui applictions. @@ -45,24 +46,28 @@ use crate::Dom; /// ``` #[derive(Clone)] pub struct Query { - pub(crate) rdom: Rc>, - pub(crate) stretch: Rc>, + pub(crate) rdom: Rc>, + pub(crate) stretch: Arc>, } impl Query { pub fn get(&self, id: ElementId) -> ElementRef { - ElementRef::new(self.rdom.borrow(), self.stretch.borrow(), id) + ElementRef::new( + self.rdom.borrow(), + self.stretch.lock().expect("taffy lock poisoned"), + id, + ) } } pub struct ElementRef<'a> { - inner: Ref<'a, Dom>, - stretch: Ref<'a, Taffy>, + inner: Ref<'a, TuiDom>, + stretch: MutexGuard<'a, Taffy>, id: ElementId, } impl<'a> ElementRef<'a> { - fn new(inner: Ref<'a, Dom>, stretch: Ref<'a, Taffy>, id: ElementId) -> Self { + fn new(inner: Ref<'a, TuiDom>, stretch: MutexGuard<'a, Taffy>, id: ElementId) -> Self { Self { inner, stretch, id } } diff --git a/packages/tui/src/render.rs b/packages/tui/src/render.rs index 9cea0ced0..7beb543e2 100644 --- a/packages/tui/src/render.rs +++ b/packages/tui/src/render.rs @@ -1,3 +1,4 @@ +use dioxus_native_core::tree::TreeView; use std::io::Stdout; use taffy::{ geometry::Point, @@ -10,7 +11,7 @@ use crate::{ style::{RinkColor, RinkStyle}, style_attributes::{BorderEdge, BorderStyle}, widget::{RinkBuffer, RinkCell, RinkWidget, WidgetWithContext}, - Config, Dom, Node, + Config, TuiDom, TuiNode, }; const RADIUS_MULTIPLIER: [f32; 2] = [1.0, 0.5]; @@ -18,12 +19,12 @@ const RADIUS_MULTIPLIER: [f32; 2] = [1.0, 0.5]; pub(crate) fn render_vnode( frame: &mut tui::Frame>, layout: &Taffy, - rdom: &Dom, - node: &Node, + rdom: &TuiDom, + node: &TuiNode, cfg: Config, parent_location: Point, ) { - use dioxus_native_core::real_dom::NodeType; + use dioxus_native_core::node::NodeType; if let NodeType::Placeholder = &node.node_data.node_type { return; @@ -68,7 +69,7 @@ pub(crate) fn render_vnode( frame.render_widget(WidgetWithContext::new(label, cfg), area); } } - NodeType::Element { children, .. } => { + NodeType::Element { .. } => { let area = Rect::new(x as u16, y as u16, *width as u16, *height as u16); // the renderer will panic if a node is rendered out of range even if the size is zero @@ -76,7 +77,7 @@ pub(crate) fn render_vnode( frame.render_widget(WidgetWithContext::new(node, cfg), area); } - for c in children { + for c in rdom.children_ids(node.node_data.node_id).unwrap() { render_vnode(frame, layout, rdom, &rdom[*c], cfg, location); } } @@ -84,7 +85,7 @@ pub(crate) fn render_vnode( } } -impl RinkWidget for &Node { +impl RinkWidget for &TuiNode { fn render(self, area: Rect, mut buf: RinkBuffer<'_>) { use tui::symbols::line::*; diff --git a/packages/tui/src/style_attributes.rs b/packages/tui/src/style_attributes.rs index 0aa674dd8..9d1a61d12 100644 --- a/packages/tui/src/style_attributes.rs +++ b/packages/tui/src/style_attributes.rs @@ -31,8 +31,8 @@ use dioxus_native_core::{ layout_attributes::parse_value, + node::OwnedAttributeView, node_ref::{AttributeMask, NodeMask, NodeView}, - real_dom::OwnedAttributeView, state::ParentDepState, }; use dioxus_native_core_macro::sorted_str_slice; @@ -48,12 +48,12 @@ pub struct StyleModifier { impl ParentDepState for StyleModifier { type Ctx = (); - type DepState = Self; + type DepState = (Self,); // todo: seperate each attribute into it's own class const NODE_MASK: NodeMask = NodeMask::new_with_attrs(AttributeMask::Static(SORTED_STYLE_ATTRS)).with_element(); - fn reduce(&mut self, node: NodeView, parent: Option<&Self::DepState>, _: &Self::Ctx) -> bool { + fn reduce(&mut self, node: NodeView, parent: Option<(&Self,)>, _: &Self::Ctx) -> bool { let mut new = StyleModifier::default(); if parent.is_some() { new.core.fg = None; @@ -91,7 +91,7 @@ impl ParentDepState for StyleModifier { } // keep the text styling from the parent element - if let Some(parent) = parent { + if let Some((parent,)) = parent { let mut new_style = new.core.merge(parent.core); new_style.bg = new.core.bg; new.core = new_style;