make tui agnostic over framework
This commit is contained in:
1 parent
05b968e8e4
commit
c805bc25af
18 files changed
+262
-257
No files matched your search
@@ -241,7 +241,7 @@ fn create_template_node(rdom: &mut RealDom, node: &TemplateNode) -> NodeId {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait NodeImmutableDioxusExt<V: FromAnyValue + Send + Sync>: NodeImmutable<V> {
|
pub trait NodeImmutableDioxusExt<V: FromAnyValue + Send + Sync>: NodeImmutable<V> {
|
||||||
fn mounted_id(&self) -> Option<ElementId> {
|
fn mounted_id(&self) -> Option<ElementId> {
|
||||||
self.get().copied()
|
self.get().copied()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
use std::future::Future;
|
||||||
use std::hash::BuildHasherDefault;
|
use std::hash::BuildHasherDefault;
|
||||||
|
use std::pin::Pin;
|
||||||
|
|
||||||
pub use node_ref::NodeMask;
|
pub use node_ref::NodeMask;
|
||||||
pub use passes::AnyMapLike;
|
pub use passes::AnyMapLike;
|
||||||
pub use passes::{Dependancy, Pass, TypeErasedPass};
|
pub use passes::{Dependancy, Pass, TypeErasedPass};
|
||||||
|
use prelude::FromAnyValue;
|
||||||
pub use real_dom::{NodeMut, NodeRef, RealDom};
|
pub use real_dom::{NodeMut, NodeRef, RealDom};
|
||||||
use rustc_hash::FxHasher;
|
use rustc_hash::FxHasher;
|
||||||
pub use tree::NodeId;
|
pub use tree::NodeId;
|
||||||
@@ -31,3 +34,11 @@ pub mod prelude {
|
|||||||
pub type FxDashMap<K, V> = dashmap::DashMap<K, V, BuildHasherDefault<FxHasher>>;
|
pub type FxDashMap<K, V> = dashmap::DashMap<K, V, BuildHasherDefault<FxHasher>>;
|
||||||
pub type FxDashSet<K> = dashmap::DashSet<K, BuildHasherDefault<FxHasher>>;
|
pub type FxDashSet<K> = dashmap::DashSet<K, BuildHasherDefault<FxHasher>>;
|
||||||
pub type SendAnyMap = anymap::Map<dyn Any + Send + Sync + 'static>;
|
pub type SendAnyMap = anymap::Map<dyn Any + Send + Sync + 'static>;
|
||||||
|
|
||||||
|
pub trait Renderer<V: FromAnyValue + Send + Sync, E> {
|
||||||
|
fn render(&mut self, root: NodeMut<V>);
|
||||||
|
fn handle_event(&mut self, node: NodeMut<V>, event: &str, value: E);
|
||||||
|
fn poll_async(&mut self) -> Pin<Box<dyn Future<Output = ()> + Send>> {
|
||||||
|
Box::pin(async {})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,8 +13,8 @@ license = "MIT/Apache-2.0"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
dioxus = { path = "../dioxus", version = "^0.3.0" }
|
dioxus = { path = "../dioxus", version = "^0.3.0", optional = true }
|
||||||
dioxus-core = { path = "../core", version = "^0.3.0", features = ["serialize"] }
|
dioxus-core = { path = "../core", version = "^0.3.0", features = ["serialize"], optional = true }
|
||||||
dioxus-html = { path = "../html", version = "^0.3.0" }
|
dioxus-html = { path = "../html", version = "^0.3.0" }
|
||||||
dioxus-native-core = { path = "../native-core", version = "^0.2.0" }
|
dioxus-native-core = { path = "../native-core", version = "^0.2.0" }
|
||||||
dioxus-hot-reload = { path = "../hot-reload", optional = true }
|
dioxus-hot-reload = { path = "../hot-reload", optional = true }
|
||||||
@@ -40,5 +40,6 @@ name = "update"
|
|||||||
harness = false
|
harness = false
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["hot-reload"]
|
default = ["hot-reload", "dioxus-bindings"]
|
||||||
hot-reload = ["dioxus-hot-reload"]
|
hot-reload = ["dioxus-hot-reload"]
|
||||||
|
dioxus-bindings = ["dioxus", "dioxus-core", "dioxus-native-core/dioxus"]
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
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) {
|
||||||
|
let mut dom = VirtualDom::new_with_props(app, props);
|
||||||
|
let mut rdom = RealDom::new(Box::new([
|
||||||
|
TaffyLayout::to_type_erased(),
|
||||||
|
Focus::to_type_erased(),
|
||||||
|
StyleModifier::to_type_erased(),
|
||||||
|
PreventDefault::to_type_erased(),
|
||||||
|
]));
|
||||||
|
|
||||||
|
let (handler, state, register_event) = RinkInputHandler::craete(&mut rdom);
|
||||||
|
|
||||||
|
// Setup input handling
|
||||||
|
let (event_tx, event_rx) = unbounded();
|
||||||
|
let event_tx_clone = 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() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let cx = dom.base_scope();
|
||||||
|
let rdom = Rc::new(RefCell::new(rdom));
|
||||||
|
let taffy = Arc::new(Mutex::new(Taffy::new()));
|
||||||
|
cx.provide_context(state);
|
||||||
|
cx.provide_context(TuiContext { tx: event_tx_clone });
|
||||||
|
cx.provide_context(Query {
|
||||||
|
rdom: rdom.clone(),
|
||||||
|
stretch: taffy.clone(),
|
||||||
|
});
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut rdom = rdom.borrow_mut();
|
||||||
|
let mutations = dom.rebuild();
|
||||||
|
rdom.apply_mutations(mutations);
|
||||||
|
let mut any_map = SendAnyMap::new();
|
||||||
|
any_map.insert(taffy.clone());
|
||||||
|
let _ = rdom.update_state(any_map, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
render_vdom(
|
||||||
|
&mut dom,
|
||||||
|
event_rx,
|
||||||
|
handler,
|
||||||
|
cfg,
|
||||||
|
rdom,
|
||||||
|
taffy,
|
||||||
|
register_event,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
+19
-46
@@ -2,7 +2,7 @@ use crate::prevent_default::PreventDefault;
|
|||||||
|
|
||||||
use dioxus_native_core::{
|
use dioxus_native_core::{
|
||||||
node_ref::{AttributeMaskBuilder, NodeMaskBuilder},
|
node_ref::{AttributeMaskBuilder, NodeMaskBuilder},
|
||||||
real_dom::{NodeImmutable, NodeMutable},
|
real_dom::NodeImmutable,
|
||||||
utils::{ElementProduced, PersistantElementIter},
|
utils::{ElementProduced, PersistantElementIter},
|
||||||
Dependancy, NodeId, Pass, RealDom, SendAnyMap,
|
Dependancy, NodeId, Pass, RealDom, SendAnyMap,
|
||||||
};
|
};
|
||||||
@@ -64,7 +64,7 @@ pub(crate) struct Focus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Pass for Focus {
|
impl Pass for Focus {
|
||||||
const NODE_MASK: NodeMaskBuilder = NodeMaskBuilder::new()
|
const NODE_MASK: NodeMaskBuilder<'static> = NodeMaskBuilder::new()
|
||||||
.with_attrs(AttributeMaskBuilder::Some(FOCUS_ATTRIBUTES))
|
.with_attrs(AttributeMaskBuilder::Some(FOCUS_ATTRIBUTES))
|
||||||
.with_listeners();
|
.with_listeners();
|
||||||
|
|
||||||
@@ -138,7 +138,6 @@ impl Pass for Focus {
|
|||||||
const FOCUS_EVENTS: &[&str] = &["keydown", "keypress", "keyup"];
|
const FOCUS_EVENTS: &[&str] = &["keydown", "keypress", "keyup"];
|
||||||
const FOCUS_ATTRIBUTES: &[&str] = &["tabindex"];
|
const FOCUS_ATTRIBUTES: &[&str] = &["tabindex"];
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub(crate) struct FocusState {
|
pub(crate) struct FocusState {
|
||||||
pub(crate) focus_iter: PersistantElementIter,
|
pub(crate) focus_iter: PersistantElementIter,
|
||||||
pub(crate) last_focused_id: Option<NodeId>,
|
pub(crate) last_focused_id: Option<NodeId>,
|
||||||
@@ -147,6 +146,16 @@ pub(crate) struct FocusState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FocusState {
|
impl FocusState {
|
||||||
|
pub fn create(rdom: &mut RealDom) -> Self {
|
||||||
|
let mut focus_iter = PersistantElementIter::create(rdom);
|
||||||
|
Self {
|
||||||
|
focus_iter,
|
||||||
|
last_focused_id: Default::default(),
|
||||||
|
focus_level: Default::default(),
|
||||||
|
dirty: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns true if the focus has changed.
|
/// Returns true if the focus has changed.
|
||||||
pub fn progress(&mut self, rdom: &mut RealDom, forward: bool) -> bool {
|
pub fn progress(&mut self, rdom: &mut RealDom, forward: bool) -> bool {
|
||||||
if let Some(last) = self.last_focused_id {
|
if let Some(last) = self.last_focused_id {
|
||||||
@@ -242,14 +251,13 @@ impl FocusState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(id) = next_focus {
|
if let Some(id) = next_focus {
|
||||||
let mut node = rdom.get_mut_raw(id).unwrap();
|
let mut node = rdom.get_mut(id).unwrap();
|
||||||
if !node.get::<Focus>().unwrap().level.focusable() {
|
if !node.get::<Focus>().unwrap().level.focusable() {
|
||||||
panic!()
|
panic!()
|
||||||
}
|
}
|
||||||
node.insert(Focused(true));
|
node.insert(Focused(true));
|
||||||
if let Some(old) = self.last_focused_id.replace(id) {
|
if let Some(old) = self.last_focused_id.replace(id) {
|
||||||
let mut old = rdom.get_mut_raw(old).unwrap();
|
let focused = rdom.get_state_mut_raw::<Focused>(old).unwrap();
|
||||||
let focused = old.get_mut::<Focused>().unwrap();
|
|
||||||
focused.0 = false;
|
focused.0 = false;
|
||||||
}
|
}
|
||||||
// reset the position to the currently focused element
|
// reset the position to the currently focused element
|
||||||
@@ -261,49 +269,14 @@ impl FocusState {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn prune(&mut self, mutations: &dioxus_core::Mutations, rdom: &RealDom) {
|
|
||||||
fn remove_children(to_prune: &mut [&mut Option<NodeId>], rdom: &RealDom, removed: NodeId) {
|
|
||||||
for opt in to_prune.iter_mut() {
|
|
||||||
if let Some(id) = opt {
|
|
||||||
if *id == removed {
|
|
||||||
**opt = None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let node = rdom.get(removed).unwrap();
|
|
||||||
if let Some(children) = node.child_ids() {
|
|
||||||
for child in children {
|
|
||||||
remove_children(to_prune, rdom, *child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if self.focus_iter.prune(mutations, rdom) {
|
|
||||||
self.dirty = true;
|
|
||||||
}
|
|
||||||
for m in &mutations.edits {
|
|
||||||
match m {
|
|
||||||
dioxus_core::Mutation::ReplaceWith { id, .. } => remove_children(
|
|
||||||
&mut [&mut self.last_focused_id],
|
|
||||||
rdom,
|
|
||||||
rdom.element_to_node_id(*id),
|
|
||||||
),
|
|
||||||
dioxus_core::Mutation::Remove { id } => remove_children(
|
|
||||||
&mut [&mut self.last_focused_id],
|
|
||||||
rdom,
|
|
||||||
rdom.element_to_node_id(*id),
|
|
||||||
),
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn set_focus(&mut self, rdom: &mut RealDom, id: NodeId) {
|
pub(crate) fn set_focus(&mut self, rdom: &mut RealDom, id: NodeId) {
|
||||||
if let Some(old) = self.last_focused_id.replace(id) {
|
if let Some(old) = self.last_focused_id.replace(id) {
|
||||||
let mut node = rdom.get_mut_raw(old).unwrap();
|
let mut focused = rdom.get_state_mut_raw::<Focused>(old).unwrap();
|
||||||
node.get_mut::<Focused>().unwrap().0 = false;
|
*focused = Focused(false);
|
||||||
}
|
}
|
||||||
let mut node = rdom.get_mut_raw(id).unwrap();
|
let mut focused = rdom.get_state_mut_raw::<Focused>(id).unwrap();
|
||||||
node.insert(Focused(true));
|
*focused = Focused(true);
|
||||||
|
let mut node = rdom.get(id).unwrap();
|
||||||
self.focus_level = node.get::<Focus>().unwrap().level;
|
self.focus_level = node.get::<Focus>().unwrap().level;
|
||||||
// reset the position to the currently focused element
|
// reset the position to the currently focused element
|
||||||
while self.focus_iter.next(rdom).id() != id {}
|
while self.focus_iter.next(rdom).id() != id {}
|
||||||
|
|||||||
+83
-89
@@ -1,7 +1,6 @@
|
|||||||
use crossterm::event::{
|
use crossterm::event::{
|
||||||
Event as TermEvent, KeyCode as TermKeyCode, KeyModifiers, MouseButton, MouseEventKind,
|
Event as TermEvent, KeyCode as TermKeyCode, KeyModifiers, MouseButton, MouseEventKind,
|
||||||
};
|
};
|
||||||
use dioxus_core::*;
|
|
||||||
use dioxus_native_core::real_dom::NodeImmutable;
|
use dioxus_native_core::real_dom::NodeImmutable;
|
||||||
use dioxus_native_core::{NodeId, NodeRef, RealDom};
|
use dioxus_native_core::{NodeId, NodeRef, RealDom};
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
@@ -13,9 +12,8 @@ use dioxus_html::geometry::{
|
|||||||
use dioxus_html::input_data::keyboard_types::{Code, Key, Location, Modifiers};
|
use dioxus_html::input_data::keyboard_types::{Code, Key, Location, Modifiers};
|
||||||
use dioxus_html::input_data::MouseButtonSet as DioxusMouseButtons;
|
use dioxus_html::input_data::MouseButtonSet as DioxusMouseButtons;
|
||||||
use dioxus_html::input_data::{MouseButton as DioxusMouseButton, MouseButtonSet};
|
use dioxus_html::input_data::{MouseButton as DioxusMouseButton, MouseButtonSet};
|
||||||
use dioxus_html::{event_bubbles, FocusData, KeyboardData, MouseData, WheelData};
|
use dioxus_html::{event_bubbles, EventData, FocusData, KeyboardData, MouseData, WheelData};
|
||||||
use std::{
|
use std::{
|
||||||
any::Any,
|
|
||||||
cell::{RefCell, RefMut},
|
cell::{RefCell, RefMut},
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
@@ -28,9 +26,9 @@ use crate::layout::TaffyLayout;
|
|||||||
use crate::{layout_to_screen_space, FocusState};
|
use crate::{layout_to_screen_space, FocusState};
|
||||||
|
|
||||||
pub(crate) struct Event {
|
pub(crate) struct Event {
|
||||||
pub id: ElementId,
|
pub id: NodeId,
|
||||||
pub name: &'static str,
|
pub name: &'static str,
|
||||||
pub data: Rc<dyn Any>,
|
pub data: Rc<EventData>,
|
||||||
pub bubbles: bool,
|
pub bubbles: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,24 +69,6 @@ pub(crate) struct Event {
|
|||||||
|
|
||||||
type EventCore = (&'static str, EventData);
|
type EventCore = (&'static str, EventData);
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum EventData {
|
|
||||||
Mouse(MouseData),
|
|
||||||
Wheel(WheelData),
|
|
||||||
Screen((u16, u16)),
|
|
||||||
Keyboard(KeyboardData),
|
|
||||||
}
|
|
||||||
impl EventData {
|
|
||||||
fn into_any(self) -> Rc<dyn Any + Send + Sync> {
|
|
||||||
match self {
|
|
||||||
Self::Mouse(m) => Rc::new(m),
|
|
||||||
Self::Wheel(w) => Rc::new(w),
|
|
||||||
Self::Screen(s) => Rc::new(s),
|
|
||||||
Self::Keyboard(k) => Rc::new(k),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const MAX_REPEAT_TIME: Duration = Duration::from_millis(100);
|
const MAX_REPEAT_TIME: Duration = Duration::from_millis(100);
|
||||||
|
|
||||||
pub struct InnerInputState {
|
pub struct InnerInputState {
|
||||||
@@ -101,14 +81,14 @@ pub struct InnerInputState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl InnerInputState {
|
impl InnerInputState {
|
||||||
fn new() -> Self {
|
fn create(rdom: &mut RealDom) -> Self {
|
||||||
Self {
|
Self {
|
||||||
mouse: None,
|
mouse: None,
|
||||||
wheel: None,
|
wheel: None,
|
||||||
last_key_pressed: None,
|
last_key_pressed: None,
|
||||||
screen: None,
|
screen: None,
|
||||||
// subscribers: Vec::new(),
|
// subscribers: Vec::new(),
|
||||||
focus_state: FocusState::default(),
|
focus_state: FocusState::create(rdom),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,7 +129,6 @@ impl InnerInputState {
|
|||||||
*m = new_mouse_data;
|
*m = new_mouse_data;
|
||||||
}
|
}
|
||||||
EventData::Wheel(ref w) => self.wheel = Some(w.clone()),
|
EventData::Wheel(ref w) => self.wheel = Some(w.clone()),
|
||||||
EventData::Screen(ref s) => self.screen = Some(*s),
|
|
||||||
EventData::Keyboard(ref mut k) => {
|
EventData::Keyboard(ref mut k) => {
|
||||||
let is_repeating = self
|
let is_repeating = self
|
||||||
.last_key_pressed
|
.last_key_pressed
|
||||||
@@ -166,6 +145,7 @@ impl InnerInputState {
|
|||||||
|
|
||||||
self.last_key_pressed = Some((k.clone(), Instant::now()));
|
self.last_key_pressed = Some((k.clone(), Instant::now()));
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,31 +182,27 @@ impl InnerInputState {
|
|||||||
// elements with listeners will always have a element id
|
// elements with listeners will always have a element id
|
||||||
if let Some(id) = self.focus_state.last_focused_id {
|
if let Some(id) = self.focus_state.last_focused_id {
|
||||||
let element = dom.get(id).unwrap();
|
let element = dom.get(id).unwrap();
|
||||||
if let Some(id) = element.node_data().element_id {
|
resolved_events.push(Event {
|
||||||
resolved_events.push(Event {
|
name: "focus",
|
||||||
name: "focus",
|
id,
|
||||||
id,
|
data: Rc::new(EventData::Focus(FocusData {})),
|
||||||
data: Rc::new(FocusData {}),
|
bubbles: event_bubbles("focus"),
|
||||||
bubbles: event_bubbles("focus"),
|
});
|
||||||
});
|
resolved_events.push(Event {
|
||||||
resolved_events.push(Event {
|
name: "focusin",
|
||||||
name: "focusin",
|
id,
|
||||||
id,
|
data: Rc::new(EventData::Focus(FocusData {})),
|
||||||
data: Rc::new(FocusData {}),
|
bubbles: event_bubbles("focusin"),
|
||||||
bubbles: event_bubbles("focusin"),
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if let Some(id) = old_focus {
|
if let Some(id) = old_focus {
|
||||||
let element = dom.get(id).unwrap();
|
let element = dom.get(id).unwrap();
|
||||||
if let Some(id) = element.node_data().element_id {
|
resolved_events.push(Event {
|
||||||
resolved_events.push(Event {
|
name: "focusout",
|
||||||
name: "focusout",
|
id,
|
||||||
id,
|
data: Rc::new(EventData::Focus(FocusData {})),
|
||||||
data: Rc::new(FocusData {}),
|
bubbles: event_bubbles("focusout"),
|
||||||
bubbles: event_bubbles("focusout"),
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,29 +236,27 @@ impl InnerInputState {
|
|||||||
|
|
||||||
fn try_create_event(
|
fn try_create_event(
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
data: Rc<dyn Any>,
|
data: Rc<EventData>,
|
||||||
will_bubble: &mut FxHashSet<NodeId>,
|
will_bubble: &mut FxHashSet<NodeId>,
|
||||||
resolved_events: &mut Vec<Event>,
|
resolved_events: &mut Vec<Event>,
|
||||||
node: NodeRef,
|
node: NodeRef,
|
||||||
dom: &RealDom,
|
dom: &RealDom,
|
||||||
) {
|
) {
|
||||||
// only trigger event if the event was not triggered already by a child
|
// only trigger event if the event was not triggered already by a child
|
||||||
let id = node.node_data().node_id;
|
let id = node.id();
|
||||||
if will_bubble.insert(id) {
|
if will_bubble.insert(id) {
|
||||||
let mut parent = Some(node);
|
let mut parent = Some(node);
|
||||||
while let Some(current_parent) = parent {
|
while let Some(current_parent) = parent {
|
||||||
let parent_id = current_parent.node_data().node_id;
|
let parent_id = current_parent.id();
|
||||||
will_bubble.insert(parent_id);
|
will_bubble.insert(parent_id);
|
||||||
parent = current_parent.parent_id().and_then(|id| dom.get(id));
|
parent = current_parent.parent_id().and_then(|id| dom.get(id));
|
||||||
}
|
}
|
||||||
if let Some(id) = node.mounted_id() {
|
resolved_events.push(Event {
|
||||||
resolved_events.push(Event {
|
name,
|
||||||
name,
|
id,
|
||||||
id,
|
data,
|
||||||
data,
|
bubbles: event_bubbles(name),
|
||||||
bubbles: event_bubbles(name),
|
})
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,7 +320,10 @@ impl InnerInputState {
|
|||||||
if currently_contains && previously_contained {
|
if currently_contains && previously_contained {
|
||||||
try_create_event(
|
try_create_event(
|
||||||
"mousemove",
|
"mousemove",
|
||||||
Rc::new(prepare_mouse_data(mouse_data, &node_layout)),
|
Rc::new(EventData::Mouse(prepare_mouse_data(
|
||||||
|
mouse_data,
|
||||||
|
&node_layout,
|
||||||
|
))),
|
||||||
&mut will_bubble,
|
&mut will_bubble,
|
||||||
resolved_events,
|
resolved_events,
|
||||||
node,
|
node,
|
||||||
@@ -370,7 +347,7 @@ impl InnerInputState {
|
|||||||
if currently_contains && !previously_contained {
|
if currently_contains && !previously_contained {
|
||||||
try_create_event(
|
try_create_event(
|
||||||
"mouseenter",
|
"mouseenter",
|
||||||
Rc::new(mouse_data.clone()),
|
Rc::new(dioxus_html::EventData::Mouse(mouse_data.clone())),
|
||||||
&mut will_bubble,
|
&mut will_bubble,
|
||||||
resolved_events,
|
resolved_events,
|
||||||
node,
|
node,
|
||||||
@@ -393,7 +370,10 @@ impl InnerInputState {
|
|||||||
if currently_contains && !previously_contained {
|
if currently_contains && !previously_contained {
|
||||||
try_create_event(
|
try_create_event(
|
||||||
"mouseover",
|
"mouseover",
|
||||||
Rc::new(prepare_mouse_data(mouse_data, &node_layout)),
|
Rc::new(EventData::Mouse(prepare_mouse_data(
|
||||||
|
mouse_data,
|
||||||
|
&node_layout,
|
||||||
|
))),
|
||||||
&mut will_bubble,
|
&mut will_bubble,
|
||||||
resolved_events,
|
resolved_events,
|
||||||
node,
|
node,
|
||||||
@@ -413,7 +393,10 @@ impl InnerInputState {
|
|||||||
if currently_contains {
|
if currently_contains {
|
||||||
try_create_event(
|
try_create_event(
|
||||||
"mousedown",
|
"mousedown",
|
||||||
Rc::new(prepare_mouse_data(mouse_data, &node_layout)),
|
Rc::new(EventData::Mouse(prepare_mouse_data(
|
||||||
|
mouse_data,
|
||||||
|
&node_layout,
|
||||||
|
))),
|
||||||
&mut will_bubble,
|
&mut will_bubble,
|
||||||
resolved_events,
|
resolved_events,
|
||||||
node,
|
node,
|
||||||
@@ -434,7 +417,10 @@ impl InnerInputState {
|
|||||||
if currently_contains {
|
if currently_contains {
|
||||||
try_create_event(
|
try_create_event(
|
||||||
"mouseup",
|
"mouseup",
|
||||||
Rc::new(prepare_mouse_data(mouse_data, &node_layout)),
|
Rc::new(EventData::Mouse(prepare_mouse_data(
|
||||||
|
mouse_data,
|
||||||
|
&node_layout,
|
||||||
|
))),
|
||||||
&mut will_bubble,
|
&mut will_bubble,
|
||||||
resolved_events,
|
resolved_events,
|
||||||
node,
|
node,
|
||||||
@@ -456,7 +442,10 @@ impl InnerInputState {
|
|||||||
if currently_contains {
|
if currently_contains {
|
||||||
try_create_event(
|
try_create_event(
|
||||||
"click",
|
"click",
|
||||||
Rc::new(prepare_mouse_data(mouse_data, &node_layout)),
|
Rc::new(EventData::Mouse(prepare_mouse_data(
|
||||||
|
mouse_data,
|
||||||
|
&node_layout,
|
||||||
|
))),
|
||||||
&mut will_bubble,
|
&mut will_bubble,
|
||||||
resolved_events,
|
resolved_events,
|
||||||
node,
|
node,
|
||||||
@@ -479,7 +468,10 @@ impl InnerInputState {
|
|||||||
if currently_contains {
|
if currently_contains {
|
||||||
try_create_event(
|
try_create_event(
|
||||||
"contextmenu",
|
"contextmenu",
|
||||||
Rc::new(prepare_mouse_data(mouse_data, &node_layout)),
|
Rc::new(EventData::Mouse(prepare_mouse_data(
|
||||||
|
mouse_data,
|
||||||
|
&node_layout,
|
||||||
|
))),
|
||||||
&mut will_bubble,
|
&mut will_bubble,
|
||||||
resolved_events,
|
resolved_events,
|
||||||
node,
|
node,
|
||||||
@@ -503,7 +495,7 @@ impl InnerInputState {
|
|||||||
if currently_contains {
|
if currently_contains {
|
||||||
try_create_event(
|
try_create_event(
|
||||||
"wheel",
|
"wheel",
|
||||||
Rc::new(w.clone()),
|
Rc::new(EventData::Wheel(w.clone())),
|
||||||
&mut will_bubble,
|
&mut will_bubble,
|
||||||
resolved_events,
|
resolved_events,
|
||||||
node,
|
node,
|
||||||
@@ -528,7 +520,10 @@ impl InnerInputState {
|
|||||||
if !currently_contains && previously_contained {
|
if !currently_contains && previously_contained {
|
||||||
try_create_event(
|
try_create_event(
|
||||||
"mouseleave",
|
"mouseleave",
|
||||||
Rc::new(prepare_mouse_data(mouse_data, &node_layout)),
|
Rc::new(EventData::Mouse(prepare_mouse_data(
|
||||||
|
mouse_data,
|
||||||
|
&node_layout,
|
||||||
|
))),
|
||||||
&mut will_bubble,
|
&mut will_bubble,
|
||||||
resolved_events,
|
resolved_events,
|
||||||
node,
|
node,
|
||||||
@@ -551,7 +546,10 @@ impl InnerInputState {
|
|||||||
if !currently_contains && previously_contained {
|
if !currently_contains && previously_contained {
|
||||||
try_create_event(
|
try_create_event(
|
||||||
"mouseout",
|
"mouseout",
|
||||||
Rc::new(prepare_mouse_data(mouse_data, &node_layout)),
|
Rc::new(EventData::Mouse(prepare_mouse_data(
|
||||||
|
mouse_data,
|
||||||
|
&node_layout,
|
||||||
|
))),
|
||||||
&mut will_bubble,
|
&mut will_bubble,
|
||||||
resolved_events,
|
resolved_events,
|
||||||
node,
|
node,
|
||||||
@@ -571,7 +569,7 @@ impl InnerInputState {
|
|||||||
let currently_contains = layout_contains_point(node_layout, new_pos);
|
let currently_contains = layout_contains_point(node_layout, new_pos);
|
||||||
|
|
||||||
if currently_contains && node.get::<Focus>().unwrap().level.focusable() {
|
if currently_contains && node.get::<Focus>().unwrap().level.focusable() {
|
||||||
focus_id = Some(node.node_data().node_id);
|
focus_id = Some(node.id());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if let Some(id) = focus_id {
|
if let Some(id) = focus_id {
|
||||||
@@ -612,7 +610,9 @@ pub struct RinkInputHandler {
|
|||||||
impl RinkInputHandler {
|
impl RinkInputHandler {
|
||||||
/// global context that handles events
|
/// global context that handles events
|
||||||
/// limitations: GUI key modifier is never detected, key up events are not detected, and only two mouse buttons may be pressed at once
|
/// limitations: GUI key modifier is never detected, key up events are not detected, and only two mouse buttons may be pressed at once
|
||||||
pub fn new() -> (
|
pub fn craete(
|
||||||
|
rdom: &mut RealDom,
|
||||||
|
) -> (
|
||||||
Self,
|
Self,
|
||||||
Rc<RefCell<InnerInputState>>,
|
Rc<RefCell<InnerInputState>>,
|
||||||
impl FnMut(crossterm::event::Event),
|
impl FnMut(crossterm::event::Event),
|
||||||
@@ -628,7 +628,7 @@ impl RinkInputHandler {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let state = Rc::new(RefCell::new(InnerInputState::new()));
|
let state = Rc::new(RefCell::new(InnerInputState::create(rdom)));
|
||||||
|
|
||||||
(
|
(
|
||||||
Self {
|
Self {
|
||||||
@@ -640,10 +640,6 @@ impl RinkInputHandler {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn prune(&self, mutations: &dioxus_core::Mutations, rdom: &RealDom) {
|
|
||||||
self.state.borrow_mut().focus_state.prune(mutations, rdom);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn get_events(&self, layout: &Taffy, dom: &mut RealDom) -> Vec<Event> {
|
pub(crate) fn get_events(&self, layout: &Taffy, dom: &mut RealDom) -> Vec<Event> {
|
||||||
let mut resolved_events = Vec::new();
|
let mut resolved_events = Vec::new();
|
||||||
|
|
||||||
@@ -675,14 +671,14 @@ impl RinkInputHandler {
|
|||||||
]
|
]
|
||||||
.contains(&e.0)
|
.contains(&e.0)
|
||||||
})
|
})
|
||||||
.map(|evt| (evt.0, evt.1.into_any()));
|
.map(|evt| (evt.0, evt.1));
|
||||||
|
|
||||||
let mut hm: FxHashMap<&'static str, Vec<Rc<dyn Any + Send + Sync>>> = FxHashMap::default();
|
let mut hm: FxHashMap<&'static str, Vec<Rc<EventData>>> = FxHashMap::default();
|
||||||
for (event, data) in events {
|
for (event, data) in events {
|
||||||
if let Some(v) = hm.get_mut(event) {
|
if let Some(v) = hm.get_mut(event) {
|
||||||
v.push(data);
|
v.push(Rc::new(data));
|
||||||
} else {
|
} else {
|
||||||
hm.insert(event, vec![data]);
|
hm.insert(event, vec![Rc::new(data)]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (event, datas) in hm {
|
for (event, datas) in hm {
|
||||||
@@ -690,14 +686,12 @@ impl RinkInputHandler {
|
|||||||
for data in &datas {
|
for data in &datas {
|
||||||
let focused = node.get::<Focused>();
|
let focused = node.get::<Focused>();
|
||||||
if focused.is_some() && focused.unwrap().0 {
|
if focused.is_some() && focused.unwrap().0 {
|
||||||
if let Some(id) = node.mounted_id() {
|
resolved_events.push(Event {
|
||||||
resolved_events.push(Event {
|
name: event,
|
||||||
name: event,
|
id: node.id(),
|
||||||
id,
|
data: data.clone(),
|
||||||
data: data.clone(),
|
bubbles: event_bubbles(event),
|
||||||
bubbles: event_bubbles(event),
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -779,7 +773,7 @@ fn get_event(evt: TermEvent) -> Option<(&'static str, EventData)> {
|
|||||||
MouseEventKind::ScrollUp => ("wheel", get_wheel_data(true)),
|
MouseEventKind::ScrollUp => ("wheel", get_wheel_data(true)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TermEvent::Resize(x, y) => ("resize", EventData::Screen((x, y))),
|
_ => return None,
|
||||||
};
|
};
|
||||||
|
|
||||||
Some((name, data))
|
Some((name, data))
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ impl Pass for TaffyLayout {
|
|||||||
type ParentDependencies = ();
|
type ParentDependencies = ();
|
||||||
type NodeDependencies = ();
|
type NodeDependencies = ();
|
||||||
|
|
||||||
const NODE_MASK: NodeMaskBuilder = NodeMaskBuilder::new()
|
const NODE_MASK: NodeMaskBuilder<'static> = NodeMaskBuilder::new()
|
||||||
.with_attrs(AttributeMaskBuilder::Some(SORTED_LAYOUT_ATTRS))
|
.with_attrs(AttributeMaskBuilder::Some(SORTED_LAYOUT_ATTRS))
|
||||||
.with_text();
|
.with_text();
|
||||||
|
|
||||||
|
|||||||
+58
-97
@@ -6,24 +6,17 @@ use crossterm::{
|
|||||||
execute,
|
execute,
|
||||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||||
};
|
};
|
||||||
use dioxus_core::*;
|
use dioxus_html::EventData;
|
||||||
use dioxus_native_core::{node_ref::NodeMaskBuilder, real_dom::NodeImmutable, Pass};
|
use dioxus_native_core::{node_ref::NodeMaskBuilder, real_dom::NodeImmutable, Pass, Renderer};
|
||||||
use dioxus_native_core::{real_dom::RealDom, FxDashSet, NodeId, SendAnyMap};
|
use dioxus_native_core::{real_dom::RealDom, FxDashSet, NodeId, SendAnyMap};
|
||||||
use focus::FocusState;
|
use focus::FocusState;
|
||||||
use futures::{
|
use futures::{channel::mpsc::UnboundedSender, pin_mut, StreamExt};
|
||||||
channel::mpsc::{UnboundedReceiver, UnboundedSender},
|
|
||||||
pin_mut, StreamExt,
|
|
||||||
};
|
|
||||||
use futures_channel::mpsc::unbounded;
|
use futures_channel::mpsc::unbounded;
|
||||||
use layout::TaffyLayout;
|
use layout::TaffyLayout;
|
||||||
use prevent_default::PreventDefault;
|
use prevent_default::PreventDefault;
|
||||||
use query::Query;
|
use std::sync::{Arc, Mutex};
|
||||||
use std::rc::Rc;
|
|
||||||
use std::{
|
|
||||||
cell::RefCell,
|
|
||||||
sync::{Arc, Mutex},
|
|
||||||
};
|
|
||||||
use std::{io, time::Duration};
|
use std::{io, time::Duration};
|
||||||
|
use std::{rc::Rc, sync::RwLock};
|
||||||
use style_attributes::StyleModifier;
|
use style_attributes::StyleModifier;
|
||||||
use taffy::Taffy;
|
use taffy::Taffy;
|
||||||
pub use taffy::{geometry::Point, prelude::*};
|
pub use taffy::{geometry::Point, prelude::*};
|
||||||
@@ -41,7 +34,7 @@ mod render;
|
|||||||
mod style;
|
mod style;
|
||||||
mod style_attributes;
|
mod style_attributes;
|
||||||
mod widget;
|
mod widget;
|
||||||
mod widgets;
|
// mod widgets;
|
||||||
|
|
||||||
pub use config::*;
|
pub use config::*;
|
||||||
pub use hooks::*;
|
pub use hooks::*;
|
||||||
@@ -75,21 +68,21 @@ impl TuiContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn launch(app: Component<()>) {
|
pub fn render<R: Renderer<(), Rc<EventData>>>(
|
||||||
launch_cfg(app, Config::default())
|
cfg: Config,
|
||||||
}
|
f: impl FnOnce(&Arc<RwLock<RealDom>>, &Arc<Mutex<Taffy>>, UnboundedSender<InputEvent>) -> R,
|
||||||
|
) -> Result<()> {
|
||||||
|
let mut rdom = RealDom::new(Box::new([
|
||||||
|
TaffyLayout::to_type_erased(),
|
||||||
|
Focus::to_type_erased(),
|
||||||
|
StyleModifier::to_type_erased(),
|
||||||
|
PreventDefault::to_type_erased(),
|
||||||
|
]));
|
||||||
|
|
||||||
pub fn launch_cfg(app: Component<()>, cfg: Config) {
|
let (handler, state, mut register_event) = RinkInputHandler::craete(&mut rdom);
|
||||||
launch_cfg_with_props(app, (), cfg);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn launch_cfg_with_props<Props: 'static>(app: Component<Props>, props: Props, cfg: Config) {
|
|
||||||
let mut dom = VirtualDom::new_with_props(app, props);
|
|
||||||
|
|
||||||
let (handler, state, register_event) = RinkInputHandler::new();
|
|
||||||
|
|
||||||
// Setup input handling
|
// Setup input handling
|
||||||
let (event_tx, event_rx) = unbounded();
|
let (event_tx, mut event_reciever) = unbounded();
|
||||||
let event_tx_clone = event_tx.clone();
|
let event_tx_clone = event_tx.clone();
|
||||||
if !cfg.headless {
|
if !cfg.headless {
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
@@ -105,51 +98,19 @@ pub fn launch_cfg_with_props<Props: 'static>(app: Component<Props>, props: Props
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let cx = dom.base_scope();
|
let rdom = Arc::new(RwLock::new(rdom));
|
||||||
let rdom = Rc::new(RefCell::new(RealDom::new(Box::new([
|
|
||||||
TaffyLayout::to_type_erased(),
|
|
||||||
Focus::to_type_erased(),
|
|
||||||
StyleModifier::to_type_erased(),
|
|
||||||
PreventDefault::to_type_erased(),
|
|
||||||
]))));
|
|
||||||
let taffy = Arc::new(Mutex::new(Taffy::new()));
|
let taffy = Arc::new(Mutex::new(Taffy::new()));
|
||||||
cx.provide_context(state);
|
let mut renderer = f(&rdom, &taffy, event_tx_clone);
|
||||||
cx.provide_context(TuiContext { tx: event_tx_clone });
|
|
||||||
cx.provide_context(Query {
|
|
||||||
rdom: rdom.clone(),
|
|
||||||
stretch: taffy.clone(),
|
|
||||||
});
|
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut rdom = rdom.borrow_mut();
|
let mut rdom = rdom.write().unwrap();
|
||||||
let mutations = dom.rebuild();
|
let root_id = rdom.root_id();
|
||||||
rdom.apply_mutations(mutations);
|
renderer.render(rdom.get_mut(root_id).unwrap());
|
||||||
let mut any_map = SendAnyMap::new();
|
let mut any_map = SendAnyMap::new();
|
||||||
any_map.insert(taffy.clone());
|
any_map.insert(taffy.clone());
|
||||||
let _ = rdom.update_state(any_map, false);
|
let _ = rdom.update_state(any_map, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
render_vdom(
|
|
||||||
&mut dom,
|
|
||||||
event_rx,
|
|
||||||
handler,
|
|
||||||
cfg,
|
|
||||||
rdom,
|
|
||||||
taffy,
|
|
||||||
register_event,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_vdom(
|
|
||||||
vdom: &mut VirtualDom,
|
|
||||||
mut event_reciever: UnboundedReceiver<InputEvent>,
|
|
||||||
handler: RinkInputHandler,
|
|
||||||
cfg: Config,
|
|
||||||
rdom: Rc<RefCell<RealDom>>,
|
|
||||||
taffy: Arc<Mutex<Taffy>>,
|
|
||||||
mut register_event: impl FnMut(crossterm::event::Event),
|
|
||||||
) -> Result<()> {
|
|
||||||
tokio::runtime::Builder::new_current_thread()
|
tokio::runtime::Builder::new_current_thread()
|
||||||
.enable_all()
|
.enable_all()
|
||||||
.build()?
|
.build()?
|
||||||
@@ -225,16 +186,16 @@ fn render_vdom(
|
|||||||
if let Some(terminal) = &mut terminal {
|
if let Some(terminal) = &mut terminal {
|
||||||
execute!(terminal.backend_mut(), SavePosition).unwrap();
|
execute!(terminal.backend_mut(), SavePosition).unwrap();
|
||||||
terminal.draw(|frame| {
|
terminal.draw(|frame| {
|
||||||
let rdom = rdom.borrow();
|
let rdom = rdom.write().unwrap();
|
||||||
let mut taffy = taffy.lock().expect("taffy lock poisoned");
|
let mut taffy = taffy.lock().expect("taffy lock poisoned");
|
||||||
// size is guaranteed to not change when rendering
|
// size is guaranteed to not change when rendering
|
||||||
resize(frame.size(), &mut taffy, &rdom);
|
resize(frame.size(), &mut taffy, &rdom);
|
||||||
let root = rdom.get(NodeId(0)).unwrap();
|
let root = rdom.get(rdom.root_id()).unwrap();
|
||||||
render::render_vnode(frame, &taffy, root, cfg, Point::ZERO);
|
render::render_vnode(frame, &taffy, root, cfg, Point::ZERO);
|
||||||
})?;
|
})?;
|
||||||
execute!(terminal.backend_mut(), RestorePosition, Show).unwrap();
|
execute!(terminal.backend_mut(), RestorePosition, Show).unwrap();
|
||||||
} else {
|
} else {
|
||||||
let rdom = rdom.borrow();
|
let rdom = rdom.write().unwrap();
|
||||||
resize(
|
resize(
|
||||||
Rect {
|
Rect {
|
||||||
x: 0,
|
x: 0,
|
||||||
@@ -248,13 +209,13 @@ fn render_vdom(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut hot_reload_msg = None;
|
// let mut hot_reload_msg = None;
|
||||||
{
|
{
|
||||||
let wait = vdom.wait_for_work();
|
let wait = renderer.poll_async();
|
||||||
#[cfg(all(feature = "hot-reload", debug_assertions))]
|
// #[cfg(all(feature = "hot-reload", debug_assertions))]
|
||||||
let hot_reload_wait = hot_reload_rx.recv();
|
// let hot_reload_wait = hot_reload_rx.recv();
|
||||||
#[cfg(not(all(feature = "hot-reload", debug_assertions)))]
|
// #[cfg(not(all(feature = "hot-reload", debug_assertions)))]
|
||||||
let hot_reload_wait = std::future::pending();
|
// let hot_reload_wait = std::future::pending();
|
||||||
|
|
||||||
pin_mut!(wait);
|
pin_mut!(wait);
|
||||||
|
|
||||||
@@ -283,40 +244,40 @@ fn render_vdom(
|
|||||||
register_event(evt);
|
register_event(evt);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Some(msg) = hot_reload_wait => {
|
// Some(msg) = hot_reload_wait => {
|
||||||
hot_reload_msg = Some(msg);
|
// hot_reload_msg = Some(msg);
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we have a new template, replace the old one
|
// // if we have a new template, replace the old one
|
||||||
if let Some(msg) = hot_reload_msg {
|
// if let Some(msg) = hot_reload_msg {
|
||||||
match msg {
|
// match msg {
|
||||||
dioxus_hot_reload::HotReloadMsg::UpdateTemplate(template) => {
|
// dioxus_hot_reload::HotReloadMsg::UpdateTemplate(template) => {
|
||||||
vdom.replace_template(template);
|
// vdom.replace_template(template);
|
||||||
}
|
// }
|
||||||
dioxus_hot_reload::HotReloadMsg::Shutdown => {
|
// dioxus_hot_reload::HotReloadMsg::Shutdown => {
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
{
|
{
|
||||||
let evts = {
|
|
||||||
let mut rdom = rdom.borrow_mut();
|
|
||||||
handler.get_events(&taffy.lock().expect("taffy lock poisoned"), &mut rdom)
|
|
||||||
};
|
|
||||||
{
|
{
|
||||||
|
let mut rdom = rdom.write().unwrap();
|
||||||
|
let evts = handler
|
||||||
|
.get_events(&taffy.lock().expect("taffy lock poisoned"), &mut rdom);
|
||||||
updated |= handler.state().focus_state.clean();
|
updated |= handler.state().focus_state.clean();
|
||||||
|
|
||||||
|
for e in evts {
|
||||||
|
let node = rdom.get_mut(e.id).unwrap();
|
||||||
|
renderer.handle_event(node, e.name, e.data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for e in evts {
|
let mut rdom = rdom.write().unwrap();
|
||||||
vdom.handle_event(e.name, e.data, e.id, e.bubbles)
|
|
||||||
}
|
|
||||||
let mut rdom = rdom.borrow_mut();
|
|
||||||
let mutations = vdom.render_immediate();
|
|
||||||
handler.prune(&mutations, &rdom);
|
|
||||||
// updates the dom's nodes
|
// updates the dom's nodes
|
||||||
rdom.apply_mutations(mutations);
|
let root_id = rdom.root_id();
|
||||||
|
renderer.render(rdom.get_mut(root_id).unwrap());
|
||||||
// update the style and layout
|
// update the style and layout
|
||||||
let mut any_map = SendAnyMap::new();
|
let mut any_map = SendAnyMap::new();
|
||||||
any_map.insert(taffy.clone());
|
any_map.insert(taffy.clone());
|
||||||
@@ -346,7 +307,7 @@ fn render_vdom(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum InputEvent {
|
pub enum InputEvent {
|
||||||
UserInput(TermEvent),
|
UserInput(TermEvent),
|
||||||
Close,
|
Close,
|
||||||
}
|
}
|
||||||
@@ -1 +1 @@
|
|||||||
pub use crate::widgets::*;
|
// pub use crate::widgets::*;
|
||||||
@@ -30,7 +30,7 @@ impl Pass for PreventDefault {
|
|||||||
type ChildDependencies = ();
|
type ChildDependencies = ();
|
||||||
type NodeDependencies = ();
|
type NodeDependencies = ();
|
||||||
|
|
||||||
const NODE_MASK: dioxus_native_core::node_ref::NodeMaskBuilder =
|
const NODE_MASK: dioxus_native_core::node_ref::NodeMaskBuilder<'static> =
|
||||||
dioxus_native_core::node_ref::NodeMaskBuilder::new()
|
dioxus_native_core::node_ref::NodeMaskBuilder::new()
|
||||||
.with_attrs(dioxus_native_core::node_ref::AttributeMaskBuilder::Some(&[
|
.with_attrs(dioxus_native_core::node_ref::AttributeMaskBuilder::Some(&[
|
||||||
"dioxus-prevent-default",
|
"dioxus-prevent-default",
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ use std::{
|
|||||||
sync::{Arc, Mutex, MutexGuard},
|
sync::{Arc, Mutex, MutexGuard},
|
||||||
};
|
};
|
||||||
|
|
||||||
use dioxus_core::ElementId;
|
use dioxus_native_core::{real_dom::NodeImmutable, NodeId, RealDom};
|
||||||
use dioxus_native_core::{real_dom::NodeImmutable, RealDom};
|
|
||||||
use taffy::{
|
use taffy::{
|
||||||
geometry::Point,
|
geometry::Point,
|
||||||
prelude::{Layout, Size},
|
prelude::{Layout, Size},
|
||||||
@@ -52,7 +51,7 @@ pub struct Query {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Query {
|
impl Query {
|
||||||
pub fn get(&self, id: ElementId) -> ElementRef {
|
pub fn get(&self, id: NodeId) -> ElementRef {
|
||||||
ElementRef::new(
|
ElementRef::new(
|
||||||
self.rdom.borrow(),
|
self.rdom.borrow(),
|
||||||
self.stretch.lock().expect("taffy lock poisoned"),
|
self.stretch.lock().expect("taffy lock poisoned"),
|
||||||
@@ -64,11 +63,11 @@ impl Query {
|
|||||||
pub struct ElementRef<'a> {
|
pub struct ElementRef<'a> {
|
||||||
inner: Ref<'a, RealDom>,
|
inner: Ref<'a, RealDom>,
|
||||||
stretch: MutexGuard<'a, Taffy>,
|
stretch: MutexGuard<'a, Taffy>,
|
||||||
id: ElementId,
|
id: NodeId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ElementRef<'a> {
|
impl<'a> ElementRef<'a> {
|
||||||
fn new(inner: Ref<'a, RealDom>, stretch: MutexGuard<'a, Taffy>, id: ElementId) -> Self {
|
fn new(inner: Ref<'a, RealDom>, stretch: MutexGuard<'a, Taffy>, id: NodeId) -> Self {
|
||||||
Self { inner, stretch, id }
|
Self { inner, stretch, id }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ impl Pass for StyleModifier {
|
|||||||
type NodeDependencies = ();
|
type NodeDependencies = ();
|
||||||
|
|
||||||
// todo: seperate each attribute into it's own class
|
// todo: seperate each attribute into it's own class
|
||||||
const NODE_MASK: NodeMaskBuilder = NodeMaskBuilder::new()
|
const NODE_MASK: NodeMaskBuilder<'static> = NodeMaskBuilder::new()
|
||||||
.with_attrs(AttributeMaskBuilder::Some(SORTED_STYLE_ATTRS))
|
.with_attrs(AttributeMaskBuilder::Some(SORTED_STYLE_ATTRS))
|
||||||
.with_element();
|
.with_element();
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ pub(crate) fn Button<'a>(cx: Scope<'a, ButtonProps>) -> Element<'a> {
|
|||||||
}
|
}
|
||||||
state.set(new_state);
|
state.set(new_state);
|
||||||
};
|
};
|
||||||
cx.render(rsx! {
|
render! {
|
||||||
div{
|
div{
|
||||||
width: "{width}",
|
width: "{width}",
|
||||||
height: "{height}",
|
height: "{height}",
|
||||||
@@ -55,5 +55,5 @@ pub(crate) fn Button<'a>(cx: Scope<'a, ButtonProps>) -> Element<'a> {
|
|||||||
},
|
},
|
||||||
"{text}"
|
"{text}"
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
@@ -61,7 +61,7 @@ pub(crate) fn CheckBox<'a>(cx: Scope<'a, CheckBoxProps>) -> Element<'a> {
|
|||||||
}
|
}
|
||||||
state.set(new_state);
|
state.set(new_state);
|
||||||
};
|
};
|
||||||
cx.render(rsx! {
|
render! {
|
||||||
div {
|
div {
|
||||||
width: "{width}",
|
width: "{width}",
|
||||||
height: "{height}",
|
height: "{height}",
|
||||||
@@ -78,5 +78,5 @@ pub(crate) fn CheckBox<'a>(cx: Scope<'a, CheckBoxProps>) -> Element<'a> {
|
|||||||
},
|
},
|
||||||
"{text}"
|
"{text}"
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
@@ -99,7 +99,7 @@ pub(crate) fn NumbericInput<'a>(cx: Scope<'a, NumbericInputProps>) -> Element<'a
|
|||||||
update(text.clone());
|
update(text.clone());
|
||||||
};
|
};
|
||||||
|
|
||||||
cx.render(rsx! {
|
render! {
|
||||||
div{
|
div{
|
||||||
width: "{width}",
|
width: "{width}",
|
||||||
height: "{height}",
|
height: "{height}",
|
||||||
@@ -205,5 +205,5 @@ pub(crate) fn NumbericInput<'a>(cx: Scope<'a, NumbericInputProps>) -> Element<'a
|
|||||||
|
|
||||||
"{text_after_second_cursor}"
|
"{text_after_second_cursor}"
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
@@ -114,7 +114,7 @@ pub(crate) fn Password<'a>(cx: Scope<'a, PasswordProps>) -> Element<'a> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
cx.render(rsx! {
|
render! {
|
||||||
div {
|
div {
|
||||||
width: "{width}",
|
width: "{width}",
|
||||||
height: "{height}",
|
height: "{height}",
|
||||||
@@ -187,5 +187,5 @@ pub(crate) fn Password<'a>(cx: Scope<'a, PasswordProps>) -> Element<'a> {
|
|||||||
|
|
||||||
"{text_after_second_cursor}"
|
"{text_after_second_cursor}"
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
@@ -62,7 +62,7 @@ pub(crate) fn Slider<'a>(cx: Scope<'a, SliderProps>) -> Element<'a> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
cx.render(rsx! {
|
render! {
|
||||||
div{
|
div{
|
||||||
width: "{width}",
|
width: "{width}",
|
||||||
height: "{height}",
|
height: "{height}",
|
||||||
@@ -103,5 +103,5 @@ pub(crate) fn Slider<'a>(cx: Scope<'a, SliderProps>) -> Element<'a> {
|
|||||||
background_color: "rgba(10,10,10,0.5)",
|
background_color: "rgba(10,10,10,0.5)",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
@@ -79,7 +79,7 @@ pub(crate) fn TextBox<'a>(cx: Scope<'a, TextBoxProps>) -> Element<'a> {
|
|||||||
"solid"
|
"solid"
|
||||||
};
|
};
|
||||||
|
|
||||||
cx.render(rsx! {
|
render! {
|
||||||
div{
|
div{
|
||||||
width: "{width}",
|
width: "{width}",
|
||||||
height: "{height}",
|
height: "{height}",
|
||||||
@@ -178,5 +178,5 @@ pub(crate) fn TextBox<'a>(cx: Scope<'a, TextBoxProps>) -> Element<'a> {
|
|||||||
|
|
||||||
"{text_after_second_cursor}"
|
"{text_after_second_cursor}"
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user