diff --git a/examples/keys.rs b/examples/keys.rs index 1270c5ea7..ef9df9750 100644 --- a/examples/keys.rs +++ b/examples/keys.rs @@ -1,6 +1,6 @@ use std::cell::RefCell; -use crossterm::event::KeyEvent; +use crossterm::event::{KeyCode, KeyEvent, MouseEvent}; use dioxus::prelude::*; use rink::InputHandler; @@ -9,6 +9,9 @@ fn main() { } fn app(cx: Scope) -> Element { + let (key, set_key) = use_state(&cx, || KeyCode::Null); + let (mouse, set_mouse) = use_state(&cx, || (0, 0)); + let (size, set_size) = use_state(&cx, || (0, 0)); let (count, set_count) = use_state(&cx, || 0); cx.render(rsx! { @@ -18,25 +21,31 @@ fn app(cx: Scope) -> Element { background_color: "red", justify_content: "center", align_items: "center", - "Hello world!", + flex_direction: "column", - // todo: enabling this will panic - // rink::InputHandler { - // onkeydown: move |evt: KeyEvent| { - // use crossterm::event::KeyCode::*; - // match evt.code { - // Left => set_count(count + 1), - // Right => set_count(count - 1), - // Up => set_count(count + 10), - // Down => set_count(count - 10), - // _ => {}, - // } - // }, - // onmousedown: move |evt| {}, - // onresize: move |dims| { - // println!("{:?}", dims); - // }, - // } + rink::InputHandler { + onkeydown: move |evt: KeyEvent| { + use crossterm::event::KeyCode::*; + match evt.code { + Left => set_count(count + 1), + Right => set_count(count - 1), + Up => set_count(count + 10), + Down => set_count(count - 10), + _ => {}, + } + set_key(evt.code); + }, + onmousedown: move |evt: MouseEvent| { + set_mouse((evt.row, evt.column)); + }, + onresize: move |dims| { + set_size(dims); + }, + }, + "count: {count:?}", + "key: {key:?}", + "mouse: {mouse:?}", + "resize: {size:?}", } }) } diff --git a/src/hooks.rs b/src/hooks.rs index 045325761..9ec8d47a6 100644 --- a/src/hooks.rs +++ b/src/hooks.rs @@ -17,22 +17,51 @@ use std::{ time::{Duration, Instant}, }; use stretch2::{prelude::Size, Stretch}; +use tokio::sync::broadcast::Receiver; use tui::{backend::CrosstermBackend, style::Style as TuiStyle, Terminal}; pub struct RinkContext { - last_event: RefCell>, - receiver: Rc>>>, + last_event: Rc>>, + subscribers: Rc>>, } impl RinkContext { - pub fn new(receiver: UnboundedReceiver) -> Self { + pub fn new(mut receiver: UnboundedReceiver, cx: &ScopeState) -> Self { + let updater = cx.schedule_update_any(); + let last_event = Rc::new(Cell::new(None)); + let last_event2 = last_event.clone(); + let subscribers = Rc::new(RefCell::new(HashMap::new())); + let subscribers2 = subscribers.clone(); + + cx.push_future(async move { + while let Some(evt) = receiver.next().await { + last_event2.replace(Some(evt)); + for (subscriber, received) in subscribers2.borrow_mut().iter_mut() { + updater(*subscriber); + *received = false; + } + } + }); + Self { - last_event: RefCell::new(None), - receiver: Rc::new(Cell::new(Some(receiver))), + last_event: last_event, + subscribers: subscribers, } } + pub fn subscribe_to_events(&self, scope: ScopeId) { - // + self.subscribers.borrow_mut().insert(scope, false); + } + + pub fn get_event(&self, scope: ScopeId) -> Option { + let mut subscribers = self.subscribers.borrow_mut(); + let received = subscribers.get_mut(&scope)?; + if !*received { + *received = true; + self.last_event.get() + } else { + None + } } } @@ -45,7 +74,7 @@ pub struct AppHandlerProps<'a> { onmousedown: EventHandler<'a, MouseEvent>, #[props(default)] - onresize: Option>, + onresize: EventHandler<'a, (u16, u16)>, } /// This component lets you handle input events @@ -64,38 +93,26 @@ pub fn InputHandler<'a>(cx: Scope<'a, AppHandlerProps<'a>>) -> Element { // perhaps add some tracking to context? rcx.subscribe_to_events(cx.scope_id()); - let mut rec = rcx.receiver.take().unwrap(); - let updater = cx.schedule_update(); - let rc2 = rcx.clone(); - cx.push_future(async move { - while let Some(evt) = rec.next().await { - rc2.last_event.borrow_mut().replace(evt); - println!("{:?}", evt); - updater(); - } - // - }); - rcx }); - if let Some(evet) = rcx.last_event.borrow().as_ref() { - match evet { - TermEvent::Key(key) => { - cx.props.onkeydown.call(key.clone()); - // let mut handler = cx.props.keydown.borrow_mut(); - // handler(*key); - // if let Some(handler) = cx.props.onkeydown { - // handler(*key); - // } - } - TermEvent::Mouse(mouse) => { - cx.props.onmousedown.call(mouse.clone()); - } - TermEvent::Resize(x, y) => { - // if let Some(handler) = cx.props.onresize { - // handler((*x, *y)); - // } + { + if let Some(evet) = rcx.get_event(cx.scope_id()) { + match evet { + TermEvent::Key(key) => { + cx.props.onkeydown.call(key.clone()); + // let mut handler = cx.props.keydown.borrow_mut(); + // handler(*key); + // if let Some(handler) = cx.props.onkeydown { + // handler(*key); + // } + } + TermEvent::Mouse(mouse) => { + cx.props.onmousedown.call(mouse.clone()); + } + TermEvent::Resize(x, y) => { + cx.props.onresize.call((x, y)); + } } } } diff --git a/src/lib.rs b/src/lib.rs index 801d5e068..89206b934 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,7 +35,10 @@ pub fn launch(app: Component<()>) { let mut dom = VirtualDom::new(app); let (tx, rx) = unbounded(); - dom.base_scope().provide_context(RinkContext::new(rx)); + let cx = dom.base_scope(); + + cx.provide_root_context(RinkContext::new(rx, cx)); + dom.rebuild(); render_vdom(&mut dom, tx).unwrap(); diff --git a/src/render.rs b/src/render.rs index 9189e4eaa..21cc6e01f 100644 --- a/src/render.rs +++ b/src/render.rs @@ -53,7 +53,9 @@ pub fn render_vnode<'a>( return; } - VNode::Placeholder(_) | VNode::Element(_) | VNode::Text(_) => {} + VNode::Placeholder(_) => return, + + VNode::Element(_) | VNode::Text(_) => {} } let id = node.try_mounted_id().unwrap();