1
0
Эх сурвалжийг харах

bugfixes, docs, and pass clippy

Evan Almloff 3 жил өмнө
parent
commit
32b2e3a135

+ 41 - 8
docs/reference/src/platforms/tui.md

@@ -9,13 +9,12 @@ TUI support is currently quite experimental. Even the project name will change.
 ## Getting Set up
 
 
-To tinker with TUI support, start by making a new package and adding our TUI package from git.
+To tinker with TUI support, start by making a new package and adding our TUI feature.
 
 ```shell
 $ cargo new --bin demo
 $ cd demo
-$ cargo add dioxus
-$ cargo add rink --git https://github.com/DioxusLabs/rink.git
+$ cargo add dioxus --features tui
 ```
 
 
@@ -27,10 +26,7 @@ Then, edit your `main.rs` with the basic template.
 use dioxus::prelude::*;
 
 fn main() {
-    let mut dom = VirtualDom::new(app);
-    dom.rebuild();
-
-    rink::render_vdom(&mut dom).unwrap();
+    dioxus::tui::launch(app);
 }
 
 fn app(cx: Scope) -> Element {
@@ -54,7 +50,44 @@ To run our app:
 $ cargo run
 ```
 
-Press "q" to close the app (yes, this is hardcoded, we are working on handlers to expose this in your code.)
+Press "ctrl-c" to close the app. To switch from "ctrl-c" to  just "q" to quit you can launch the app with a Configeration to disable the default quit and use the root TuiContext to quit on your own.
+
+```rust
+//  main
+use dioxus::events::{KeyCode, KeyboardEvent};
+use dioxus::prelude::*;
+use dioxus::tui::TuiContext;
+
+fn main() {
+    dioxus::tui::launch_cfg(
+        app,
+        dioxus::tui::Config {
+            ctrl_c_quit: false,
+            // Some older terminals only support 16 colors or ANSI colors if your terminal is one of these change this to BaseColors or ANSI
+            rendering_mode: dioxus::tui::RenderingMode::Rgb,
+        },
+    );
+}
+
+fn app(cx: Scope) -> Element {
+    let tui_ctx: TuiContext = cx.consume_context().unwrap();
+
+    cx.render(rsx! {
+        div {
+            width: "100%",
+            height: "10px",
+            background_color: "red",
+            justify_content: "center",
+            align_items: "center",
+            onkeydown: move |k: KeyboardEvent| if let KeyCode::Q = k.data.key_code {
+                tui_ctx.quit();
+            },
+
+            "Hello world!"
+        }
+    })
+}
+```
 
 ## Notes
 

+ 1 - 0
examples/tui_color_test.rs

@@ -5,6 +5,7 @@ fn main() {
         app,
         dioxus::tui::Config {
             rendering_mode: dioxus::tui::RenderingMode::Ansi,
+            ..Default::default()
         },
     );
 }

+ 5 - 5
packages/native-core/src/layout_attributes.rs

@@ -255,11 +255,11 @@ pub enum UnitSystem {
     Point(f32),
 }
 
-impl Into<Dimension> for UnitSystem {
-    fn into(self) -> Dimension {
-        match self {
-            Self::Percent(v) => Dimension::Percent(v),
-            Self::Point(v) => Dimension::Points(v),
+impl From<UnitSystem> for Dimension {
+    fn from(other: UnitSystem) -> Dimension {
+        match other {
+            UnitSystem::Percent(v) => Dimension::Percent(v),
+            UnitSystem::Point(v) => Dimension::Points(v),
         }
     }
 }

+ 88 - 84
packages/native-core/src/real_dom.rs

@@ -12,25 +12,30 @@ use dioxus_core::{ElementId, Mutations, VNode, VirtualDom};
 #[derive(Debug)]
 pub struct RealDom<US: BubbledUpState = (), DS: PushedDownState = ()> {
     root: usize,
-    nodes: Vec<Option<TreeNode<US, DS>>>,
+    nodes: Vec<Option<Node<US, DS>>>,
     nodes_listening: FxHashMap<&'static str, FxHashSet<usize>>,
     node_stack: smallvec::SmallVec<[usize; 10]>,
 }
 
+impl<US: BubbledUpState, DS: PushedDownState> Default for RealDom<US, DS> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
 impl<US: BubbledUpState, DS: PushedDownState> RealDom<US, DS> {
     pub fn new() -> RealDom<US, DS> {
         RealDom {
             root: 0,
             nodes: {
-                let mut v = Vec::new();
-                v.push(Some(TreeNode::new(
+                let v = vec![Some(Node::new(
                     0,
-                    TreeNodeType::Element {
+                    NodeType::Element {
                         tag: "Root".to_string(),
                         namespace: Some("Root"),
                         children: Vec::new(),
                     },
-                )));
+                ))];
                 v
             },
             nodes_listening: FxHashMap::default(),
@@ -47,7 +52,7 @@ impl<US: BubbledUpState, DS: PushedDownState> RealDom<US, DS> {
                 match e {
                     PushRoot { root } => self.node_stack.push(root as usize),
                     AppendChildren { many } => {
-                        let target = if self.node_stack.len() >= many as usize + 1 {
+                        let target = if self.node_stack.len() > many as usize {
                             *self
                                 .node_stack
                                 .get(self.node_stack.len() - (many as usize + 1))
@@ -96,9 +101,9 @@ impl<US: BubbledUpState, DS: PushedDownState> RealDom<US, DS> {
                         self.remove(root as usize).unwrap();
                     }
                     CreateTextNode { root, text } => {
-                        let n = TreeNode::new(
+                        let n = Node::new(
                             root,
-                            TreeNodeType::Text {
+                            NodeType::Text {
                                 text: text.to_string(),
                             },
                         );
@@ -106,9 +111,9 @@ impl<US: BubbledUpState, DS: PushedDownState> RealDom<US, DS> {
                         self.node_stack.push(root as usize)
                     }
                     CreateElement { root, tag } => {
-                        let n = TreeNode::new(
+                        let n = Node::new(
                             root,
-                            TreeNodeType::Element {
+                            NodeType::Element {
                                 tag: tag.to_string(),
                                 namespace: None,
                                 children: Vec::new(),
@@ -118,9 +123,9 @@ impl<US: BubbledUpState, DS: PushedDownState> RealDom<US, DS> {
                         self.node_stack.push(root as usize)
                     }
                     CreateElementNs { root, tag, ns } => {
-                        let n = TreeNode::new(
+                        let n = Node::new(
                             root,
-                            TreeNodeType::Element {
+                            NodeType::Element {
                                 tag: tag.to_string(),
                                 namespace: Some(ns),
                                 children: Vec::new(),
@@ -130,7 +135,7 @@ impl<US: BubbledUpState, DS: PushedDownState> RealDom<US, DS> {
                         self.node_stack.push(root as usize)
                     }
                     CreatePlaceholder { root } => {
-                        let n = TreeNode::new(root, TreeNodeType::Placeholder);
+                        let n = Node::new(root, NodeType::Placeholder);
                         self.insert(n);
                         self.node_stack.push(root as usize)
                     }
@@ -159,7 +164,7 @@ impl<US: BubbledUpState, DS: PushedDownState> RealDom<US, DS> {
                         let target = &mut self[root as usize];
                         nodes_updated.push(root as usize);
                         match &mut target.node_type {
-                            TreeNodeType::Text { text } => {
+                            NodeType::Text { text } => {
                                 *text = new_text.to_string();
                             }
                             _ => unreachable!(),
@@ -204,13 +209,13 @@ impl<US: BubbledUpState, DS: PushedDownState> RealDom<US, DS> {
             let node_type = &node.node_type;
             let up_state = &mut node.up_state;
             let children = match node_type {
-                TreeNodeType::Element { children, .. } => Some(children),
+                NodeType::Element { children, .. } => Some(children),
                 _ => None,
             };
             // todo: reduce cloning state
             let old = up_state.clone();
             let mut new = up_state.clone();
-            let parent = node.parent.clone();
+            let parent = node.parent;
             new.reduce(
                 children
                     .unwrap_or(&Vec::new())
@@ -254,19 +259,16 @@ impl<US: BubbledUpState, DS: PushedDownState> RealDom<US, DS> {
             if new != old {
                 to_rerender.insert(id);
                 let node = &mut self[id as usize];
-                match &node.node_type {
-                    TreeNodeType::Element { children, .. } => {
-                        for c in children {
-                            let i = to_push.partition_point(|(other_id, h)| {
-                                *h < height + 1 || (*h == height + 1 && *other_id < c.0)
-                            });
-                            if i >= to_push.len() || to_push[i].0 != c.0 {
-                                to_push.insert(i, (c.0, height + 1));
-                            }
+                if let NodeType::Element { children, .. } = &node.node_type {
+                    for c in children {
+                        let i = to_push.partition_point(|(other_id, h)| {
+                            *h < height + 1 || (*h == height + 1 && *other_id < c.0)
+                        });
+                        if i >= to_push.len() || to_push[i].0 != c.0 {
+                            to_push.insert(i, (c.0, height + 1));
                         }
                     }
-                    _ => (),
-                };
+                }
                 node.down_state = new;
             }
         }
@@ -287,31 +289,25 @@ impl<US: BubbledUpState, DS: PushedDownState> RealDom<US, DS> {
     fn increase_height(&mut self, id: usize, amount: u16) {
         let n = &mut self[id];
         n.height += amount;
-        match &n.node_type {
-            TreeNodeType::Element { children, .. } => {
-                for c in children.clone() {
-                    self.increase_height(c.0, amount);
-                }
+        if let NodeType::Element { children, .. } = &n.node_type {
+            for c in children.clone() {
+                self.increase_height(c.0, amount);
             }
-            _ => (),
         }
     }
 
     // remove a node and it's children from the tree.
-    fn remove(&mut self, id: usize) -> Option<TreeNode<US, DS>> {
+    fn remove(&mut self, id: usize) -> Option<Node<US, DS>> {
         // We do not need to remove the node from the parent's children list for children.
         fn inner<US: BubbledUpState, DS: PushedDownState>(
             tree: &mut RealDom<US, DS>,
             id: usize,
-        ) -> Option<TreeNode<US, DS>> {
+        ) -> Option<Node<US, DS>> {
             let mut node = tree.nodes[id as usize].take()?;
-            match &mut node.node_type {
-                TreeNodeType::Element { children, .. } => {
-                    for c in children {
-                        inner(tree, c.0)?;
-                    }
+            if let NodeType::Element { children, .. } = &mut node.node_type {
+                for c in children {
+                    inner(tree, c.0)?;
                 }
-                _ => (),
             }
             Some(node)
         }
@@ -320,18 +316,15 @@ impl<US: BubbledUpState, DS: PushedDownState> RealDom<US, DS> {
             let parent = &mut self[parent];
             parent.remove_child(ElementId(id));
         }
-        match &mut node.node_type {
-            TreeNodeType::Element { children, .. } => {
-                for c in children {
-                    inner(self, c.0)?;
-                }
+        if let NodeType::Element { children, .. } = &mut node.node_type {
+            for c in children {
+                inner(self, c.0)?;
             }
-            _ => (),
         }
         Some(node)
     }
 
-    fn insert(&mut self, node: TreeNode<US, DS>) {
+    fn insert(&mut self, node: Node<US, DS>) {
         let current_len = self.nodes.len();
         let id = node.id.0;
         if current_len - 1 < node.id.0 {
@@ -341,15 +334,15 @@ impl<US: BubbledUpState, DS: PushedDownState> RealDom<US, DS> {
         self.nodes[id] = Some(node);
     }
 
-    pub fn get(&self, id: usize) -> Option<&TreeNode<US, DS>> {
+    pub fn get(&self, id: usize) -> Option<&Node<US, DS>> {
         self.nodes.get(id)?.as_ref()
     }
 
-    pub fn get_mut(&mut self, id: usize) -> Option<&mut TreeNode<US, DS>> {
+    pub fn get_mut(&mut self, id: usize) -> Option<&mut Node<US, DS>> {
         self.nodes.get_mut(id)?.as_mut()
     }
 
-    pub fn get_listening_sorted(&self, event: &'static str) -> Vec<&TreeNode<US, DS>> {
+    pub fn get_listening_sorted(&self, event: &'static str) -> Vec<&Node<US, DS>> {
         if let Some(nodes) = self.nodes_listening.get(event) {
             let mut listening: Vec<_> = nodes.iter().map(|id| &self[*id]).collect();
             listening.sort_by(|n1, n2| (n1.height).cmp(&n2.height).reverse());
@@ -369,7 +362,7 @@ impl<US: BubbledUpState, DS: PushedDownState> RealDom<US, DS> {
                 if let Some(id) = e.id.get() {
                     let tree_node = &self[id];
                     match &tree_node.node_type {
-                        TreeNodeType::Element {
+                        NodeType::Element {
                             tag,
                             namespace,
                             children,
@@ -398,7 +391,7 @@ impl<US: BubbledUpState, DS: PushedDownState> RealDom<US, DS> {
                 if let Some(id) = t.id.get() {
                     let tree_node = &self[id];
                     match &tree_node.node_type {
-                        TreeNodeType::Text { text } => t.text == text,
+                        NodeType::Text { text } => t.text == text,
                         _ => false,
                     }
                 } else {
@@ -420,36 +413,53 @@ impl<US: BubbledUpState, DS: PushedDownState> RealDom<US, DS> {
     }
 
     /// Call a function for each node in the tree, depth first.
-    pub fn traverse_depth_first(&self, mut f: impl FnMut(&TreeNode<US, DS>)) {
+    pub fn traverse_depth_first(&self, mut f: impl FnMut(&Node<US, DS>)) {
         fn inner<US: BubbledUpState, DS: PushedDownState>(
             tree: &RealDom<US, DS>,
             id: ElementId,
-            f: &mut impl FnMut(&TreeNode<US, DS>),
+            f: &mut impl FnMut(&Node<US, DS>),
         ) {
             let node = &tree[id];
             f(node);
-            match &node.node_type {
-                TreeNodeType::Element { children, .. } => {
-                    for c in children {
-                        inner(tree, *c, f);
-                    }
+            if let NodeType::Element { children, .. } = &node.node_type {
+                for c in children {
+                    inner(tree, *c, f);
                 }
-                _ => (),
             }
         }
-        match &self[self.root].node_type {
-            TreeNodeType::Element { children, .. } => {
-                for c in children {
-                    inner(self, *c, &mut f);
+        if let NodeType::Element { children, .. } = &self[self.root].node_type {
+            for c in children {
+                inner(self, *c, &mut f);
+            }
+        }
+    }
+
+    /// Call a function for each node in the tree, depth first.
+    pub fn traverse_depth_first_mut(&mut self, mut f: impl FnMut(&mut Node<US, DS>)) {
+        fn inner<US: BubbledUpState, DS: PushedDownState>(
+            tree: &mut RealDom<US, DS>,
+            id: ElementId,
+            f: &mut impl FnMut(&mut Node<US, DS>),
+        ) {
+            let node = &mut tree[id];
+            f(node);
+            if let NodeType::Element { children, .. } = &mut node.node_type {
+                for c in children.clone() {
+                    inner(tree, c, f);
                 }
             }
-            _ => (),
+        }
+        let root = self.root;
+        if let NodeType::Element { children, .. } = &mut self[root].node_type {
+            for c in children.clone() {
+                inner(self, c, &mut f);
+            }
         }
     }
 }
 
 impl<US: BubbledUpState, DS: PushedDownState> Index<usize> for RealDom<US, DS> {
-    type Output = TreeNode<US, DS>;
+    type Output = Node<US, DS>;
 
     fn index(&self, idx: usize) -> &Self::Output {
         self.get(idx).expect("Node does not exist")
@@ -457,7 +467,7 @@ impl<US: BubbledUpState, DS: PushedDownState> Index<usize> for RealDom<US, DS> {
 }
 
 impl<US: BubbledUpState, DS: PushedDownState> Index<ElementId> for RealDom<US, DS> {
-    type Output = TreeNode<US, DS>;
+    type Output = Node<US, DS>;
 
     fn index(&self, idx: ElementId) -> &Self::Output {
         &self[idx.0]
@@ -477,7 +487,7 @@ impl<US: BubbledUpState, DS: PushedDownState> IndexMut<ElementId> for RealDom<US
 
 /// The node is stored client side and stores only basic data about the node. For more complete information about the node see [`TreeNode::element`].
 #[derive(Debug, Clone)]
-pub struct TreeNode<US: BubbledUpState, DS: PushedDownState> {
+pub struct Node<US: BubbledUpState, DS: PushedDownState> {
     /// The id of the node this node was created from.
     pub id: ElementId,
     /// The parent id of the node.
@@ -487,13 +497,13 @@ pub struct TreeNode<US: BubbledUpState, DS: PushedDownState> {
     /// State of the node that is pushed down to the children. The state must depend only on the node itself and its parent.
     pub down_state: DS,
     /// Additional inforation specific to the node type
-    pub node_type: TreeNodeType,
+    pub node_type: NodeType,
     /// The number of parents before the root node. The root node has height 1.
     pub height: u16,
 }
 
 #[derive(Debug, Clone)]
-pub enum TreeNodeType {
+pub enum NodeType {
     Text {
         text: String,
     },
@@ -505,9 +515,9 @@ pub enum TreeNodeType {
     Placeholder,
 }
 
-impl<US: BubbledUpState, DS: PushedDownState> TreeNode<US, DS> {
-    fn new(id: u64, node_type: TreeNodeType) -> Self {
-        TreeNode {
+impl<US: BubbledUpState, DS: PushedDownState> Node<US, DS> {
+    fn new(id: u64, node_type: NodeType) -> Self {
+        Node {
             id: ElementId(id as usize),
             parent: None,
             node_type,
@@ -523,20 +533,14 @@ impl<US: BubbledUpState, DS: PushedDownState> TreeNode<US, DS> {
     }
 
     fn add_child(&mut self, child: ElementId) {
-        match &mut self.node_type {
-            TreeNodeType::Element { children, .. } => {
-                children.push(child);
-            }
-            _ => (),
+        if let NodeType::Element { children, .. } = &mut self.node_type {
+            children.push(child);
         }
     }
 
     fn remove_child(&mut self, child: ElementId) {
-        match &mut self.node_type {
-            TreeNodeType::Element { children, .. } => {
-                children.retain(|c| c != &child);
-            }
-            _ => (),
+        if let NodeType::Element { children, .. } = &mut self.node_type {
+            children.retain(|c| c != &child);
         }
     }
 

+ 13 - 1
packages/tui/src/config.rs

@@ -1,6 +1,18 @@
-#[derive(Default, Clone, Copy)]
+#[derive(Clone, Copy)]
 pub struct Config {
     pub rendering_mode: RenderingMode,
+    /// Should the terminal quit when the user presses `ctrl+c`?
+    /// To handle quiting on your own, use the [crate::TuiContext] root context.
+    pub ctrl_c_quit: bool,
+}
+
+impl Default for Config {
+    fn default() -> Self {
+        Self {
+            rendering_mode: Default::default(),
+            ctrl_c_quit: true,
+        }
+    }
 }
 
 #[derive(Clone, Copy)]

+ 94 - 109
packages/tui/src/hooks.rs

@@ -5,8 +5,7 @@ use dioxus_core::*;
 use fxhash::{FxHashMap, FxHashSet};
 
 use dioxus_html::{on::*, KeyCode};
-use dioxus_native_core::real_dom::{RealDom, TreeNode};
-use futures::{channel::mpsc::UnboundedReceiver, StreamExt};
+use dioxus_native_core::real_dom::{Node, RealDom};
 use std::{
     any::Any,
     cell::RefCell,
@@ -162,7 +161,7 @@ impl InnerInputState {
         }
     }
 
-    fn update<'a>(
+    fn update(
         &mut self,
         evts: &mut Vec<EventCore>,
         resolved_events: &mut Vec<UserEvent>,
@@ -176,9 +175,11 @@ impl InnerInputState {
 
         self.wheel = None;
 
+        println!("update {evts:?}");
         for e in evts.iter_mut() {
             self.apply_event(e);
         }
+        println!("->update {evts:?}");
 
         self.resolve_mouse_events(previous_mouse, resolved_events, layout, tree);
 
@@ -216,7 +217,7 @@ impl InnerInputState {
             data: Arc<dyn Any + Send + Sync>,
             will_bubble: &mut FxHashSet<ElementId>,
             resolved_events: &mut Vec<UserEvent>,
-            node: &TreeNode<StretchLayout, StyleModifier>,
+            node: &Node<StretchLayout, StyleModifier>,
             tree: &RealDom<StretchLayout, StyleModifier>,
         ) {
             // only trigger event if the event was not triggered already by a child
@@ -231,7 +232,7 @@ impl InnerInputState {
                     priority: EventPriority::Medium,
                     name,
                     element: Some(node.id),
-                    data: data,
+                    data,
                 })
             }
         }
@@ -269,17 +270,15 @@ impl InnerInputState {
                         .is_some();
                     let currently_contains = layout_contains_point(node_layout, data.new_pos);
 
-                    if currently_contains {
-                        if previously_contained {
-                            try_create_event(
-                                "mousemove",
-                                Arc::new(clone_mouse_data(data.mouse_data)),
-                                &mut will_bubble,
-                                resolved_events,
-                                node,
-                                tree,
-                            );
-                        }
+                    if currently_contains && previously_contained {
+                        try_create_event(
+                            "mousemove",
+                            Arc::new(clone_mouse_data(data.mouse_data)),
+                            &mut will_bubble,
+                            resolved_events,
+                            node,
+                            tree,
+                        );
                     }
                 }
             }
@@ -295,17 +294,15 @@ impl InnerInputState {
                         .is_some();
                     let currently_contains = layout_contains_point(node_layout, data.new_pos);
 
-                    if currently_contains {
-                        if !previously_contained {
-                            try_create_event(
-                                "mouseenter",
-                                Arc::new(clone_mouse_data(data.mouse_data)),
-                                &mut will_bubble,
-                                resolved_events,
-                                node,
-                                tree,
-                            );
-                        }
+                    if currently_contains && !previously_contained {
+                        try_create_event(
+                            "mouseenter",
+                            Arc::new(clone_mouse_data(data.mouse_data)),
+                            &mut will_bubble,
+                            resolved_events,
+                            node,
+                            tree,
+                        );
                     }
                 }
             }
@@ -321,17 +318,15 @@ impl InnerInputState {
                         .is_some();
                     let currently_contains = layout_contains_point(node_layout, data.new_pos);
 
-                    if currently_contains {
-                        if !previously_contained {
-                            try_create_event(
-                                "mouseover",
-                                Arc::new(clone_mouse_data(data.mouse_data)),
-                                &mut will_bubble,
-                                resolved_events,
-                                node,
-                                tree,
-                            );
-                        }
+                    if currently_contains && !previously_contained {
+                        try_create_event(
+                            "mouseover",
+                            Arc::new(clone_mouse_data(data.mouse_data)),
+                            &mut will_bubble,
+                            resolved_events,
+                            node,
+                            tree,
+                        );
                     }
                 }
             }
@@ -343,17 +338,15 @@ impl InnerInputState {
                     let node_layout = layout.layout(node.up_state.node.unwrap()).unwrap();
                     let currently_contains = layout_contains_point(node_layout, data.new_pos);
 
-                    if currently_contains {
-                        if data.clicked {
-                            try_create_event(
-                                "mousedown",
-                                Arc::new(clone_mouse_data(data.mouse_data)),
-                                &mut will_bubble,
-                                resolved_events,
-                                node,
-                                tree,
-                            );
-                        }
+                    if currently_contains && data.clicked {
+                        try_create_event(
+                            "mousedown",
+                            Arc::new(clone_mouse_data(data.mouse_data)),
+                            &mut will_bubble,
+                            resolved_events,
+                            node,
+                            tree,
+                        );
                     }
                 }
             }
@@ -365,17 +358,15 @@ impl InnerInputState {
                     let node_layout = layout.layout(node.up_state.node.unwrap()).unwrap();
                     let currently_contains = layout_contains_point(node_layout, data.new_pos);
 
-                    if currently_contains {
-                        if data.released {
-                            try_create_event(
-                                "mouseup",
-                                Arc::new(clone_mouse_data(data.mouse_data)),
-                                &mut will_bubble,
-                                resolved_events,
-                                node,
-                                tree,
-                            );
-                        }
+                    if currently_contains && data.released {
+                        try_create_event(
+                            "mouseup",
+                            Arc::new(clone_mouse_data(data.mouse_data)),
+                            &mut will_bubble,
+                            resolved_events,
+                            node,
+                            tree,
+                        );
                     }
                 }
             }
@@ -387,17 +378,15 @@ impl InnerInputState {
                     let node_layout = layout.layout(node.up_state.node.unwrap()).unwrap();
                     let currently_contains = layout_contains_point(node_layout, data.new_pos);
 
-                    if currently_contains {
-                        if data.released && data.mouse_data.button == 0 {
-                            try_create_event(
-                                "click",
-                                Arc::new(clone_mouse_data(data.mouse_data)),
-                                &mut will_bubble,
-                                resolved_events,
-                                node,
-                                tree,
-                            );
-                        }
+                    if currently_contains && data.released && data.mouse_data.button == 0 {
+                        try_create_event(
+                            "click",
+                            Arc::new(clone_mouse_data(data.mouse_data)),
+                            &mut will_bubble,
+                            resolved_events,
+                            node,
+                            tree,
+                        );
                     }
                 }
             }
@@ -409,17 +398,15 @@ impl InnerInputState {
                     let node_layout = layout.layout(node.up_state.node.unwrap()).unwrap();
                     let currently_contains = layout_contains_point(node_layout, data.new_pos);
 
-                    if currently_contains {
-                        if data.released && data.mouse_data.button == 2 {
-                            try_create_event(
-                                "contextmenu",
-                                Arc::new(clone_mouse_data(data.mouse_data)),
-                                &mut will_bubble,
-                                resolved_events,
-                                node,
-                                tree,
-                            );
-                        }
+                    if currently_contains && data.released && data.mouse_data.button == 2 {
+                        try_create_event(
+                            "contextmenu",
+                            Arc::new(clone_mouse_data(data.mouse_data)),
+                            &mut will_bubble,
+                            resolved_events,
+                            node,
+                            tree,
+                        );
                     }
                 }
             }
@@ -431,18 +418,16 @@ impl InnerInputState {
                     let node_layout = layout.layout(node.up_state.node.unwrap()).unwrap();
                     let currently_contains = layout_contains_point(node_layout, data.new_pos);
 
-                    if currently_contains {
-                        if let Some(w) = data.wheel_data {
-                            if data.wheel_delta != 0.0 {
-                                try_create_event(
-                                    "wheel",
-                                    Arc::new(clone_wheel_data(w)),
-                                    &mut will_bubble,
-                                    resolved_events,
-                                    node,
-                                    tree,
-                                );
-                            }
+                    if let Some(w) = data.wheel_data {
+                        if currently_contains && data.wheel_delta != 0.0 {
+                            try_create_event(
+                                "wheel",
+                                Arc::new(clone_wheel_data(w)),
+                                &mut will_bubble,
+                                resolved_events,
+                                node,
+                                tree,
+                            );
                         }
                     }
                 }
@@ -511,24 +496,22 @@ pub struct RinkInputHandler {
 impl RinkInputHandler {
     /// global context that handles events
     /// limitations: GUI key modifier is never detected, key up events are not detected, and only two mouse buttons may be pressed at once
-    pub fn new(
-        mut receiver: UnboundedReceiver<TermEvent>,
-        cx: &ScopeState,
-    ) -> (Self, Rc<RefCell<InnerInputState>>) {
+    pub fn new() -> (
+        Self,
+        Rc<RefCell<InnerInputState>>,
+        impl FnMut(crossterm::event::Event),
+    ) {
         let queued_events = Rc::new(RefCell::new(Vec::new()));
         let queued_events2 = Rc::downgrade(&queued_events);
 
-        cx.push_future(async move {
-            while let Some(evt) = receiver.next().await {
-                if let Some(evt) = get_event(evt) {
-                    if let Some(v) = queued_events2.upgrade() {
-                        (*v).borrow_mut().push(evt);
-                    } else {
-                        break;
-                    }
+        let regester_event = move |evt: crossterm::event::Event| {
+            if let Some(evt) = get_event(evt) {
+                if let Some(v) = queued_events2.upgrade() {
+                    println!("queued event: {:?}", evt);
+                    (*v).borrow_mut().push(evt);
                 }
             }
-        });
+        };
 
         let state = Rc::new(RefCell::new(InnerInputState::new()));
 
@@ -538,14 +521,16 @@ impl RinkInputHandler {
                 queued_events,
             },
             state,
+            regester_event,
         )
     }
 
-    pub fn get_events<'a>(
+    pub fn get_events(
         &self,
         layout: &Stretch,
         tree: &mut RealDom<StretchLayout, StyleModifier>,
     ) -> Vec<UserEvent> {
+        println!("get_events");
         let mut resolved_events = Vec::new();
 
         (*self.state).borrow_mut().update(
@@ -799,7 +784,7 @@ fn translate_key_event(event: crossterm::event::KeyEvent) -> Option<EventData> {
     // from https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent
     Some(EventData::Keyboard(KeyboardData {
         char_code: code.raw_code(),
-        key: key_str.to_string(),
+        key: key_str,
         key_code: code,
         alt_key: event.modifiers.contains(KeyModifiers::ALT),
         ctrl_key: event.modifiers.contains(KeyModifiers::CONTROL),

+ 1 - 1
packages/tui/src/layout.rs

@@ -65,7 +65,7 @@ impl BubbledUpState for StretchLayout {
                 }
 
                 if let Some(n) = self.node {
-                    if &stretch.children(n).unwrap() != &child_layout {
+                    if stretch.children(n).unwrap() != child_layout {
                         stretch.set_children(n, &child_layout).unwrap();
                     }
                     if self.style != style {

+ 40 - 28
packages/tui/src/lib.rs

@@ -1,6 +1,3 @@
-// notes:
-// mouse events binary search was broken for absolutely positioned elements
-
 use anyhow::Result;
 use crossterm::{
     event::{DisableMouseCapture, EnableMouseCapture, Event as TermEvent, KeyCode, KeyModifiers},
@@ -48,11 +45,8 @@ pub fn launch(app: Component<()>) {
 
 pub fn launch_cfg(app: Component<()>, cfg: Config) {
     let mut dom = VirtualDom::new(app);
-    let (tx, rx) = unbounded();
-
-    let cx = dom.base_scope();
 
-    let (handler, state) = RinkInputHandler::new(rx, cx);
+    let (handler, state, register_event) = RinkInputHandler::new();
 
     // Setup input handling
     let (event_tx, event_rx) = unbounded();
@@ -70,6 +64,7 @@ pub fn launch_cfg(app: Component<()>, cfg: Config) {
         }
     });
 
+    let cx = dom.base_scope();
     cx.provide_root_context(state);
     cx.provide_root_context(TuiContext { tx: event_tx_clone });
 
@@ -81,17 +76,26 @@ pub fn launch_cfg(app: Component<()>, cfg: Config) {
         .update_state(&dom, to_update, &mut stretch, &mut ())
         .unwrap();
 
-    render_vdom(&mut dom, tx, event_rx, handler, cfg, tree, stretch).unwrap();
+    render_vdom(
+        &mut dom,
+        event_rx,
+        handler,
+        cfg,
+        tree,
+        stretch,
+        register_event,
+    )
+    .unwrap();
 }
 
 fn render_vdom(
     vdom: &mut VirtualDom,
-    crossterm_event_sender: UnboundedSender<TermEvent>,
     mut event_reciever: UnboundedReceiver<InputEvent>,
     handler: RinkInputHandler,
     cfg: Config,
     mut tree: RealDom<StretchLayout, StyleModifier>,
     mut stretch: Stretch,
+    mut register_event: impl FnMut(crossterm::event::Event),
 ) -> Result<()> {
     tokio::runtime::Builder::new_current_thread()
         .enable_all()
@@ -105,7 +109,7 @@ fn render_vdom(
 
             terminal.clear().unwrap();
             let mut to_rerender: fxhash::FxHashSet<usize> = vec![0].into_iter().collect();
-            let mut redraw = true;
+            let mut resized = true;
 
             loop {
                 /*
@@ -119,8 +123,8 @@ fn render_vdom(
                 todo: lazy re-rendering
                 */
 
-                if !to_rerender.is_empty() || redraw {
-                    redraw = false;
+                if !to_rerender.is_empty() || resized {
+                    resized = false;
                     terminal.draw(|frame| {
                         // size is guaranteed to not change when rendering
                         let dims = frame.size();
@@ -138,8 +142,8 @@ fn render_vdom(
                                 },
                             )
                             .unwrap();
-                        let root = &tree[tree.root_id()];
-                        render::render_vnode(frame, &stretch, &tree, &root, cfg);
+                        // let root = &tree[tree.root_id()];
+                        // render::render_vnode(frame, &stretch, &tree, &root, cfg);
                     })?;
                 }
 
@@ -158,35 +162,44 @@ fn render_vdom(
                                     TermEvent::Key(key) => {
                                         if matches!(key.code, KeyCode::Char('C' | 'c'))
                                             && key.modifiers.contains(KeyModifiers::CONTROL)
+                                            && cfg.ctrl_c_quit
                                         {
                                             break;
                                         }
                                     }
-                                    TermEvent::Resize(_, _) => redraw = true,
+                                    TermEvent::Resize(_, _) => resized = true,
                                     TermEvent::Mouse(_) => {}
                                 },
                                 InputEvent::Close => break,
                             };
 
                             if let InputEvent::UserInput(evt) = evt.unwrap() {
-                                crossterm_event_sender.unbounded_send(evt).unwrap();
+                                register_event(evt);
                             }
                         }
                     }
                 }
 
-                // resolve events before rendering
-                for e in handler.get_events(&stretch, &mut tree) {
-                    vdom.handle_message(SchedulerMsg::Event(e));
+                {
+                    // resolve events before rendering
+                    let evts = handler.get_events(&stretch, &mut tree);
+                    println!("evts: {:?}", evts);
+                    for e in evts {
+                        vdom.handle_message(SchedulerMsg::Event(e));
+                    }
+                    let mutations = vdom.work_with_deadline(|| false);
+                    // updates the tree's nodes
+                    let to_update = tree.apply_mutations(mutations);
+                    // update the style and layout
+                    to_rerender.extend(
+                        tree.update_state(vdom, to_update, &mut stretch, &mut ())
+                            .unwrap()
+                            .iter(),
+                    )
                 }
-                vdom.process_all_messages();
-                let mutations = vdom.work_with_deadline(|| false);
-                // updates the tree's nodes
-                let to_update = tree.apply_mutations(mutations);
-                // update the style and layout
-                to_rerender = tree
-                    .update_state(&vdom, to_update, &mut stretch, &mut ())
-                    .unwrap();
+                println!();
+                println!();
+                println!();
             }
 
             disable_raw_mode()?;
@@ -203,6 +216,5 @@ fn render_vdom(
 
 enum InputEvent {
     UserInput(TermEvent),
-    #[allow(dead_code)]
     Close,
 }

+ 13 - 14
packages/tui/src/render.rs

@@ -1,7 +1,7 @@
 use crate::layout::StretchLayout;
 use dioxus_native_core::{
     layout_attributes::UnitSystem,
-    real_dom::{RealDom, TreeNode},
+    real_dom::{Node, RealDom},
 };
 use std::io::Stdout;
 use stretch2::{
@@ -20,18 +20,17 @@ use crate::{
 
 const RADIUS_MULTIPLIER: [f32; 2] = [1.0, 0.5];
 
-pub fn render_vnode<'a>(
+pub fn render_vnode(
     frame: &mut tui::Frame<CrosstermBackend<Stdout>>,
     layout: &Stretch,
     tree: &RealDom<StretchLayout, StyleModifier>,
-    node: &TreeNode<StretchLayout, StyleModifier>,
+    node: &Node<StretchLayout, StyleModifier>,
     cfg: Config,
 ) {
-    use dioxus_native_core::real_dom::TreeNodeType;
+    use dioxus_native_core::real_dom::NodeType;
 
-    match &node.node_type {
-        TreeNodeType::Placeholder => return,
-        _ => (),
+    if let NodeType::Placeholder = &node.node_type {
+        return;
     }
 
     let Layout { location, size, .. } = layout.layout(node.up_state.node.unwrap()).unwrap();
@@ -40,7 +39,7 @@ pub fn render_vnode<'a>(
     let Size { width, height } = size;
 
     match &node.node_type {
-        TreeNodeType::Text { text } => {
+        NodeType::Text { text } => {
             #[derive(Default)]
             struct Label<'a> {
                 text: &'a str,
@@ -59,7 +58,7 @@ pub fn render_vnode<'a>(
             }
 
             let label = Label {
-                text: &text,
+                text,
                 style: node.down_state.style,
             };
             let area = Rect::new(*x as u16, *y as u16, *width as u16, *height as u16);
@@ -69,7 +68,7 @@ pub fn render_vnode<'a>(
                 frame.render_widget(WidgetWithContext::new(label, cfg), area);
             }
         }
-        TreeNodeType::Element { children, .. } => {
+        NodeType::Element { children, .. } => {
             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
@@ -81,11 +80,11 @@ pub fn render_vnode<'a>(
                 render_vnode(frame, layout, tree, &tree[c.0], cfg);
             }
         }
-        TreeNodeType::Placeholder => unreachable!(),
+        NodeType::Placeholder => unreachable!(),
     }
 }
 
-impl RinkWidget for &TreeNode<StretchLayout, StyleModifier> {
+impl RinkWidget for &Node<StretchLayout, StyleModifier> {
     fn render(self, area: Rect, mut buf: RinkBuffer<'_>) {
         use tui::symbols::line::*;
 
@@ -249,8 +248,8 @@ impl RinkWidget for &TreeNode<StretchLayout, StyleModifier> {
 
         fn get_radius(border: &BorderEdge, area: Rect) -> f32 {
             match border.style {
-                BorderStyle::HIDDEN => 0.0,
-                BorderStyle::NONE => 0.0,
+                BorderStyle::Hidden => 0.0,
+                BorderStyle::None => 0.0,
                 _ => match border.radius {
                     UnitSystem::Percent(p) => p * area.width as f32 / 100.0,
                     UnitSystem::Point(p) => p,

+ 50 - 55
packages/tui/src/style_attributes.rs

@@ -51,33 +51,28 @@ impl PushedDownState for StyleModifier {
         if parent.is_some() {
             self.style.fg = None;
         }
-        match vnode {
-            VNode::Element(el) => {
-                // handle text modifier elements
-                if el.namespace.is_none() {
-                    match el.tag {
-                        "b" => apply_style_attributes("font-weight", "bold", self),
-                        "strong" => apply_style_attributes("font-weight", "bold", self),
-                        "u" => apply_style_attributes("text-decoration", "underline", self),
-                        "ins" => apply_style_attributes("text-decoration", "underline", self),
-                        "del" => apply_style_attributes("text-decoration", "line-through", self),
-                        "i" => apply_style_attributes("font-style", "italic", self),
-                        "em" => apply_style_attributes("font-style", "italic", self),
-                        "mark" => apply_style_attributes(
-                            "background-color",
-                            "rgba(241, 231, 64, 50%)",
-                            self,
-                        ),
-                        _ => (),
+        if let VNode::Element(el) = vnode {
+            // handle text modifier elements
+            if el.namespace.is_none() {
+                match el.tag {
+                    "b" => apply_style_attributes("font-weight", "bold", self),
+                    "strong" => apply_style_attributes("font-weight", "bold", self),
+                    "u" => apply_style_attributes("text-decoration", "underline", self),
+                    "ins" => apply_style_attributes("text-decoration", "underline", self),
+                    "del" => apply_style_attributes("text-decoration", "line-through", self),
+                    "i" => apply_style_attributes("font-style", "italic", self),
+                    "em" => apply_style_attributes("font-style", "italic", self),
+                    "mark" => {
+                        apply_style_attributes("background-color", "rgba(241, 231, 64, 50%)", self)
                     }
+                    _ => (),
                 }
+            }
 
-                // gather up all the styles from the attribute list
-                for &Attribute { name, value, .. } in el.attributes {
-                    apply_style_attributes(name, value, self);
-                }
+            // gather up all the styles from the attribute list
+            for &Attribute { name, value, .. } in el.attributes {
+                apply_style_attributes(name, value, self);
             }
-            _ => (),
         }
 
         // keep the text styling from the parent element
@@ -125,7 +120,7 @@ impl Default for BorderEdge {
     fn default() -> Self {
         Self {
             color: None,
-            style: BorderStyle::NONE,
+            style: BorderStyle::None,
             width: UnitSystem::Point(0.0),
             radius: UnitSystem::Point(0.0),
         }
@@ -134,16 +129,16 @@ impl Default for BorderEdge {
 
 #[derive(Clone, Copy, PartialEq, Debug)]
 pub enum BorderStyle {
-    DOTTED,
-    DASHED,
-    SOLID,
-    DOUBLE,
-    GROOVE,
-    RIDGE,
-    INSET,
-    OUTSET,
-    HIDDEN,
-    NONE,
+    Dotted,
+    Dashed,
+    Solid,
+    Double,
+    Groove,
+    Ridge,
+    Inset,
+    Outset,
+    Hidden,
+    None,
 }
 
 impl BorderStyle {
@@ -160,16 +155,16 @@ impl BorderStyle {
             ..NORMAL
         };
         match self {
-            BorderStyle::DOTTED => Some(DOTTED),
-            BorderStyle::DASHED => Some(DASHED),
-            BorderStyle::SOLID => Some(NORMAL),
-            BorderStyle::DOUBLE => Some(DOUBLE),
-            BorderStyle::GROOVE => Some(NORMAL),
-            BorderStyle::RIDGE => Some(NORMAL),
-            BorderStyle::INSET => Some(NORMAL),
-            BorderStyle::OUTSET => Some(NORMAL),
-            BorderStyle::HIDDEN => None,
-            BorderStyle::NONE => None,
+            BorderStyle::Dotted => Some(DOTTED),
+            BorderStyle::Dashed => Some(DASHED),
+            BorderStyle::Solid => Some(NORMAL),
+            BorderStyle::Double => Some(DOUBLE),
+            BorderStyle::Groove => Some(NORMAL),
+            BorderStyle::Ridge => Some(NORMAL),
+            BorderStyle::Inset => Some(NORMAL),
+            BorderStyle::Outset => Some(NORMAL),
+            BorderStyle::Hidden => None,
+            BorderStyle::None => None,
         }
     }
 }
@@ -334,16 +329,16 @@ fn apply_background(name: &str, value: &str, style: &mut StyleModifier) {
 fn apply_border(name: &str, value: &str, style: &mut StyleModifier) {
     fn parse_border_style(v: &str) -> BorderStyle {
         match v {
-            "dotted" => BorderStyle::DOTTED,
-            "dashed" => BorderStyle::DASHED,
-            "solid" => BorderStyle::SOLID,
-            "double" => BorderStyle::DOUBLE,
-            "groove" => BorderStyle::GROOVE,
-            "ridge" => BorderStyle::RIDGE,
-            "inset" => BorderStyle::INSET,
-            "outset" => BorderStyle::OUTSET,
-            "none" => BorderStyle::NONE,
-            "hidden" => BorderStyle::HIDDEN,
+            "dotted" => BorderStyle::Dotted,
+            "dashed" => BorderStyle::Dashed,
+            "solid" => BorderStyle::Solid,
+            "double" => BorderStyle::Double,
+            "groove" => BorderStyle::Groove,
+            "ridge" => BorderStyle::Ridge,
+            "inset" => BorderStyle::Inset,
+            "outset" => BorderStyle::Outset,
+            "none" => BorderStyle::None,
+            "hidden" => BorderStyle::Hidden,
             _ => todo!(),
         }
     }
@@ -505,7 +500,7 @@ fn apply_border(name: &str, value: &str, style: &mut StyleModifier) {
                     .zip(style.modifier.borders.slice().iter_mut())
                 {
                     if let Some(w) = parse_value(v) {
-                        width.width = w.into();
+                        width.width = w;
                     }
                 }
             }

+ 3 - 0
src/lib.rs

@@ -23,6 +23,9 @@ pub use dioxus_desktop as desktop;
 #[cfg(feature = "tui")]
 pub use dioxus_tui as tui;
 
+#[cfg(feature = "native-core")]
+pub use dioxus_native_core as native_core;
+
 #[cfg(feature = "fermi")]
 pub use fermi;