2022-01-12 14:40:36 +00:00
|
|
|
use anyhow::Result;
|
|
|
|
use crossterm::{
|
|
|
|
event::{
|
|
|
|
DisableMouseCapture, EnableMouseCapture, Event as TermEvent, KeyCode, KeyEvent, MouseEvent,
|
|
|
|
},
|
|
|
|
execute,
|
|
|
|
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
|
|
|
};
|
|
|
|
use dioxus::{core::exports::futures_channel::mpsc::unbounded, prelude::Props};
|
|
|
|
use dioxus::{core::*, prelude::*};
|
|
|
|
use futures::{channel::mpsc::UnboundedReceiver, future::Either, pin_mut, StreamExt};
|
|
|
|
use std::{
|
|
|
|
cell::{Cell, RefCell},
|
|
|
|
collections::HashMap,
|
|
|
|
io,
|
|
|
|
rc::Rc,
|
|
|
|
time::{Duration, Instant},
|
|
|
|
};
|
|
|
|
use stretch2::{prelude::Size, Stretch};
|
2022-02-04 20:52:01 +00:00
|
|
|
use tokio::sync::broadcast::Receiver;
|
2022-01-12 14:40:36 +00:00
|
|
|
use tui::{backend::CrosstermBackend, style::Style as TuiStyle, Terminal};
|
|
|
|
|
|
|
|
pub struct RinkContext {
|
2022-02-04 20:52:01 +00:00
|
|
|
last_event: Rc<Cell<Option<TermEvent>>>,
|
|
|
|
subscribers: Rc<RefCell<HashMap<ScopeId, bool>>>,
|
2022-01-12 14:40:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl RinkContext {
|
2022-02-04 20:52:01 +00:00
|
|
|
pub fn new(mut receiver: UnboundedReceiver<TermEvent>, 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2022-01-12 14:40:36 +00:00
|
|
|
Self {
|
2022-02-04 20:52:01 +00:00
|
|
|
last_event: last_event,
|
|
|
|
subscribers: subscribers,
|
2022-01-12 14:40:36 +00:00
|
|
|
}
|
|
|
|
}
|
2022-02-04 20:52:01 +00:00
|
|
|
|
2022-01-12 14:40:36 +00:00
|
|
|
pub fn subscribe_to_events(&self, scope: ScopeId) {
|
2022-02-04 20:52:01 +00:00
|
|
|
self.subscribers.borrow_mut().insert(scope, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_event(&self, scope: ScopeId) -> Option<TermEvent> {
|
|
|
|
let mut subscribers = self.subscribers.borrow_mut();
|
|
|
|
let received = subscribers.get_mut(&scope)?;
|
|
|
|
if !*received {
|
|
|
|
*received = true;
|
|
|
|
self.last_event.get()
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
2022-01-12 14:40:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Props)]
|
|
|
|
pub struct AppHandlerProps<'a> {
|
2022-02-04 13:24:02 +00:00
|
|
|
#[props(default)]
|
2022-01-12 14:40:36 +00:00
|
|
|
onkeydown: EventHandler<'a, KeyEvent>,
|
|
|
|
|
2022-02-04 13:24:02 +00:00
|
|
|
#[props(default)]
|
2022-01-12 14:40:36 +00:00
|
|
|
onmousedown: EventHandler<'a, MouseEvent>,
|
|
|
|
|
2022-02-04 13:24:02 +00:00
|
|
|
#[props(default)]
|
2022-02-04 20:52:01 +00:00
|
|
|
onresize: EventHandler<'a, (u16, u16)>,
|
2022-01-12 14:40:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// This component lets you handle input events
|
|
|
|
///
|
|
|
|
/// Once attached to the DOM, it will listen for input events from the terminal
|
|
|
|
///
|
|
|
|
///
|
|
|
|
pub fn InputHandler<'a>(cx: Scope<'a, AppHandlerProps<'a>>) -> Element {
|
|
|
|
let rcx = cx.use_hook(|_| {
|
|
|
|
let rcx = cx
|
|
|
|
.consume_context::<RinkContext>()
|
|
|
|
.unwrap_or_else(|| panic!("Rink InputHandlers can only be used in Rink apps!"));
|
|
|
|
|
|
|
|
// our component will only re-render if new events are received ... or if the parent is updated
|
|
|
|
// todo: if update was not caused by a new event, we should not re-render
|
|
|
|
// perhaps add some tracking to context?
|
|
|
|
rcx.subscribe_to_events(cx.scope_id());
|
|
|
|
|
|
|
|
rcx
|
|
|
|
});
|
|
|
|
|
2022-02-04 20:52:01 +00:00
|
|
|
{
|
|
|
|
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));
|
|
|
|
}
|
2022-01-12 14:40:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
None
|
|
|
|
}
|