Merge pull request #940 from Demonthos/make-widgets-cross-framework

This commit is contained in:
Jonathan Kelley authored and GitHub committed 2023-07-11 20:47:01 -07:00
commit f4b3be1b13
44 files changed
+3232 -1185

No files matched your search

+98 -19
View File
@@ -6,8 +6,7 @@ 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::{prelude::*, tree::TreeRef};
use dioxus_native_core::{real_dom::RealDom, FxDashSet, NodeId, SendAnyMap};
use focus::FocusState;
use futures::{channel::mpsc::UnboundedSender, pin_mut, Future, StreamExt};
@@ -21,22 +20,22 @@ use std::{
};
use std::{rc::Rc, sync::RwLock};
use style_attributes::StyleModifier;
use taffy::Taffy;
pub use taffy::{geometry::Point, prelude::*};
use tokio::select;
use tui::{backend::CrosstermBackend, layout::Rect, Terminal};
use tui::{backend::CrosstermBackend, 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,11 +90,14 @@ 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 || {
// Timeout after 10ms when waiting for events
@@ -103,7 +105,10 @@ pub fn render<R: Driver>(
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;
}
}
@@ -111,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();
@@ -160,7 +176,7 @@ pub fn render<R: Driver>(
if !to_rerender.is_empty() || updated {
updated = false;
fn resize(dims: Rect, taffy: &mut Taffy, rdom: &RealDom) {
fn resize(dims: tui::layout::Rect, taffy: &mut Taffy, rdom: &RealDom) {
let width = screen_to_layout_space(dims.width);
let height = screen_to_layout_space(dims.height);
let root_node = rdom
@@ -202,7 +218,7 @@ pub fn render<R: Driver>(
} else {
let rdom = rdom.read().unwrap();
resize(
Rect {
tui::layout::Rect {
x: 0,
y: 0,
width: 1000,
@@ -214,6 +230,7 @@ pub fn render<R: Driver>(
}
}
let mut event_recieved = None;
{
let wait = renderer.poll_async();
@@ -223,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) => {
@@ -244,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
@@ -310,3 +338,54 @@ 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(id);
while let Some(node_id) = node {
let parent_id = {
let tree = rdom.tree_ref();
tree.parent_id_advanced(node_id, true)
};
{
// println!("@ bubbling event to node {:?}", node_id);
let mut node_mut = rdom.get_mut(node_id).unwrap();
if let Some(mut widget) = node_mut
.get_mut::<RinkWidgetTraitObject>()
.map(|w| w.clone())
{
widget.handle_event(event, node_mut)
}
}
if !event.bubbles {
// println!("event does not bubble");
break;
}
node = parent_id;
}
}
pub(crate) fn get_abs_layout(node: NodeRef, taffy: &Taffy) -> Layout {
let mut node_layout = *taffy
.layout(node.get::<TaffyLayout>().unwrap().node.unwrap())
.unwrap();
let mut current = node;
let dom = node.real_dom();
let tree = dom.tree_ref();
while let Some(parent) = tree.parent_id_advanced(current.id(), true) {
let parent = dom.get(parent).unwrap();
current = parent;
let parent_layout = taffy
.layout(parent.get::<TaffyLayout>().unwrap().node.unwrap())
.unwrap();
node_layout.location.x += parent_layout.location.x;
node_layout.location.y += parent_layout.location.y;
}
node_layout
}