dioxus/packages/dioxus-tui/src/lib.rs

187 lines
6 KiB
Rust
Raw Normal View History

#![doc = include_str!("../README.md")]
#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/79236386")]
#![doc(html_favicon_url = "https://avatars.githubusercontent.com/u/79236386")]
mod element;
2023-02-10 10:56:24 -06:00
use std::{
any::Any,
2023-02-10 10:56:24 -06:00
ops::Deref,
rc::Rc,
sync::{Arc, RwLock},
};
2023-02-07 14:51:30 -06:00
2023-02-09 21:34:47 -06:00
use dioxus_core::{Component, ElementId, VirtualDom};
2023-03-13 17:49:37 -05:00
use dioxus_native_core::dioxus::{DioxusState, NodeImmutableDioxusExt};
use dioxus_native_core::prelude::*;
2023-02-07 14:51:30 -06:00
use element::{create_mounted_events, find_mount_events};
pub use plasmo::{query::Query, Config, RenderingMode, Size, TuiContext};
use plasmo::{render, Driver};
2023-02-07 14:51:30 -06:00
2023-02-06 21:28:48 -06:00
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<Props: 'static>(app: Component<Props>, props: Props, cfg: Config) {
2023-02-07 14:51:30 -06:00
render(cfg, |rdom, taffy, event_tx| {
2023-02-10 11:01:24 -06:00
let dioxus_state = {
let mut rdom = rdom.write().unwrap();
DioxusState::create(&mut rdom)
};
let dioxus_state = Rc::new(RwLock::new(dioxus_state));
2023-02-07 14:51:30 -06:00
let mut vdom = VirtualDom::new_with_props(app, props)
.with_root_context(TuiContext::new(event_tx))
.with_root_context(Query::new(rdom.clone(), taffy.clone()))
2023-02-10 11:01:24 -06:00
.with_root_context(DioxusElementToNodeId {
mapping: dioxus_state.clone(),
2023-02-07 14:51:30 -06:00
});
let muts = vdom.rebuild();
let mut queued_events = Vec::new();
{
let mut rdom = rdom.write().unwrap();
let mut dioxus_state = dioxus_state.write().unwrap();
// Find any mount events
2023-06-30 12:49:37 -07:00
let mounted = find_mount_events(&muts);
dioxus_state.apply_mutations(&mut rdom, muts);
// Send the mount events
create_mounted_events(
&vdom,
&mut queued_events,
mounted
.iter()
.map(|id| (*dbg!(id), dioxus_state.element_to_node_id(*id))),
);
}
2023-02-07 14:51:30 -06:00
DioxusRenderer {
vdom,
dioxus_state,
queued_events,
2023-02-07 14:51:30 -06:00
#[cfg(all(feature = "hot-reload", debug_assertions))]
hot_reload_rx: {
let (hot_reload_tx, hot_reload_rx) =
tokio::sync::mpsc::unbounded_channel::<dioxus_hot_reload::HotReloadMsg>();
dioxus_hot_reload::connect(move |msg| {
let _ = hot_reload_tx.send(msg);
});
hot_reload_rx
},
}
})
.unwrap();
}
struct DioxusRenderer {
vdom: VirtualDom,
2023-02-09 21:34:47 -06:00
dioxus_state: Rc<RwLock<DioxusState>>,
// Events that are queued up to be sent to the vdom next time the vdom is polled
queued_events: Vec<(ElementId, &'static str, Rc<dyn Any>, bool)>,
2023-02-07 14:51:30 -06:00
#[cfg(all(feature = "hot-reload", debug_assertions))]
hot_reload_rx: tokio::sync::mpsc::UnboundedReceiver<dioxus_hot_reload::HotReloadMsg>,
}
impl Driver for DioxusRenderer {
fn update(&mut self, rdom: &Arc<RwLock<RealDom>>) {
2023-02-07 14:51:30 -06:00
let muts = self.vdom.render_immediate();
2023-02-10 10:56:24 -06:00
{
let mut rdom = rdom.write().unwrap();
{
// Find any mount events
let mounted = find_mount_events(&muts);
let mut dioxus_state = self.dioxus_state.write().unwrap();
dioxus_state.apply_mutations(&mut rdom, muts);
// Send the mount events
create_mounted_events(
&self.vdom,
&mut self.queued_events,
mounted
.iter()
.map(|id| (*id, dioxus_state.element_to_node_id(*id))),
);
}
2023-02-10 10:56:24 -06:00
}
2023-02-07 14:51:30 -06:00
}
2023-02-06 21:28:48 -06:00
2023-02-07 14:51:30 -06:00
fn handle_event(
&mut self,
2023-02-10 10:56:24 -06:00
rdom: &Arc<RwLock<RealDom>>,
id: NodeId,
2023-02-07 14:51:30 -06:00
event: &str,
value: Rc<plasmo::EventData>,
2023-02-07 14:51:30 -06:00
bubbles: bool,
) {
2023-02-10 10:56:24 -06:00
let id = { rdom.read().unwrap().get(id).unwrap().mounted_id() };
if let Some(id) = id {
2023-03-24 12:43:51 -05:00
let inner_value = value.deref().clone();
2023-02-07 14:51:30 -06:00
self.vdom
2023-03-24 12:43:51 -05:00
.handle_event(event, inner_value.into_any(), id, bubbles);
2023-02-07 14:51:30 -06:00
}
}
2023-02-06 21:28:48 -06:00
2023-02-07 14:51:30 -06:00
fn poll_async(&mut self) -> std::pin::Pin<Box<dyn futures::Future<Output = ()> + '_>> {
// Add any queued events
for (id, event, value, bubbles) in self.queued_events.drain(..) {
self.vdom.handle_event(event, value, id, bubbles);
}
2023-02-07 14:51:30 -06:00
#[cfg(all(feature = "hot-reload", debug_assertions))]
return Box::pin(async {
let hot_reload_wait = self.hot_reload_rx.recv();
let mut hot_reload_msg = None;
let wait_for_work = self.vdom.wait_for_work();
tokio::select! {
2023-02-07 14:51:30 -06:00
Some(msg) = hot_reload_wait => {
#[cfg(all(feature = "hot-reload", debug_assertions))]
{
hot_reload_msg = Some(msg);
}
#[cfg(not(all(feature = "hot-reload", debug_assertions)))]
let () = msg;
}
_ = wait_for_work => {}
}
// 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) => {
self.vdom.replace_template(template);
}
dioxus_hot_reload::HotReloadMsg::Shutdown => {
std::process::exit(0);
2023-02-06 21:28:48 -06:00
}
}
}
});
2023-02-07 14:51:30 -06:00
#[cfg(not(all(feature = "hot-reload", debug_assertions)))]
Box::pin(self.vdom.wait_for_work())
2023-02-06 21:28:48 -06:00
}
}
2023-02-09 21:34:47 -06:00
#[derive(Clone)]
pub struct DioxusElementToNodeId {
mapping: Rc<RwLock<DioxusState>>,
}
impl DioxusElementToNodeId {
pub fn get_node_id(&self, element_id: ElementId) -> Option<NodeId> {
self.mapping
.read()
.unwrap()
.try_element_to_node_id(element_id)
}
}