make TUI widgets cross framework

This commit is contained in:
Evan Almloff committed 2023-03-19 13:26:29 -05:00
1 parent 9a16687bdc
commit c4c35cb046
33 files changed
+3025 -1091

No files matched your search

+63 -14
View File
@@ -6,7 +6,6 @@ use crossterm::{
execute,
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
use dioxus_html::EventData;
use dioxus_native_core::prelude::*;
use dioxus_native_core::{real_dom::RealDom, FxDashSet, NodeId, SendAnyMap};
use focus::FocusState;
@@ -25,18 +24,19 @@ use taffy::Taffy;
pub use taffy::{geometry::Point, prelude::*};
use tokio::select;
use tui::{backend::CrosstermBackend, layout::Rect, Terminal};
use widgets::{register_widgets, RinkWidgetResponder, RinkWidgetTraitObject};
mod config;
mod focus;
mod hooks;
mod layout;
pub mod prelude;
mod prevent_default;
pub mod query;
mod render;
mod style;
mod style_attributes;
mod widget;
mod widgets;
pub use config::*;
pub use hooks::*;
@@ -91,18 +91,24 @@ pub fn render<R: Driver>(
PreventDefault::to_type_erased(),
]);
let (handler, mut register_event) = RinkInputHandler::create(&mut rdom);
// Setup input handling
// The event channel for fully resolved events
let (event_tx, mut event_reciever) = unbounded();
let event_tx_clone = event_tx.clone();
// The event channel for raw terminal events
let (raw_event_tx, mut raw_event_reciever) = unbounded();
let event_tx_clone = raw_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() {
if raw_event_tx
.unbounded_send(InputEvent::UserInput(evt))
.is_err()
{
break;
}
}
@@ -110,10 +116,21 @@ pub fn render<R: Driver>(
});
}
register_widgets(&mut rdom, event_tx);
let (handler, mut register_event) = RinkInputHandler::create(&mut rdom);
let rdom = Arc::new(RwLock::new(rdom));
let taffy = Arc::new(Mutex::new(Taffy::new()));
let mut renderer = create_renderer(&rdom, &taffy, event_tx_clone);
// insert the query engine into the rdom
let query_engine = Query::new(rdom.clone(), taffy.clone());
{
let mut rdom = rdom.write().unwrap();
rdom.raw_world_mut().add_unique(query_engine);
}
{
renderer.update(&rdom);
let mut any_map = SendAnyMap::new();
@@ -213,6 +230,7 @@ pub fn render<R: Driver>(
}
}
let mut event_recieved = None;
{
let wait = renderer.poll_async();
@@ -222,7 +240,7 @@ pub fn render<R: Driver>(
_ = wait => {
},
evt = event_reciever.next() => {
evt = raw_event_reciever.next() => {
match evt.as_ref().unwrap() {
InputEvent::UserInput(event) => match event {
TermEvent::Key(key) => {
@@ -243,21 +261,32 @@ pub fn render<R: Driver>(
register_event(evt);
}
},
Some(evt) = event_reciever.next() => {
event_recieved=Some(evt);
}
}
}
{
if let Some(evt) = event_recieved {
renderer.handle_event(
&rdom,
evt.id,
evt.name,
Rc::new(evt.data),
evt.bubbles,
);
}
{
let evts = {
handler.get_events(
&taffy.lock().expect("taffy lock poisoned"),
&mut rdom.write().unwrap(),
)
};
let evts = handler.get_events(
&taffy.lock().expect("taffy lock poisoned"),
&mut rdom.write().unwrap(),
);
updated |= handler.state().focus_state.clean();
for e in evts {
renderer.handle_event(&rdom, e.id, e.name, e.data, e.bubbles);
bubble_event_to_widgets(&mut rdom.write().unwrap(), &e);
renderer.handle_event(&rdom, e.id, e.name, Rc::new(e.data), e.bubbles);
}
}
// updates the dom's nodes
@@ -309,3 +338,23 @@ pub trait Driver {
);
fn poll_async(&mut self) -> Pin<Box<dyn Future<Output = ()> + '_>>;
}
/// Before sending the event to drivers, we need to bubble it up the tree to any widgets that are listening
fn bubble_event_to_widgets(rdom: &mut RealDom, event: &Event) {
let id = event.id;
let mut node = Some(rdom.get_mut(id).unwrap());
while let Some(mut node_mut) = node {
let parent_id = node_mut.parent_id();
if let Some(mut widget) = node_mut
.get_mut::<RinkWidgetTraitObject>()
.map(|w| w.clone())
{
widget.handle_event(event, &mut node_mut)
}
if !event.bubbles {
break;
}
node = parent_id.map(|id| rdom.get_mut(id).unwrap());
}
}