diff --git a/packages/native-core/src/dioxus.rs b/packages/native-core/src/dioxus.rs index 1c688b864..f524035a4 100644 --- a/packages/native-core/src/dioxus.rs +++ b/packages/native-core/src/dioxus.rs @@ -241,7 +241,7 @@ fn create_template_node(rdom: &mut RealDom, node: &TemplateNode) -> NodeId { } } -trait NodeImmutableDioxusExt: NodeImmutable { +pub trait NodeImmutableDioxusExt: NodeImmutable { fn mounted_id(&self) -> Option { self.get().copied() } diff --git a/packages/native-core/src/lib.rs b/packages/native-core/src/lib.rs index 05e9a2c93..eeb3b86e2 100644 --- a/packages/native-core/src/lib.rs +++ b/packages/native-core/src/lib.rs @@ -1,9 +1,12 @@ use std::any::Any; +use std::future::Future; use std::hash::BuildHasherDefault; +use std::pin::Pin; pub use node_ref::NodeMask; pub use passes::AnyMapLike; pub use passes::{Dependancy, Pass, TypeErasedPass}; +use prelude::FromAnyValue; pub use real_dom::{NodeMut, NodeRef, RealDom}; use rustc_hash::FxHasher; pub use tree::NodeId; @@ -31,3 +34,11 @@ pub mod prelude { pub type FxDashMap = dashmap::DashMap>; pub type FxDashSet = dashmap::DashSet>; pub type SendAnyMap = anymap::Map; + +pub trait Renderer { + fn render(&mut self, root: NodeMut); + fn handle_event(&mut self, node: NodeMut, event: &str, value: E); + fn poll_async(&mut self) -> Pin + Send>> { + Box::pin(async {}) + } +} diff --git a/packages/tui/Cargo.toml b/packages/tui/Cargo.toml index eb0ccf721..46a868301 100644 --- a/packages/tui/Cargo.toml +++ b/packages/tui/Cargo.toml @@ -13,8 +13,8 @@ license = "MIT/Apache-2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -dioxus = { path = "../dioxus", version = "^0.3.0" } -dioxus-core = { path = "../core", version = "^0.3.0", features = ["serialize"] } +dioxus = { path = "../dioxus", version = "^0.3.0", optional = true } +dioxus-core = { path = "../core", version = "^0.3.0", features = ["serialize"], optional = true } dioxus-html = { path = "../html", version = "^0.3.0" } dioxus-native-core = { path = "../native-core", version = "^0.2.0" } dioxus-hot-reload = { path = "../hot-reload", optional = true } @@ -40,5 +40,6 @@ name = "update" harness = false [features] -default = ["hot-reload"] +default = ["hot-reload", "dioxus-bindings"] hot-reload = ["dioxus-hot-reload"] +dioxus-bindings = ["dioxus", "dioxus-core", "dioxus-native-core/dioxus"] \ No newline at end of file diff --git a/packages/tui/src/dioxus.rs b/packages/tui/src/dioxus.rs new file mode 100644 index 000000000..c45918493 --- /dev/null +++ b/packages/tui/src/dioxus.rs @@ -0,0 +1,66 @@ +pub fn launch(app: Component<()>) { + launch_cfg(app, Config::default()) +} + +pub fn launch_cfg(app: Component<()>, cfg: Config) { + launch_cfg_with_props(app, (), cfg); +} + +pub fn launch_cfg_with_props(app: Component, props: Props, cfg: Config) { + let mut dom = VirtualDom::new_with_props(app, props); + let mut rdom = RealDom::new(Box::new([ + TaffyLayout::to_type_erased(), + Focus::to_type_erased(), + StyleModifier::to_type_erased(), + PreventDefault::to_type_erased(), + ])); + + let (handler, state, register_event) = RinkInputHandler::craete(&mut rdom); + + // Setup input handling + let (event_tx, event_rx) = unbounded(); + let event_tx_clone = event_tx.clone(); + if !cfg.headless { + std::thread::spawn(move || { + let tick_rate = Duration::from_millis(1000); + loop { + if crossterm::event::poll(tick_rate).unwrap() { + let evt = crossterm::event::read().unwrap(); + if event_tx.unbounded_send(InputEvent::UserInput(evt)).is_err() { + break; + } + } + } + }); + } + + let cx = dom.base_scope(); + let rdom = Rc::new(RefCell::new(rdom)); + 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(), + }); + + { + let mut rdom = rdom.borrow_mut(); + let mutations = dom.rebuild(); + rdom.apply_mutations(mutations); + let mut any_map = SendAnyMap::new(); + any_map.insert(taffy.clone()); + let _ = rdom.update_state(any_map, false); + } + + render_vdom( + &mut dom, + event_rx, + handler, + cfg, + rdom, + taffy, + register_event, + ) + .unwrap(); +} diff --git a/packages/tui/src/focus.rs b/packages/tui/src/focus.rs index 05ae2019c..e2958df61 100644 --- a/packages/tui/src/focus.rs +++ b/packages/tui/src/focus.rs @@ -2,7 +2,7 @@ use crate::prevent_default::PreventDefault; use dioxus_native_core::{ node_ref::{AttributeMaskBuilder, NodeMaskBuilder}, - real_dom::{NodeImmutable, NodeMutable}, + real_dom::NodeImmutable, utils::{ElementProduced, PersistantElementIter}, Dependancy, NodeId, Pass, RealDom, SendAnyMap, }; @@ -64,7 +64,7 @@ pub(crate) struct Focus { } impl Pass for Focus { - const NODE_MASK: NodeMaskBuilder = NodeMaskBuilder::new() + const NODE_MASK: NodeMaskBuilder<'static> = NodeMaskBuilder::new() .with_attrs(AttributeMaskBuilder::Some(FOCUS_ATTRIBUTES)) .with_listeners(); @@ -138,7 +138,6 @@ impl Pass for Focus { const FOCUS_EVENTS: &[&str] = &["keydown", "keypress", "keyup"]; const FOCUS_ATTRIBUTES: &[&str] = &["tabindex"]; -#[derive(Default)] pub(crate) struct FocusState { pub(crate) focus_iter: PersistantElementIter, pub(crate) last_focused_id: Option, @@ -147,6 +146,16 @@ pub(crate) struct FocusState { } impl FocusState { + pub fn create(rdom: &mut RealDom) -> Self { + let mut focus_iter = PersistantElementIter::create(rdom); + Self { + focus_iter, + last_focused_id: Default::default(), + focus_level: Default::default(), + dirty: Default::default(), + } + } + /// Returns true if the focus has changed. pub fn progress(&mut self, rdom: &mut RealDom, forward: bool) -> bool { if let Some(last) = self.last_focused_id { @@ -242,14 +251,13 @@ impl FocusState { } if let Some(id) = next_focus { - let mut node = rdom.get_mut_raw(id).unwrap(); + let mut node = rdom.get_mut(id).unwrap(); if !node.get::().unwrap().level.focusable() { panic!() } node.insert(Focused(true)); if let Some(old) = self.last_focused_id.replace(id) { - let mut old = rdom.get_mut_raw(old).unwrap(); - let focused = old.get_mut::().unwrap(); + let focused = rdom.get_state_mut_raw::(old).unwrap(); focused.0 = false; } // reset the position to the currently focused element @@ -261,49 +269,14 @@ impl FocusState { false } - pub(crate) fn prune(&mut self, mutations: &dioxus_core::Mutations, rdom: &RealDom) { - fn remove_children(to_prune: &mut [&mut Option], rdom: &RealDom, removed: NodeId) { - for opt in to_prune.iter_mut() { - if let Some(id) = opt { - if *id == removed { - **opt = None; - } - } - } - let node = rdom.get(removed).unwrap(); - if let Some(children) = node.child_ids() { - for child in children { - remove_children(to_prune, rdom, *child); - } - } - } - if self.focus_iter.prune(mutations, rdom) { - self.dirty = true; - } - for m in &mutations.edits { - match m { - dioxus_core::Mutation::ReplaceWith { id, .. } => remove_children( - &mut [&mut self.last_focused_id], - rdom, - rdom.element_to_node_id(*id), - ), - dioxus_core::Mutation::Remove { id } => remove_children( - &mut [&mut self.last_focused_id], - rdom, - rdom.element_to_node_id(*id), - ), - _ => (), - } - } - } - pub(crate) fn set_focus(&mut self, rdom: &mut RealDom, id: NodeId) { if let Some(old) = self.last_focused_id.replace(id) { - let mut node = rdom.get_mut_raw(old).unwrap(); - node.get_mut::().unwrap().0 = false; + let mut focused = rdom.get_state_mut_raw::(old).unwrap(); + *focused = Focused(false); } - let mut node = rdom.get_mut_raw(id).unwrap(); - node.insert(Focused(true)); + let mut focused = rdom.get_state_mut_raw::(id).unwrap(); + *focused = Focused(true); + let mut node = rdom.get(id).unwrap(); self.focus_level = node.get::().unwrap().level; // reset the position to the currently focused element while self.focus_iter.next(rdom).id() != id {} diff --git a/packages/tui/src/hooks.rs b/packages/tui/src/hooks.rs index feec8686c..31b466816 100644 --- a/packages/tui/src/hooks.rs +++ b/packages/tui/src/hooks.rs @@ -1,7 +1,6 @@ use crossterm::event::{ Event as TermEvent, KeyCode as TermKeyCode, KeyModifiers, MouseButton, MouseEventKind, }; -use dioxus_core::*; use dioxus_native_core::real_dom::NodeImmutable; use dioxus_native_core::{NodeId, NodeRef, RealDom}; use rustc_hash::{FxHashMap, FxHashSet}; @@ -13,9 +12,8 @@ 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, FocusData, KeyboardData, MouseData, WheelData}; +use dioxus_html::{event_bubbles, EventData, FocusData, KeyboardData, MouseData, WheelData}; use std::{ - any::Any, cell::{RefCell, RefMut}, rc::Rc, time::{Duration, Instant}, @@ -28,9 +26,9 @@ use crate::layout::TaffyLayout; use crate::{layout_to_screen_space, FocusState}; pub(crate) struct Event { - pub id: ElementId, + pub id: NodeId, pub name: &'static str, - pub data: Rc, + pub data: Rc, pub bubbles: bool, } @@ -71,24 +69,6 @@ pub(crate) struct Event { type EventCore = (&'static str, EventData); -#[derive(Debug)] -enum EventData { - Mouse(MouseData), - Wheel(WheelData), - Screen((u16, u16)), - Keyboard(KeyboardData), -} -impl EventData { - fn into_any(self) -> Rc { - match self { - Self::Mouse(m) => Rc::new(m), - Self::Wheel(w) => Rc::new(w), - Self::Screen(s) => Rc::new(s), - Self::Keyboard(k) => Rc::new(k), - } - } -} - const MAX_REPEAT_TIME: Duration = Duration::from_millis(100); pub struct InnerInputState { @@ -101,14 +81,14 @@ pub struct InnerInputState { } impl InnerInputState { - fn new() -> Self { + fn create(rdom: &mut RealDom) -> Self { Self { mouse: None, wheel: None, last_key_pressed: None, screen: None, // subscribers: Vec::new(), - focus_state: FocusState::default(), + focus_state: FocusState::create(rdom), } } @@ -149,7 +129,6 @@ impl InnerInputState { *m = new_mouse_data; } EventData::Wheel(ref w) => self.wheel = Some(w.clone()), - EventData::Screen(ref s) => self.screen = Some(*s), EventData::Keyboard(ref mut k) => { let is_repeating = self .last_key_pressed @@ -166,6 +145,7 @@ impl InnerInputState { self.last_key_pressed = Some((k.clone(), Instant::now())); } + _ => {} } } @@ -202,31 +182,27 @@ impl InnerInputState { // elements with listeners will always have a element id if let Some(id) = self.focus_state.last_focused_id { let element = dom.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"), - }); - } + resolved_events.push(Event { + name: "focus", + id, + data: Rc::new(EventData::Focus(FocusData {})), + bubbles: event_bubbles("focus"), + }); + resolved_events.push(Event { + name: "focusin", + id, + data: Rc::new(EventData::Focus(FocusData {})), + bubbles: event_bubbles("focusin"), + }); } if let Some(id) = old_focus { let element = dom.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"), - }); - } + resolved_events.push(Event { + name: "focusout", + id, + data: Rc::new(EventData::Focus(FocusData {})), + bubbles: event_bubbles("focusout"), + }); } } @@ -260,29 +236,27 @@ impl InnerInputState { fn try_create_event( name: &'static str, - data: Rc, + data: Rc, will_bubble: &mut FxHashSet, resolved_events: &mut Vec, node: NodeRef, dom: &RealDom, ) { // only trigger event if the event was not triggered already by a child - let id = node.node_data().node_id; + let id = node.id(); if will_bubble.insert(id) { let mut parent = Some(node); while let Some(current_parent) = parent { - let parent_id = current_parent.node_data().node_id; + let parent_id = current_parent.id(); will_bubble.insert(parent_id); parent = current_parent.parent_id().and_then(|id| dom.get(id)); } - if let Some(id) = node.mounted_id() { - resolved_events.push(Event { - name, - id, - data, - bubbles: event_bubbles(name), - }) - } + resolved_events.push(Event { + name, + id, + data, + bubbles: event_bubbles(name), + }) } } @@ -346,7 +320,10 @@ impl InnerInputState { if currently_contains && previously_contained { try_create_event( "mousemove", - Rc::new(prepare_mouse_data(mouse_data, &node_layout)), + Rc::new(EventData::Mouse(prepare_mouse_data( + mouse_data, + &node_layout, + ))), &mut will_bubble, resolved_events, node, @@ -370,7 +347,7 @@ impl InnerInputState { if currently_contains && !previously_contained { try_create_event( "mouseenter", - Rc::new(mouse_data.clone()), + Rc::new(dioxus_html::EventData::Mouse(mouse_data.clone())), &mut will_bubble, resolved_events, node, @@ -393,7 +370,10 @@ impl InnerInputState { if currently_contains && !previously_contained { try_create_event( "mouseover", - Rc::new(prepare_mouse_data(mouse_data, &node_layout)), + Rc::new(EventData::Mouse(prepare_mouse_data( + mouse_data, + &node_layout, + ))), &mut will_bubble, resolved_events, node, @@ -413,7 +393,10 @@ impl InnerInputState { if currently_contains { try_create_event( "mousedown", - Rc::new(prepare_mouse_data(mouse_data, &node_layout)), + Rc::new(EventData::Mouse(prepare_mouse_data( + mouse_data, + &node_layout, + ))), &mut will_bubble, resolved_events, node, @@ -434,7 +417,10 @@ impl InnerInputState { if currently_contains { try_create_event( "mouseup", - Rc::new(prepare_mouse_data(mouse_data, &node_layout)), + Rc::new(EventData::Mouse(prepare_mouse_data( + mouse_data, + &node_layout, + ))), &mut will_bubble, resolved_events, node, @@ -456,7 +442,10 @@ impl InnerInputState { if currently_contains { try_create_event( "click", - Rc::new(prepare_mouse_data(mouse_data, &node_layout)), + Rc::new(EventData::Mouse(prepare_mouse_data( + mouse_data, + &node_layout, + ))), &mut will_bubble, resolved_events, node, @@ -479,7 +468,10 @@ impl InnerInputState { if currently_contains { try_create_event( "contextmenu", - Rc::new(prepare_mouse_data(mouse_data, &node_layout)), + Rc::new(EventData::Mouse(prepare_mouse_data( + mouse_data, + &node_layout, + ))), &mut will_bubble, resolved_events, node, @@ -503,7 +495,7 @@ impl InnerInputState { if currently_contains { try_create_event( "wheel", - Rc::new(w.clone()), + Rc::new(EventData::Wheel(w.clone())), &mut will_bubble, resolved_events, node, @@ -528,7 +520,10 @@ impl InnerInputState { if !currently_contains && previously_contained { try_create_event( "mouseleave", - Rc::new(prepare_mouse_data(mouse_data, &node_layout)), + Rc::new(EventData::Mouse(prepare_mouse_data( + mouse_data, + &node_layout, + ))), &mut will_bubble, resolved_events, node, @@ -551,7 +546,10 @@ impl InnerInputState { if !currently_contains && previously_contained { try_create_event( "mouseout", - Rc::new(prepare_mouse_data(mouse_data, &node_layout)), + Rc::new(EventData::Mouse(prepare_mouse_data( + mouse_data, + &node_layout, + ))), &mut will_bubble, resolved_events, node, @@ -571,7 +569,7 @@ impl InnerInputState { let currently_contains = layout_contains_point(node_layout, new_pos); if currently_contains && node.get::().unwrap().level.focusable() { - focus_id = Some(node.node_data().node_id); + focus_id = Some(node.id()); } }); if let Some(id) = focus_id { @@ -612,7 +610,9 @@ 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() -> ( + pub fn craete( + rdom: &mut RealDom, + ) -> ( Self, Rc>, impl FnMut(crossterm::event::Event), @@ -628,7 +628,7 @@ impl RinkInputHandler { } }; - let state = Rc::new(RefCell::new(InnerInputState::new())); + let state = Rc::new(RefCell::new(InnerInputState::create(rdom))); ( Self { @@ -640,10 +640,6 @@ impl RinkInputHandler { ) } - pub(crate) fn prune(&self, mutations: &dioxus_core::Mutations, rdom: &RealDom) { - self.state.borrow_mut().focus_state.prune(mutations, rdom); - } - pub(crate) fn get_events(&self, layout: &Taffy, dom: &mut RealDom) -> Vec { let mut resolved_events = Vec::new(); @@ -675,14 +671,14 @@ impl RinkInputHandler { ] .contains(&e.0) }) - .map(|evt| (evt.0, evt.1.into_any())); + .map(|evt| (evt.0, evt.1)); - 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); + v.push(Rc::new(data)); } else { - hm.insert(event, vec![data]); + hm.insert(event, vec![Rc::new(data)]); } } for (event, datas) in hm { @@ -690,14 +686,12 @@ impl RinkInputHandler { for data in &datas { let focused = node.get::(); if focused.is_some() && focused.unwrap().0 { - if let Some(id) = node.mounted_id() { - resolved_events.push(Event { - name: event, - id, - data: data.clone(), - bubbles: event_bubbles(event), - }); - } + resolved_events.push(Event { + name: event, + id: node.id(), + data: data.clone(), + bubbles: event_bubbles(event), + }); } } } @@ -779,7 +773,7 @@ fn get_event(evt: TermEvent) -> Option<(&'static str, EventData)> { MouseEventKind::ScrollUp => ("wheel", get_wheel_data(true)), } } - TermEvent::Resize(x, y) => ("resize", EventData::Screen((x, y))), + _ => return None, }; Some((name, data)) diff --git a/packages/tui/src/layout.rs b/packages/tui/src/layout.rs index 6e34ba0c9..5dfbd6c0b 100644 --- a/packages/tui/src/layout.rs +++ b/packages/tui/src/layout.rs @@ -47,7 +47,7 @@ impl Pass for TaffyLayout { type ParentDependencies = (); type NodeDependencies = (); - const NODE_MASK: NodeMaskBuilder = NodeMaskBuilder::new() + const NODE_MASK: NodeMaskBuilder<'static> = NodeMaskBuilder::new() .with_attrs(AttributeMaskBuilder::Some(SORTED_LAYOUT_ATTRS)) .with_text(); diff --git a/packages/tui/src/lib.rs b/packages/tui/src/lib.rs index a26cfe547..f39564a4c 100644 --- a/packages/tui/src/lib.rs +++ b/packages/tui/src/lib.rs @@ -6,24 +6,17 @@ use crossterm::{ execute, terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, }; -use dioxus_core::*; -use dioxus_native_core::{node_ref::NodeMaskBuilder, real_dom::NodeImmutable, Pass}; +use dioxus_html::EventData; +use dioxus_native_core::{node_ref::NodeMaskBuilder, real_dom::NodeImmutable, Pass, Renderer}; use dioxus_native_core::{real_dom::RealDom, FxDashSet, NodeId, SendAnyMap}; use focus::FocusState; -use futures::{ - channel::mpsc::{UnboundedReceiver, UnboundedSender}, - pin_mut, StreamExt, -}; +use futures::{channel::mpsc::UnboundedSender, pin_mut, StreamExt}; use futures_channel::mpsc::unbounded; use layout::TaffyLayout; use prevent_default::PreventDefault; -use query::Query; -use std::rc::Rc; -use std::{ - cell::RefCell, - sync::{Arc, Mutex}, -}; +use std::sync::{Arc, Mutex}; use std::{io, time::Duration}; +use std::{rc::Rc, sync::RwLock}; use style_attributes::StyleModifier; use taffy::Taffy; pub use taffy::{geometry::Point, prelude::*}; @@ -41,7 +34,7 @@ mod render; mod style; mod style_attributes; mod widget; -mod widgets; +// mod widgets; pub use config::*; pub use hooks::*; @@ -75,21 +68,21 @@ impl TuiContext { } } -pub fn launch(app: Component<()>) { - launch_cfg(app, Config::default()) -} +pub fn render>>( + cfg: Config, + f: impl FnOnce(&Arc>, &Arc>, UnboundedSender) -> R, +) -> Result<()> { + let mut rdom = RealDom::new(Box::new([ + TaffyLayout::to_type_erased(), + Focus::to_type_erased(), + StyleModifier::to_type_erased(), + PreventDefault::to_type_erased(), + ])); -pub fn launch_cfg(app: Component<()>, cfg: Config) { - launch_cfg_with_props(app, (), cfg); -} - -pub fn launch_cfg_with_props(app: Component, props: Props, cfg: Config) { - let mut dom = VirtualDom::new_with_props(app, props); - - let (handler, state, register_event) = RinkInputHandler::new(); + let (handler, state, mut register_event) = RinkInputHandler::craete(&mut rdom); // Setup input handling - let (event_tx, event_rx) = unbounded(); + let (event_tx, mut event_reciever) = unbounded(); let event_tx_clone = event_tx.clone(); if !cfg.headless { std::thread::spawn(move || { @@ -105,51 +98,19 @@ pub fn launch_cfg_with_props(app: Component, props: Props }); } - let cx = dom.base_scope(); - let rdom = Rc::new(RefCell::new(RealDom::new(Box::new([ - TaffyLayout::to_type_erased(), - Focus::to_type_erased(), - StyleModifier::to_type_erased(), - PreventDefault::to_type_erased(), - ])))); + let rdom = Arc::new(RwLock::new(rdom)); 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(), - }); + let mut renderer = f(&rdom, &taffy, event_tx_clone); { - let mut rdom = rdom.borrow_mut(); - let mutations = dom.rebuild(); - rdom.apply_mutations(mutations); + let mut rdom = rdom.write().unwrap(); + let root_id = rdom.root_id(); + renderer.render(rdom.get_mut(root_id).unwrap()); let mut any_map = SendAnyMap::new(); any_map.insert(taffy.clone()); let _ = rdom.update_state(any_map, false); } - render_vdom( - &mut dom, - event_rx, - handler, - cfg, - rdom, - taffy, - register_event, - ) - .unwrap(); -} - -fn render_vdom( - vdom: &mut VirtualDom, - mut event_reciever: UnboundedReceiver, - handler: RinkInputHandler, - cfg: Config, - rdom: Rc>, - taffy: Arc>, - mut register_event: impl FnMut(crossterm::event::Event), -) -> Result<()> { tokio::runtime::Builder::new_current_thread() .enable_all() .build()? @@ -225,16 +186,16 @@ fn render_vdom( if let Some(terminal) = &mut terminal { execute!(terminal.backend_mut(), SavePosition).unwrap(); terminal.draw(|frame| { - let rdom = rdom.borrow(); + let rdom = rdom.write().unwrap(); let mut taffy = taffy.lock().expect("taffy lock poisoned"); // size is guaranteed to not change when rendering resize(frame.size(), &mut taffy, &rdom); - let root = rdom.get(NodeId(0)).unwrap(); + let root = rdom.get(rdom.root_id()).unwrap(); render::render_vnode(frame, &taffy, root, cfg, Point::ZERO); })?; execute!(terminal.backend_mut(), RestorePosition, Show).unwrap(); } else { - let rdom = rdom.borrow(); + let rdom = rdom.write().unwrap(); resize( Rect { x: 0, @@ -248,13 +209,13 @@ fn render_vdom( } } - let mut hot_reload_msg = None; + // let mut hot_reload_msg = None; { - let wait = vdom.wait_for_work(); - #[cfg(all(feature = "hot-reload", debug_assertions))] - let hot_reload_wait = hot_reload_rx.recv(); - #[cfg(not(all(feature = "hot-reload", debug_assertions)))] - let hot_reload_wait = std::future::pending(); + let wait = renderer.poll_async(); + // #[cfg(all(feature = "hot-reload", debug_assertions))] + // let hot_reload_wait = hot_reload_rx.recv(); + // #[cfg(not(all(feature = "hot-reload", debug_assertions)))] + // let hot_reload_wait = std::future::pending(); pin_mut!(wait); @@ -283,40 +244,40 @@ fn render_vdom( register_event(evt); } }, - Some(msg) = hot_reload_wait => { - hot_reload_msg = Some(msg); - } + // Some(msg) = hot_reload_wait => { + // hot_reload_msg = Some(msg); + // } } } - // if we have a new template, replace the old one - if let Some(msg) = hot_reload_msg { - match msg { - dioxus_hot_reload::HotReloadMsg::UpdateTemplate(template) => { - vdom.replace_template(template); - } - dioxus_hot_reload::HotReloadMsg::Shutdown => { - break; - } - } - } + // // if we have a new template, replace the old one + // if let Some(msg) = hot_reload_msg { + // match msg { + // dioxus_hot_reload::HotReloadMsg::UpdateTemplate(template) => { + // vdom.replace_template(template); + // } + // dioxus_hot_reload::HotReloadMsg::Shutdown => { + // break; + // } + // } + // } { - let evts = { - let mut rdom = rdom.borrow_mut(); - handler.get_events(&taffy.lock().expect("taffy lock poisoned"), &mut rdom) - }; { + let mut rdom = rdom.write().unwrap(); + let evts = handler + .get_events(&taffy.lock().expect("taffy lock poisoned"), &mut rdom); updated |= handler.state().focus_state.clean(); + + for e in evts { + let node = rdom.get_mut(e.id).unwrap(); + renderer.handle_event(node, e.name, e.data); + } } - for e in evts { - vdom.handle_event(e.name, e.data, e.id, e.bubbles) - } - let mut rdom = rdom.borrow_mut(); - let mutations = vdom.render_immediate(); - handler.prune(&mutations, &rdom); + let mut rdom = rdom.write().unwrap(); // updates the dom's nodes - rdom.apply_mutations(mutations); + let root_id = rdom.root_id(); + renderer.render(rdom.get_mut(root_id).unwrap()); // update the style and layout let mut any_map = SendAnyMap::new(); any_map.insert(taffy.clone()); @@ -346,7 +307,7 @@ fn render_vdom( } #[derive(Debug)] -enum InputEvent { +pub enum InputEvent { UserInput(TermEvent), Close, } diff --git a/packages/tui/src/prelude/mod.rs b/packages/tui/src/prelude/mod.rs index 2155f7707..2d5b029a0 100644 --- a/packages/tui/src/prelude/mod.rs +++ b/packages/tui/src/prelude/mod.rs @@ -1 +1 @@ -pub use crate::widgets::*; +// pub use crate::widgets::*; diff --git a/packages/tui/src/prevent_default.rs b/packages/tui/src/prevent_default.rs index e527b099b..0fda912c9 100644 --- a/packages/tui/src/prevent_default.rs +++ b/packages/tui/src/prevent_default.rs @@ -30,7 +30,7 @@ impl Pass for PreventDefault { type ChildDependencies = (); type NodeDependencies = (); - const NODE_MASK: dioxus_native_core::node_ref::NodeMaskBuilder = + const NODE_MASK: dioxus_native_core::node_ref::NodeMaskBuilder<'static> = dioxus_native_core::node_ref::NodeMaskBuilder::new() .with_attrs(dioxus_native_core::node_ref::AttributeMaskBuilder::Some(&[ "dioxus-prevent-default", diff --git a/packages/tui/src/query.rs b/packages/tui/src/query.rs index df1f69fbd..4bf89516d 100644 --- a/packages/tui/src/query.rs +++ b/packages/tui/src/query.rs @@ -4,8 +4,7 @@ use std::{ sync::{Arc, Mutex, MutexGuard}, }; -use dioxus_core::ElementId; -use dioxus_native_core::{real_dom::NodeImmutable, RealDom}; +use dioxus_native_core::{real_dom::NodeImmutable, NodeId, RealDom}; use taffy::{ geometry::Point, prelude::{Layout, Size}, @@ -52,7 +51,7 @@ pub struct Query { } impl Query { - pub fn get(&self, id: ElementId) -> ElementRef { + pub fn get(&self, id: NodeId) -> ElementRef { ElementRef::new( self.rdom.borrow(), self.stretch.lock().expect("taffy lock poisoned"), @@ -64,11 +63,11 @@ impl Query { pub struct ElementRef<'a> { inner: Ref<'a, RealDom>, stretch: MutexGuard<'a, Taffy>, - id: ElementId, + id: NodeId, } impl<'a> ElementRef<'a> { - fn new(inner: Ref<'a, RealDom>, stretch: MutexGuard<'a, Taffy>, id: ElementId) -> Self { + fn new(inner: Ref<'a, RealDom>, stretch: MutexGuard<'a, Taffy>, id: NodeId) -> Self { Self { inner, stretch, id } } diff --git a/packages/tui/src/style_attributes.rs b/packages/tui/src/style_attributes.rs index 27c262ff1..30b1ef2a1 100644 --- a/packages/tui/src/style_attributes.rs +++ b/packages/tui/src/style_attributes.rs @@ -51,7 +51,7 @@ impl Pass for StyleModifier { type NodeDependencies = (); // todo: seperate each attribute into it's own class - const NODE_MASK: NodeMaskBuilder = NodeMaskBuilder::new() + const NODE_MASK: NodeMaskBuilder<'static> = NodeMaskBuilder::new() .with_attrs(AttributeMaskBuilder::Some(SORTED_STYLE_ATTRS)) .with_element(); diff --git a/packages/tui/src/widgets/button.rs b/packages/tui/src/widgets/button.rs index f3ebc7901..a6578905e 100644 --- a/packages/tui/src/widgets/button.rs +++ b/packages/tui/src/widgets/button.rs @@ -37,7 +37,7 @@ pub(crate) fn Button<'a>(cx: Scope<'a, ButtonProps>) -> Element<'a> { } state.set(new_state); }; - cx.render(rsx! { + render! { div{ width: "{width}", height: "{height}", @@ -55,5 +55,5 @@ pub(crate) fn Button<'a>(cx: Scope<'a, ButtonProps>) -> Element<'a> { }, "{text}" } - }) + } } diff --git a/packages/tui/src/widgets/checkbox.rs b/packages/tui/src/widgets/checkbox.rs index 483117212..0b5ebf671 100644 --- a/packages/tui/src/widgets/checkbox.rs +++ b/packages/tui/src/widgets/checkbox.rs @@ -61,7 +61,7 @@ pub(crate) fn CheckBox<'a>(cx: Scope<'a, CheckBoxProps>) -> Element<'a> { } state.set(new_state); }; - cx.render(rsx! { + render! { div { width: "{width}", height: "{height}", @@ -78,5 +78,5 @@ pub(crate) fn CheckBox<'a>(cx: Scope<'a, CheckBoxProps>) -> Element<'a> { }, "{text}" } - }) + } } diff --git a/packages/tui/src/widgets/number.rs b/packages/tui/src/widgets/number.rs index f34618f60..48e198ebd 100644 --- a/packages/tui/src/widgets/number.rs +++ b/packages/tui/src/widgets/number.rs @@ -99,7 +99,7 @@ pub(crate) fn NumbericInput<'a>(cx: Scope<'a, NumbericInputProps>) -> Element<'a update(text.clone()); }; - cx.render(rsx! { + render! { div{ width: "{width}", height: "{height}", @@ -205,5 +205,5 @@ pub(crate) fn NumbericInput<'a>(cx: Scope<'a, NumbericInputProps>) -> Element<'a "{text_after_second_cursor}" } - }) + } } diff --git a/packages/tui/src/widgets/password.rs b/packages/tui/src/widgets/password.rs index 6574ab4f9..714a5ad93 100644 --- a/packages/tui/src/widgets/password.rs +++ b/packages/tui/src/widgets/password.rs @@ -114,7 +114,7 @@ pub(crate) fn Password<'a>(cx: Scope<'a, PasswordProps>) -> Element<'a> { } }; - cx.render(rsx! { + render! { div { width: "{width}", height: "{height}", @@ -187,5 +187,5 @@ pub(crate) fn Password<'a>(cx: Scope<'a, PasswordProps>) -> Element<'a> { "{text_after_second_cursor}" } - }) + } } diff --git a/packages/tui/src/widgets/slider.rs b/packages/tui/src/widgets/slider.rs index 0d5dbca13..32de32ce2 100644 --- a/packages/tui/src/widgets/slider.rs +++ b/packages/tui/src/widgets/slider.rs @@ -62,7 +62,7 @@ pub(crate) fn Slider<'a>(cx: Scope<'a, SliderProps>) -> Element<'a> { } }; - cx.render(rsx! { + render! { div{ width: "{width}", height: "{height}", @@ -103,5 +103,5 @@ pub(crate) fn Slider<'a>(cx: Scope<'a, SliderProps>) -> Element<'a> { background_color: "rgba(10,10,10,0.5)", } } - }) + } } diff --git a/packages/tui/src/widgets/textbox.rs b/packages/tui/src/widgets/textbox.rs index 5e3cc693a..ad48f0800 100644 --- a/packages/tui/src/widgets/textbox.rs +++ b/packages/tui/src/widgets/textbox.rs @@ -79,7 +79,7 @@ pub(crate) fn TextBox<'a>(cx: Scope<'a, TextBoxProps>) -> Element<'a> { "solid" }; - cx.render(rsx! { + render! { div{ width: "{width}", height: "{height}", @@ -178,5 +178,5 @@ pub(crate) fn TextBox<'a>(cx: Scope<'a, TextBoxProps>) -> Element<'a> { "{text_after_second_cursor}" } - }) + } }