tests passing, and tui updated

This commit is contained in:
Evan Almloff committed 2022-04-12 18:46:16 -05:00
1 parent 92010b0bab
commit 9eaf7212a3
13 files changed
+450 -305

No files matched your search

+10 -12
View File
@@ -105,8 +105,8 @@ fn impl_derive_macro(ast: &syn::DeriveInput) -> TokenStream {
let gen = quote! { let gen = quote! {
impl State for #type_name{ impl State for #type_name{
fn update_node_dep_state<'a>(&'a mut self, ty: std::any::TypeId, node: Option<&'a dioxus_core::VElement<'a>>, ctx: &anymap::AnyMap) -> bool{ fn update_node_dep_state<'a>(&'a mut self, ty: std::any::TypeId, node: &'a dioxus_core::VNode<'a>, ctx: &anymap::AnyMap) -> bool{
use dioxus_native_core::real_dom_new_api::NodeDepState as _; use dioxus_native_core::state::NodeDepState as _;
// println!("called update_node_dep_state with ty: {:?}", ty); // println!("called update_node_dep_state with ty: {:?}", ty);
if false { if false {
unreachable!(); unreachable!();
@@ -117,8 +117,8 @@ fn impl_derive_macro(ast: &syn::DeriveInput) -> TokenStream {
} }
} }
fn update_parent_dep_state<'a>(&'a mut self, ty: std::any::TypeId, node: Option<&'a dioxus_core::VElement<'a>>, parent: Option<&Self>, ctx: &anymap::AnyMap) -> bool{ fn update_parent_dep_state<'a>(&'a mut self, ty: std::any::TypeId, node: &'a dioxus_core::VNode<'a>, parent: Option<&Self>, ctx: &anymap::AnyMap) -> bool{
use dioxus_native_core::real_dom_new_api::ParentDepState as _; use dioxus_native_core::state::ParentDepState as _;
// println!("called update_parent_dep_state with ty: {:?}", ty); // println!("called update_parent_dep_state with ty: {:?}", ty);
if false { if false {
unreachable!(); unreachable!();
@@ -129,8 +129,8 @@ fn impl_derive_macro(ast: &syn::DeriveInput) -> TokenStream {
} }
} }
fn update_child_dep_state<'a>(&'a mut self, ty: std::any::TypeId, node: Option<&'a dioxus_core::VElement<'a>>, children: &[&Self], ctx: &anymap::AnyMap) -> bool{ fn update_child_dep_state<'a>(&'a mut self, ty: std::any::TypeId, node: &'a dioxus_core::VNode<'a>, children: &[&Self], ctx: &anymap::AnyMap) -> bool{
use dioxus_native_core::real_dom_new_api::ChildDepState as _; use dioxus_native_core::state::ChildDepState as _;
// println!("called update_child_dep_state with ty: {:?}", ty); // println!("called update_child_dep_state with ty: {:?}", ty);
if false { if false {
unreachable!() unreachable!()
@@ -141,7 +141,7 @@ fn impl_derive_macro(ast: &syn::DeriveInput) -> TokenStream {
} }
} }
fn child_dep_types(&self, mask: &dioxus_native_core::real_dom_new_api::NodeMask) -> Vec<std::any::TypeId>{ fn child_dep_types(&self, mask: &dioxus_native_core::state::NodeMask) -> Vec<std::any::TypeId>{
let mut dep_types = Vec::new(); let mut dep_types = Vec::new();
#(if #child_types::NODE_MASK.overlaps(mask) { #(if #child_types::NODE_MASK.overlaps(mask) {
dep_types.push(std::any::TypeId::of::<#child_types>()); dep_types.push(std::any::TypeId::of::<#child_types>());
@@ -149,7 +149,7 @@ fn impl_derive_macro(ast: &syn::DeriveInput) -> TokenStream {
dep_types dep_types
} }
fn parent_dep_types(&self, mask: &dioxus_native_core::real_dom_new_api::NodeMask) -> Vec<std::any::TypeId>{ fn parent_dep_types(&self, mask: &dioxus_native_core::state::NodeMask) -> Vec<std::any::TypeId>{
let mut dep_types = Vec::new(); let mut dep_types = Vec::new();
#(if #parent_types::NODE_MASK.overlaps(mask) { #(if #parent_types::NODE_MASK.overlaps(mask) {
dep_types.push(std::any::TypeId::of::<#parent_types>()); dep_types.push(std::any::TypeId::of::<#parent_types>());
@@ -157,7 +157,7 @@ fn impl_derive_macro(ast: &syn::DeriveInput) -> TokenStream {
dep_types dep_types
} }
fn node_dep_types(&self, mask: &dioxus_native_core::real_dom_new_api::NodeMask) -> Vec<std::any::TypeId>{ fn node_dep_types(&self, mask: &dioxus_native_core::state::NodeMask) -> Vec<std::any::TypeId>{
let mut dep_types = Vec::new(); let mut dep_types = Vec::new();
#(if #node_types::NODE_MASK.overlaps(mask) { #(if #node_types::NODE_MASK.overlaps(mask) {
dep_types.push(std::any::TypeId::of::<#node_types>()); dep_types.push(std::any::TypeId::of::<#node_types>());
@@ -314,7 +314,7 @@ impl<'a> StateMember<'a> {
quote!(self.#ident.reduce(#node_view, #get_ctx)) quote!(self.#ident.reduce(#node_view, #get_ctx))
} }
DepKind::ChildDepState => { DepKind::ChildDepState => {
quote!(self.#ident.reduce(#node_view, children.iter().map(|s| &s.#dep_ident).collect(), #get_ctx)) quote!(self.#ident.reduce(#node_view, children.iter().map(|s| &s.#dep_ident), #get_ctx))
} }
DepKind::ParentDepState => { DepKind::ParentDepState => {
quote!(self.#ident.reduce(#node_view, parent.as_ref().map(|p| &p.#dep_ident), #get_ctx)) quote!(self.#ident.reduce(#node_view, parent.as_ref().map(|p| &p.#dep_ident), #get_ctx))
@@ -337,10 +337,8 @@ impl<'a> StateMember<'a> {
fn type_id(&self) -> quote::__private::TokenStream { fn type_id(&self) -> quote::__private::TokenStream {
let ty = &self.mem.ty; let ty = &self.mem.ty;
// quote!(std::any::TypeId::of::<#ty>())
quote!({ quote!({
let type_id = std::any::TypeId::of::<#ty>(); let type_id = std::any::TypeId::of::<#ty>();
// println!("{:?}", type_id);
type_id type_id
}) })
} }
+1 -1
View File
@@ -1,4 +1,4 @@
pub mod layout_attributes; pub mod layout_attributes;
pub mod real_dom; pub mod real_dom;
pub mod real_dom_new_api; pub mod state;
pub use dioxus_native_core_macro; pub use dioxus_native_core_macro;
+144 -63
View File
@@ -8,7 +8,7 @@ use std::{
use dioxus_core::{ElementId, Mutations, VNode, VirtualDom}; use dioxus_core::{ElementId, Mutations, VNode, VirtualDom};
use crate::real_dom_new_api::{AttributeMask, NodeMask, State}; use crate::state::{union_ordered_iter, AttributeMask, NodeMask, State};
/// A Dom that can sync with the VirtualDom mutations intended for use in lazy renderers. /// A Dom that can sync with the VirtualDom mutations intended for use in lazy renderers.
/// The render state passes from parent to children and or accumulates state from children to parents. /// The render state passes from parent to children and or accumulates state from children to parents.
@@ -166,7 +166,10 @@ impl<S: State> RealDom<S> {
text: new_text, text: new_text,
} => { } => {
let target = &mut self[root as usize]; let target = &mut self[root as usize];
nodes_updated.push((root as usize, NodeMask::NONE)); nodes_updated.push((
root as usize,
NodeMask::new(AttributeMask::NONE, false, false, true),
));
match &mut target.node_type { match &mut target.node_type {
NodeType::Text { text } => { NodeType::Text { text } => {
*text = new_text.to_string(); *text = new_text.to_string();
@@ -177,7 +180,7 @@ impl<S: State> RealDom<S> {
SetAttribute { root, field, .. } => { SetAttribute { root, field, .. } => {
nodes_updated.push(( nodes_updated.push((
root as usize, root as usize,
NodeMask::new(AttributeMask::single(field), false, false), NodeMask::new(AttributeMask::single(field), false, false, false),
)); ));
} }
RemoveAttribute { RemoveAttribute {
@@ -185,7 +188,7 @@ impl<S: State> RealDom<S> {
} => { } => {
nodes_updated.push(( nodes_updated.push((
root as usize, root as usize,
NodeMask::new(AttributeMask::single(field), false, false), NodeMask::new(AttributeMask::single(field), false, false, false),
)); ));
} }
PopRoot {} => { PopRoot {} => {
@@ -210,65 +213,122 @@ impl<S: State> RealDom<S> {
All, All,
Some(Vec<TypeId>), Some(Vec<TypeId>),
} }
impl StatesToCheck {
fn union(&self, other: &Self) -> Self {
match (self, other) {
(Self::Some(s), Self::Some(o)) => Self::Some(union_ordered_iter(
s.iter().copied(),
o.iter().copied(),
s.len() + o.len(),
)),
_ => Self::All,
}
}
}
#[derive(Debug, Clone)]
struct NodeRef {
id: usize,
height: u16,
node_mask: NodeMask,
to_check: StatesToCheck,
}
impl NodeRef {
fn union_with(&mut self, other: &Self) {
self.node_mask = self.node_mask.union(&other.node_mask);
self.to_check = self.to_check.union(&other.to_check);
}
}
impl Eq for NodeRef {}
impl PartialEq for NodeRef {
fn eq(&self, other: &Self) -> bool {
self.id == other.id && self.height == other.height
}
}
impl Ord for NodeRef {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.partial_cmp(other).unwrap()
}
}
impl PartialOrd for NodeRef {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
// Sort nodes first by height, then if the height is the same id.
// The order of the id does not matter it just helps with binary search later
Some(self.height.cmp(&other.height).then(self.id.cmp(&other.id)))
}
}
let mut to_rerender = FxHashSet::default(); let mut to_rerender = FxHashSet::default();
to_rerender.extend(nodes_updated.iter().map(|(id, _)| id)); to_rerender.extend(nodes_updated.iter().map(|(id, _)| id));
let mut nodes_updated: Vec<_> = nodes_updated let mut nodes_updated: Vec<_> = nodes_updated
.into_iter() .into_iter()
.map(|(id, mask)| (id, self[id].height, mask, StatesToCheck::All)) .map(|(id, mask)| NodeRef {
id,
height: self[id].height,
node_mask: mask,
to_check: StatesToCheck::All,
})
.collect(); .collect();
// Sort nodes first by height, then if the height is the same id. nodes_updated.sort();
nodes_updated.sort_by(|fst, snd| fst.1.cmp(&snd.1).then(fst.0.cmp(&snd.0)));
{ // Combine mutations that affect the same node.
// Combine mutations that affect the same node. let mut last_node: Option<NodeRef> = None;
let current_key = None; let mut new_nodes_updated = VecDeque::new();
for i in 0..nodes_updated.len() { for current in nodes_updated.into_iter() {
let current = nodes_updated; if let Some(node) = &mut last_node {
if *node == current {
node.union_with(&current);
} else {
new_nodes_updated.push_back(last_node.replace(current).unwrap());
}
} else {
last_node = Some(current);
} }
} }
println!("{:?}", nodes_updated); if let Some(node) = last_node {
new_nodes_updated.push_back(node);
}
let nodes_updated = new_nodes_updated;
// update the state that only depends on nodes. The order does not matter. // update the state that only depends on nodes. The order does not matter.
for (id, _height, mask, to_check) in &nodes_updated { for node_ref in &nodes_updated {
let mut changed = false; let mut changed = false;
let node = &mut self[*id as usize]; let node = &mut self[node_ref.id];
let ids = match to_check { let ids = match &node_ref.to_check {
StatesToCheck::All => node.state.node_dep_types(&mask), StatesToCheck::All => node.state.node_dep_types(&node_ref.node_mask),
StatesToCheck::Some(_) => unreachable!(), StatesToCheck::Some(_) => unreachable!(),
}; };
for ty in ids { for ty in ids {
let node = &mut self[*id as usize]; let node = &mut self[node_ref.id];
let el = if let &VNode::Element(e) = node.element(vdom) { let vnode = node.element(vdom);
Some(e) changed |= node.state.update_node_dep_state(ty, vnode, &ctx);
} else {
None
};
changed |= node.state.update_node_dep_state(ty, el, &ctx);
} }
if changed { if changed {
to_rerender.insert(*id); to_rerender.insert(node_ref.id);
} }
} }
// bubble up state. To avoid calling reduce more times than nessisary start from the bottom and go up. // bubble up state. To avoid calling reduce more times than nessisary start from the bottom and go up.
let mut to_bubble: VecDeque<_> = nodes_updated.clone().into(); let mut to_bubble = nodes_updated.clone();
while let Some((id, height, mask, to_check)) = to_bubble.pop_back() { while let Some(node_ref) = to_bubble.pop_back() {
let NodeRef {
id,
height,
node_mask,
to_check,
} = node_ref;
let (node, children) = self.get_node_children_mut(id).unwrap(); let (node, children) = self.get_node_children_mut(id).unwrap();
let children_state: Vec<_> = children.iter().map(|c| &c.state).collect(); let children_state: Vec<_> = children.iter().map(|c| &c.state).collect();
let ids = match to_check { let ids = match to_check {
StatesToCheck::All => node.state.child_dep_types(&mask), StatesToCheck::All => node.state.child_dep_types(&node_mask),
StatesToCheck::Some(ids) => ids, StatesToCheck::Some(ids) => ids,
}; };
let mut changed = Vec::new(); let mut changed = Vec::new();
for ty in ids { for ty in ids {
let el = if let &VNode::Element(e) = node.element(vdom) { let vnode = node.element(vdom);
Some(e)
} else {
None
};
if node if node
.state .state
.update_child_dep_state(ty, el, &children_state, &ctx) .update_child_dep_state(ty, vnode, &children_state, &ctx)
{ {
changed.push(ty); changed.push(ty);
} }
@@ -276,19 +336,28 @@ impl<S: State> RealDom<S> {
if let Some(parent_id) = node.parent { if let Some(parent_id) = node.parent {
if !changed.is_empty() { if !changed.is_empty() {
to_rerender.insert(id); to_rerender.insert(id);
let i = to_bubble.partition_point(|(other_id, h, ..)| { let i = to_bubble.partition_point(
*h < height - 1 || (*h == height - 1 && *other_id < parent_id.0) |NodeRef {
}); id: other_id,
height: h,
..
}| {
*h < height - 1 || (*h == height - 1 && *other_id < parent_id.0)
},
);
// make sure the parent is not already queued // make sure the parent is not already queued
if i >= to_bubble.len() || to_bubble[i].0 != parent_id.0 { if i < to_bubble.len() && to_bubble[i].id == parent_id.0 {
to_bubble[i].to_check =
to_bubble[i].to_check.union(&StatesToCheck::Some(changed));
} else {
to_bubble.insert( to_bubble.insert(
i, i,
( NodeRef {
parent_id.0, id: parent_id.0,
height - 1, height: height - 1,
NodeMask::NONE, node_mask: NodeMask::NONE,
StatesToCheck::Some(changed), to_check: StatesToCheck::Some(changed),
), },
); );
} }
} }
@@ -296,26 +365,28 @@ impl<S: State> RealDom<S> {
} }
// push down state. To avoid calling reduce more times than nessisary start from the top and go down. // push down state. To avoid calling reduce more times than nessisary start from the top and go down.
let mut to_push: VecDeque<_> = nodes_updated.clone().into(); let mut to_push = nodes_updated.clone();
while let Some((id, height, mask, to_check)) = to_push.pop_front() { while let Some(node_ref) = to_push.pop_front() {
let NodeRef {
id,
height,
node_mask,
to_check,
} = node_ref;
let node = &self[id]; let node = &self[id];
let ids = match to_check { let ids = match to_check {
StatesToCheck::All => node.state.parent_dep_types(&mask), StatesToCheck::All => node.state.parent_dep_types(&node_mask),
StatesToCheck::Some(ids) => ids, StatesToCheck::Some(ids) => ids,
}; };
let mut changed = Vec::new(); let mut changed = Vec::new();
let (node, parent) = self.get_node_parent_mut(id).unwrap(); let (node, parent) = self.get_node_parent_mut(id).unwrap();
for ty in ids { for ty in ids {
let el = if let &VNode::Element(e) = node.element(vdom) { let vnode = node.element(vdom);
Some(e)
} else {
None
};
let parent = parent.as_deref(); let parent = parent.as_deref();
let state = &mut node.state; let state = &mut node.state;
if state.update_parent_dep_state( if state.update_parent_dep_state(
ty, ty,
el, vnode,
parent.filter(|n| n.id.0 != 0).map(|n| &n.state), parent.filter(|n| n.id.0 != 0).map(|n| &n.state),
&ctx, &ctx,
) { ) {
@@ -328,18 +399,28 @@ impl<S: State> RealDom<S> {
let node = &self[id]; let node = &self[id];
if let NodeType::Element { children, .. } = &node.node_type { if let NodeType::Element { children, .. } = &node.node_type {
for c in children { for c in children {
let i = to_push.partition_point(|(other_id, h, ..)| { let i = to_push.partition_point(
*h < height + 1 || (*h == height + 1 && *other_id < c.0) |NodeRef {
}); id: other_id,
if i >= to_push.len() || to_push[i].0 != c.0 { height: h,
..
}| {
*h < height + 1 || (*h == height + 1 && *other_id < c.0)
},
);
if i < to_push.len() && to_push[i].id == c.0 {
to_push[i].to_check = to_push[i]
.to_check
.union(&StatesToCheck::Some(changed.clone()));
} else {
to_push.insert( to_push.insert(
i, i,
( NodeRef {
c.0, id: c.0,
height + 1, height: height + 1,
NodeMask::NONE, node_mask: NodeMask::NONE,
StatesToCheck::Some(changed.clone()), to_check: StatesToCheck::Some(changed.clone()),
), },
); );
} }
} }
@@ -1,43 +1,96 @@
use std::any::TypeId; use std::{any::TypeId, fmt::Debug};
use anymap::AnyMap; use anymap::AnyMap;
use dioxus_core::{Attribute, VElement}; use dioxus_core::{Attribute, ElementId, VElement, VNode, VText};
pub(crate) fn union_ordered_iter<T: Ord + Debug>(
s_iter: impl Iterator<Item = T>,
o_iter: impl Iterator<Item = T>,
new_len_guess: usize,
) -> Vec<T> {
let mut s_peekable = s_iter.peekable();
let mut o_peekable = o_iter.peekable();
let mut v = Vec::with_capacity(new_len_guess);
while let Some(s_i) = s_peekable.peek() {
loop {
if let Some(o_i) = o_peekable.peek() {
if o_i > s_i {
break;
} else if o_i < s_i {
v.push(o_peekable.next().unwrap());
}
} else {
break;
}
}
v.push(s_peekable.next().unwrap());
}
while let Some(o_i) = o_peekable.next() {
v.push(o_i);
}
for w in v.windows(2) {
debug_assert!(w[1] > w[0]);
}
v
}
#[derive(Debug)] #[derive(Debug)]
pub struct NodeView<'a> { pub struct NodeView<'a> {
inner: Option<&'a VElement<'a>>, inner: &'a VNode<'a>,
view: NodeMask, mask: NodeMask,
} }
impl<'a> NodeView<'a> { impl<'a> NodeView<'a> {
pub fn new(velement: Option<&'a VElement<'a>>, view: NodeMask) -> Self { pub fn new(vnode: &'a VNode<'a>, view: NodeMask) -> Self {
Self { Self {
inner: velement, inner: vnode,
view: view, mask: view,
} }
} }
pub fn id(&self) -> ElementId {
self.inner.mounted_id()
}
pub fn tag(&self) -> Option<&'a str> { pub fn tag(&self) -> Option<&'a str> {
if self.view.tag { self.mask.tag.then(|| self.el().map(|el| el.tag)).flatten()
self.inner.map(|el| el.tag)
} else {
None
}
} }
pub fn namespace(&self) -> Option<&'a str> { pub fn namespace(&self) -> Option<&'a str> {
if self.view.namespace { self.mask
self.inner.map(|el| el.namespace).flatten() .namespace
.then(|| self.el().map(|el| el.namespace).flatten())
.flatten()
}
pub fn attributes(&self) -> impl Iterator<Item = &Attribute<'a>> {
self.el()
.map(|el| el.attributes)
.unwrap_or_default()
.iter()
.filter(|a| self.mask.attritutes.contains_attribute(&a.name))
}
pub fn text(&self) -> Option<&str> {
self.mask
.text
.then(|| self.txt().map(|txt| txt.text))
.flatten()
}
fn el(&self) -> Option<&'a VElement<'a>> {
if let VNode::Element(el) = &self.inner {
Some(el)
} else { } else {
None None
} }
} }
pub fn attributes(&self) -> impl Iterator<Item = &Attribute<'a>> { fn txt(&self) -> Option<&'a VText<'a>> {
self.inner if let VNode::Text(txt) = &self.inner {
.map(|el| el.attributes) Some(txt)
.unwrap_or_default() } else {
.iter() None
.filter(|a| self.view.attritutes.contains_attribute(&a.name)) }
} }
} }
@@ -54,8 +107,8 @@ impl AttributeMask {
fn contains_attribute(&self, attr: &'static str) -> bool { fn contains_attribute(&self, attr: &'static str) -> bool {
match self { match self {
AttributeMask::All => true, AttributeMask::All => true,
AttributeMask::Dynamic(l) => l.contains(&attr), AttributeMask::Dynamic(l) => l.binary_search(&attr).is_ok(),
AttributeMask::Static(l) => l.contains(&attr), AttributeMask::Static(l) => l.binary_search(&attr).is_ok(),
} }
} }
@@ -78,46 +131,19 @@ impl AttributeMask {
} }
pub fn union(&self, other: &Self) -> Self { pub fn union(&self, other: &Self) -> Self {
pub fn union_iter(
s_iter: impl Iterator<Item = &'static str>,
o_iter: impl Iterator<Item = &'static str>,
) -> Vec<&'static str> {
let mut s_peekable = s_iter.peekable();
let mut o_peekable = o_iter.peekable();
let mut v = Vec::new();
while let Some(s_i) = s_peekable.peek() {
loop {
if let Some(o_i) = o_peekable.peek() {
if o_i > s_i {
break;
} else {
v.push(o_peekable.next().unwrap());
}
} else {
break;
}
}
v.push(s_peekable.next().unwrap());
}
while let Some(o_i) = o_peekable.next() {
v.push(o_i);
}
v
}
let new = match (self, other) { let new = match (self, other) {
(AttributeMask::Dynamic(s), AttributeMask::Dynamic(o)) => { (AttributeMask::Dynamic(s), AttributeMask::Dynamic(o)) => AttributeMask::Dynamic(
AttributeMask::Dynamic(union_iter(s.iter().copied(), o.iter().copied())) union_ordered_iter(s.iter().copied(), o.iter().copied(), s.len() + o.len()),
} ),
(AttributeMask::Static(s), AttributeMask::Dynamic(o)) => { (AttributeMask::Static(s), AttributeMask::Dynamic(o)) => AttributeMask::Dynamic(
AttributeMask::Dynamic(union_iter(s.iter().copied(), o.iter().copied())) union_ordered_iter(s.iter().copied(), o.iter().copied(), s.len() + o.len()),
} ),
(AttributeMask::Dynamic(s), AttributeMask::Static(o)) => { (AttributeMask::Dynamic(s), AttributeMask::Static(o)) => AttributeMask::Dynamic(
AttributeMask::Dynamic(union_iter(s.iter().copied(), o.iter().copied())) union_ordered_iter(s.iter().copied(), o.iter().copied(), s.len() + o.len()),
} ),
(AttributeMask::Static(s), AttributeMask::Static(o)) => { (AttributeMask::Static(s), AttributeMask::Static(o)) => AttributeMask::Dynamic(
AttributeMask::Dynamic(union_iter(s.iter().copied(), o.iter().copied())) union_ordered_iter(s.iter().copied(), o.iter().copied(), s.len() + o.len()),
} ),
_ => AttributeMask::All, _ => AttributeMask::All,
}; };
new.verify(); new.verify();
@@ -179,29 +205,37 @@ pub struct NodeMask {
attritutes: AttributeMask, attritutes: AttributeMask,
tag: bool, tag: bool,
namespace: bool, namespace: bool,
text: bool,
} }
impl NodeMask { impl NodeMask {
pub const NONE: Self = Self::new(AttributeMask::Static(&[]), false, false); pub const NONE: Self = Self::new(AttributeMask::Static(&[]), false, false, false);
pub const ALL: Self = Self::new(AttributeMask::All, true, true); pub const ALL: Self = Self::new(AttributeMask::All, true, true, true);
/// attritutes must be sorted! /// attritutes must be sorted!
pub const fn new(attritutes: AttributeMask, tag: bool, namespace: bool) -> Self { pub const fn new(attritutes: AttributeMask, tag: bool, namespace: bool, text: bool) -> Self {
Self { Self {
attritutes, attritutes,
tag, tag,
namespace, namespace,
text,
} }
} }
pub fn overlaps(&self, other: &Self) -> bool { pub fn overlaps(&self, other: &Self) -> bool {
(self.tag && other.tag) (self.tag && other.tag)
|| (self.namespace && other.namespace) || (self.namespace && other.namespace)
|| self.attritutes_overlap(other) || self.attritutes.overlaps(&other.attritutes)
|| (self.text && other.text)
} }
fn attritutes_overlap(&self, other: &Self) -> bool { pub fn union(&self, other: &Self) -> Self {
self.attritutes.overlaps(&other.attritutes) Self {
attritutes: self.attritutes.union(&other.attritutes),
tag: self.tag | other.tag,
namespace: self.namespace | other.namespace,
text: self.text | other.text,
}
} }
} }
@@ -213,8 +247,15 @@ pub trait ChildDepState {
/// This is sometimes nessisary for lifetime purposes. /// This is sometimes nessisary for lifetime purposes.
type Ctx; type Ctx;
type DepState: ChildDepState; type DepState: ChildDepState;
const NODE_MASK: NodeMask = NodeMask::new(AttributeMask::NONE, false, false); const NODE_MASK: NodeMask = NodeMask::NONE;
fn reduce(&mut self, node: NodeView, children: Vec<&Self::DepState>, ctx: &Self::Ctx) -> bool; fn reduce<'a>(
&mut self,
node: NodeView,
children: impl Iterator<Item = &'a Self::DepState>,
ctx: &Self::Ctx,
) -> bool
where
Self::DepState: 'a;
} }
/// This state that is passed down to children. For example text properties (`<b>` `<i>` `<u>`) would be passed to children. /// This state that is passed down to children. For example text properties (`<b>` `<i>` `<u>`) would be passed to children.
@@ -225,7 +266,7 @@ pub trait ParentDepState {
/// This is sometimes nessisary for lifetime purposes. /// This is sometimes nessisary for lifetime purposes.
type Ctx; type Ctx;
type DepState: ParentDepState; type DepState: ParentDepState;
const NODE_MASK: NodeMask = NodeMask::new(AttributeMask::NONE, false, false); const NODE_MASK: NodeMask = NodeMask::NONE;
fn reduce(&mut self, node: NodeView, parent: Option<&Self::DepState>, ctx: &Self::Ctx) -> bool; fn reduce(&mut self, node: NodeView, parent: Option<&Self::DepState>, ctx: &Self::Ctx) -> bool;
} }
@@ -234,7 +275,7 @@ pub trait ParentDepState {
/// Called at most once per update. /// Called at most once per update.
pub trait NodeDepState { pub trait NodeDepState {
type Ctx; type Ctx;
const NODE_MASK: NodeMask = NodeMask::new(AttributeMask::NONE, false, false); const NODE_MASK: NodeMask = NodeMask::NONE;
fn reduce(&mut self, node: NodeView, ctx: &Self::Ctx) -> bool; fn reduce(&mut self, node: NodeView, ctx: &Self::Ctx) -> bool;
} }
@@ -242,7 +283,7 @@ pub trait State: Default + Clone {
fn update_node_dep_state<'a>( fn update_node_dep_state<'a>(
&'a mut self, &'a mut self,
ty: TypeId, ty: TypeId,
node: Option<&'a VElement<'a>>, node: &'a VNode<'a>,
ctx: &AnyMap, ctx: &AnyMap,
) -> bool; ) -> bool;
/// This must be a valid resolution order. (no nodes updated before a state they rely on) /// This must be a valid resolution order. (no nodes updated before a state they rely on)
@@ -251,7 +292,7 @@ pub trait State: Default + Clone {
fn update_parent_dep_state<'a>( fn update_parent_dep_state<'a>(
&'a mut self, &'a mut self,
ty: TypeId, ty: TypeId,
node: Option<&'a VElement<'a>>, node: &'a VNode<'a>,
parent: Option<&Self>, parent: Option<&Self>,
ctx: &AnyMap, ctx: &AnyMap,
) -> bool; ) -> bool;
@@ -261,7 +302,7 @@ pub trait State: Default + Clone {
fn update_child_dep_state<'a>( fn update_child_dep_state<'a>(
&'a mut self, &'a mut self,
ty: TypeId, ty: TypeId,
node: Option<&'a VElement<'a>>, node: &'a VNode<'a>,
children: &[&Self], children: &[&Self],
ctx: &AnyMap, ctx: &AnyMap,
) -> bool; ) -> bool;
+1 -1
View File
@@ -3,7 +3,7 @@ use dioxus_core::*;
use dioxus_core_macro::*; use dioxus_core_macro::*;
use dioxus_html as dioxus_elements; use dioxus_html as dioxus_elements;
use dioxus_native_core::real_dom::RealDom; use dioxus_native_core::real_dom::RealDom;
use dioxus_native_core::real_dom_new_api::State; use dioxus_native_core::state::State;
use dioxus_native_core_macro::State; use dioxus_native_core_macro::State;
use std::cell::Cell; use std::cell::Cell;
+1 -1
View File
@@ -5,7 +5,7 @@ use dioxus_core::*;
use dioxus_core_macro::*; use dioxus_core_macro::*;
use dioxus_html as dioxus_elements; use dioxus_html as dioxus_elements;
use dioxus_native_core::real_dom::RealDom; use dioxus_native_core::real_dom::RealDom;
use dioxus_native_core::real_dom_new_api::State; use dioxus_native_core::state::State;
use dioxus_native_core_macro::State; use dioxus_native_core_macro::State;
#[derive(State, Default, Clone)] #[derive(State, Default, Clone)]
+10 -7
View File
@@ -1,4 +1,4 @@
use dioxus_native_core::real_dom_new_api::*; use dioxus_native_core::state::*;
use dioxus_native_core_macro::*; use dioxus_native_core_macro::*;
#[derive(State, Default, Clone)] #[derive(State, Default, Clone)]
@@ -20,7 +20,7 @@ struct Z {
// z: C, // z: C,
// } // }
use dioxus_native_core::real_dom_new_api::NodeDepState; use dioxus_native_core::state::NodeDepState;
#[derive(Default, Clone)] #[derive(Default, Clone)]
struct A; struct A;
@@ -36,12 +36,15 @@ struct B;
impl ChildDepState for B { impl ChildDepState for B {
type Ctx = i32; type Ctx = i32;
type DepState = Self; type DepState = Self;
fn reduce( fn reduce<'a>(
&mut self, &mut self,
_: dioxus_native_core::real_dom_new_api::NodeView, _: dioxus_native_core::state::NodeView,
_: Vec<&Self::DepState>, _: impl Iterator<Item = &'a Self::DepState>,
_: &i32, _: &i32,
) -> bool { ) -> bool
where
Self::DepState: 'a,
{
todo!() todo!()
} }
} }
@@ -53,7 +56,7 @@ impl ParentDepState for C {
type DepState = Self; type DepState = Self;
fn reduce( fn reduce(
&mut self, &mut self,
_: dioxus_native_core::real_dom_new_api::NodeView, _: dioxus_native_core::state::NodeView,
_: Option<&Self::DepState>, _: Option<&Self::DepState>,
_: &u8, _: &u8,
) -> bool { ) -> bool {
@@ -4,7 +4,7 @@ use dioxus_core::*;
use dioxus_core_macro::*; use dioxus_core_macro::*;
use dioxus_html as dioxus_elements; use dioxus_html as dioxus_elements;
use dioxus_native_core::real_dom::*; use dioxus_native_core::real_dom::*;
use dioxus_native_core::real_dom_new_api::{ use dioxus_native_core::state::{
AttributeMask, ChildDepState, NodeDepState, NodeMask, NodeView, ParentDepState, State, AttributeMask, ChildDepState, NodeDepState, NodeMask, NodeView, ParentDepState, State,
}; };
use dioxus_native_core_macro::State; use dioxus_native_core_macro::State;
@@ -25,12 +25,15 @@ impl ChildDepState for ChildDepCallCounter {
type Ctx = (); type Ctx = ();
type DepState = Self; type DepState = Self;
const NODE_MASK: NodeMask = NodeMask::ALL; const NODE_MASK: NodeMask = NodeMask::ALL;
fn reduce( fn reduce<'a>(
&mut self, &mut self,
_node: NodeView, _: NodeView,
_children: Vec<&Self::DepState>, _: impl Iterator<Item = &'a Self::DepState>,
_ctx: &Self::Ctx, _: &Self::Ctx,
) -> bool { ) -> bool
where
Self::DepState: 'a,
{
self.0 += 1; self.0 += 1;
true true
} }
@@ -70,7 +73,15 @@ impl ChildDepState for BubbledUpStateTester {
type Ctx = u32; type Ctx = u32;
type DepState = Self; type DepState = Self;
const NODE_MASK: NodeMask = NodeMask::new(AttributeMask::NONE, true, false); const NODE_MASK: NodeMask = NodeMask::new(AttributeMask::NONE, true, false);
fn reduce(&mut self, node: NodeView, children: Vec<&Self::DepState>, ctx: &Self::Ctx) -> bool { fn reduce<'a>(
&mut self,
node: NodeView,
children: impl Iterator<Item = &'a Self::DepState>,
ctx: &Self::Ctx,
) -> bool
where
Self::DepState: 'a,
{
assert_eq!(*ctx, 42); assert_eq!(*ctx, 42);
*self = BubbledUpStateTester( *self = BubbledUpStateTester(
node.tag().map(|s| s.to_string()), node.tag().map(|s| s.to_string()),
@@ -245,6 +256,10 @@ fn state_reduce_initally_called_minimally() {
let nodes_updated = dom.apply_mutations(vec![mutations]); let nodes_updated = dom.apply_mutations(vec![mutations]);
let _to_rerender = dom.update_state(&vdom, nodes_updated, AnyMap::new()); let _to_rerender = dom.update_state(&vdom, nodes_updated, AnyMap::new());
dom.traverse_depth_first(|n| {
println!("{:#?}", n.state);
});
dom.traverse_depth_first(|n| { dom.traverse_depth_first(|n| {
assert_eq!(n.state.child_counter.0, 1); assert_eq!(n.state.child_counter.0, 1);
assert_eq!(n.state.parent_counter.0, 1); assert_eq!(n.state.parent_counter.0, 1);
@@ -314,10 +329,10 @@ fn state_reduce_down_called_minimally_on_update() {
let _to_rerender = dom.update_state(&vdom, nodes_updated, AnyMap::new()); let _to_rerender = dom.update_state(&vdom, nodes_updated, AnyMap::new());
dom.traverse_depth_first(|n| { dom.traverse_depth_first(|n| {
println!("{:?}", n.state); // println!("{:?}", n.state);
// assert_eq!(n.state.parent_counter.0, 2); assert_eq!(n.state.parent_counter.0, 2);
}); });
panic!() // panic!()
} }
#[test] #[test]
@@ -382,8 +397,6 @@ fn state_reduce_up_called_minimally_on_update() {
let _to_rerender = dom.update_state(&vdom, nodes_updated, AnyMap::new()); let _to_rerender = dom.update_state(&vdom, nodes_updated, AnyMap::new());
dom.traverse_depth_first(|n| { dom.traverse_depth_first(|n| {
println!("{:?}", n.state); assert_eq!(n.state.child_counter.0, if n.id.0 > 4 { 1 } else { 2 });
// assert_eq!(n.state.child_counter.0, if n.id.0 > 4 { 1 } else { 2 });
}); });
panic!()
} }
+16 -20
View File
@@ -5,7 +5,6 @@ use dioxus_core::*;
use fxhash::{FxHashMap, FxHashSet}; use fxhash::{FxHashMap, FxHashSet};
use dioxus_html::{on::*, KeyCode}; use dioxus_html::{on::*, KeyCode};
use dioxus_native_core::real_dom::{Node, RealDom};
use std::{ use std::{
any::Any, any::Any,
cell::RefCell, cell::RefCell,
@@ -17,6 +16,7 @@ use stretch2::{prelude::Layout, Stretch};
use crate::layout::StretchLayout; use crate::layout::StretchLayout;
use crate::style_attributes::StyleModifier; use crate::style_attributes::StyleModifier;
use crate::{Dom, Node};
// a wrapper around the input state for easier access // a wrapper around the input state for easier access
// todo: fix loop // todo: fix loop
@@ -166,7 +166,7 @@ impl InnerInputState {
evts: &mut Vec<EventCore>, evts: &mut Vec<EventCore>,
resolved_events: &mut Vec<UserEvent>, resolved_events: &mut Vec<UserEvent>,
layout: &Stretch, layout: &Stretch,
dom: &mut RealDom<StretchLayout, StyleModifier>, dom: &mut Dom,
) { ) {
let previous_mouse = self let previous_mouse = self
.mouse .mouse
@@ -191,7 +191,7 @@ impl InnerInputState {
previous_mouse: Option<(MouseData, Vec<u16>)>, previous_mouse: Option<(MouseData, Vec<u16>)>,
resolved_events: &mut Vec<UserEvent>, resolved_events: &mut Vec<UserEvent>,
layout: &Stretch, layout: &Stretch,
dom: &mut RealDom<StretchLayout, StyleModifier>, dom: &mut Dom,
) { ) {
struct Data<'b> { struct Data<'b> {
new_pos: (i32, i32), new_pos: (i32, i32),
@@ -215,8 +215,8 @@ impl InnerInputState {
data: Arc<dyn Any + Send + Sync>, data: Arc<dyn Any + Send + Sync>,
will_bubble: &mut FxHashSet<ElementId>, will_bubble: &mut FxHashSet<ElementId>,
resolved_events: &mut Vec<UserEvent>, resolved_events: &mut Vec<UserEvent>,
node: &Node<StretchLayout, StyleModifier>, node: &Node,
dom: &RealDom<StretchLayout, StyleModifier>, dom: &Dom,
) { ) {
// 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
if will_bubble.insert(node.id) { if will_bubble.insert(node.id) {
@@ -261,7 +261,7 @@ impl InnerInputState {
// mousemove // mousemove
let mut will_bubble = FxHashSet::default(); let mut will_bubble = FxHashSet::default();
for node in dom.get_listening_sorted("mousemove") { for node in dom.get_listening_sorted("mousemove") {
let node_layout = layout.layout(node.up_state.node.unwrap()).unwrap(); let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
let previously_contained = data let previously_contained = data
.old_pos .old_pos
.filter(|pos| layout_contains_point(node_layout, *pos)) .filter(|pos| layout_contains_point(node_layout, *pos))
@@ -285,7 +285,7 @@ impl InnerInputState {
// mouseenter // mouseenter
let mut will_bubble = FxHashSet::default(); let mut will_bubble = FxHashSet::default();
for node in dom.get_listening_sorted("mouseenter") { for node in dom.get_listening_sorted("mouseenter") {
let node_layout = layout.layout(node.up_state.node.unwrap()).unwrap(); let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
let previously_contained = data let previously_contained = data
.old_pos .old_pos
.filter(|pos| layout_contains_point(node_layout, *pos)) .filter(|pos| layout_contains_point(node_layout, *pos))
@@ -309,7 +309,7 @@ impl InnerInputState {
// mouseover // mouseover
let mut will_bubble = FxHashSet::default(); let mut will_bubble = FxHashSet::default();
for node in dom.get_listening_sorted("mouseover") { for node in dom.get_listening_sorted("mouseover") {
let node_layout = layout.layout(node.up_state.node.unwrap()).unwrap(); let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
let previously_contained = data let previously_contained = data
.old_pos .old_pos
.filter(|pos| layout_contains_point(node_layout, *pos)) .filter(|pos| layout_contains_point(node_layout, *pos))
@@ -333,7 +333,7 @@ impl InnerInputState {
// mousedown // mousedown
let mut will_bubble = FxHashSet::default(); let mut will_bubble = FxHashSet::default();
for node in dom.get_listening_sorted("mousedown") { for node in dom.get_listening_sorted("mousedown") {
let node_layout = layout.layout(node.up_state.node.unwrap()).unwrap(); let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
let currently_contains = layout_contains_point(node_layout, data.new_pos); let currently_contains = layout_contains_point(node_layout, data.new_pos);
if currently_contains && data.clicked { if currently_contains && data.clicked {
@@ -353,7 +353,7 @@ impl InnerInputState {
// mouseup // mouseup
let mut will_bubble = FxHashSet::default(); let mut will_bubble = FxHashSet::default();
for node in dom.get_listening_sorted("mouseup") { for node in dom.get_listening_sorted("mouseup") {
let node_layout = layout.layout(node.up_state.node.unwrap()).unwrap(); let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
let currently_contains = layout_contains_point(node_layout, data.new_pos); let currently_contains = layout_contains_point(node_layout, data.new_pos);
if currently_contains && data.released { if currently_contains && data.released {
@@ -373,7 +373,7 @@ impl InnerInputState {
// click // click
let mut will_bubble = FxHashSet::default(); let mut will_bubble = FxHashSet::default();
for node in dom.get_listening_sorted("click") { for node in dom.get_listening_sorted("click") {
let node_layout = layout.layout(node.up_state.node.unwrap()).unwrap(); let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
let currently_contains = layout_contains_point(node_layout, data.new_pos); let currently_contains = layout_contains_point(node_layout, data.new_pos);
if currently_contains && data.released && data.mouse_data.button == 0 { if currently_contains && data.released && data.mouse_data.button == 0 {
@@ -393,7 +393,7 @@ impl InnerInputState {
// contextmenu // contextmenu
let mut will_bubble = FxHashSet::default(); let mut will_bubble = FxHashSet::default();
for node in dom.get_listening_sorted("contextmenu") { for node in dom.get_listening_sorted("contextmenu") {
let node_layout = layout.layout(node.up_state.node.unwrap()).unwrap(); let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
let currently_contains = layout_contains_point(node_layout, data.new_pos); let currently_contains = layout_contains_point(node_layout, data.new_pos);
if currently_contains && data.released && data.mouse_data.button == 2 { if currently_contains && data.released && data.mouse_data.button == 2 {
@@ -413,7 +413,7 @@ impl InnerInputState {
// wheel // wheel
let mut will_bubble = FxHashSet::default(); let mut will_bubble = FxHashSet::default();
for node in dom.get_listening_sorted("wheel") { for node in dom.get_listening_sorted("wheel") {
let node_layout = layout.layout(node.up_state.node.unwrap()).unwrap(); let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
let currently_contains = layout_contains_point(node_layout, data.new_pos); let currently_contains = layout_contains_point(node_layout, data.new_pos);
if let Some(w) = data.wheel_data { if let Some(w) = data.wheel_data {
@@ -435,7 +435,7 @@ impl InnerInputState {
// mouseleave // mouseleave
let mut will_bubble = FxHashSet::default(); let mut will_bubble = FxHashSet::default();
for node in dom.get_listening_sorted("mouseleave") { for node in dom.get_listening_sorted("mouseleave") {
let node_layout = layout.layout(node.up_state.node.unwrap()).unwrap(); let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
let previously_contained = data let previously_contained = data
.old_pos .old_pos
.filter(|pos| layout_contains_point(node_layout, *pos)) .filter(|pos| layout_contains_point(node_layout, *pos))
@@ -459,7 +459,7 @@ impl InnerInputState {
// mouseout // mouseout
let mut will_bubble = FxHashSet::default(); let mut will_bubble = FxHashSet::default();
for node in dom.get_listening_sorted("mouseout") { for node in dom.get_listening_sorted("mouseout") {
let node_layout = layout.layout(node.up_state.node.unwrap()).unwrap(); let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
let previously_contained = data let previously_contained = data
.old_pos .old_pos
.filter(|pos| layout_contains_point(node_layout, *pos)) .filter(|pos| layout_contains_point(node_layout, *pos))
@@ -522,11 +522,7 @@ impl RinkInputHandler {
) )
} }
pub fn get_events( pub(crate) fn get_events(&self, layout: &Stretch, dom: &mut Dom) -> Vec<UserEvent> {
&self,
layout: &Stretch,
dom: &mut RealDom<StretchLayout, StyleModifier>,
) -> Vec<UserEvent> {
let mut resolved_events = Vec::new(); let mut resolved_events = Vec::new();
(*self.state).borrow_mut().update( (*self.state).borrow_mut().update(
+65 -58
View File
@@ -1,83 +1,90 @@
use std::cell::RefCell;
use std::rc::Rc;
use dioxus_core::*; use dioxus_core::*;
use dioxus_native_core::layout_attributes::apply_layout_attributes; use dioxus_native_core::layout_attributes::apply_layout_attributes;
use dioxus_native_core::real_dom::BubbledUpState; use dioxus_native_core::state::{AttributeMask, ChildDepState, NodeMask, NodeView};
use stretch2::prelude::*; use stretch2::prelude::*;
/// the size
#[derive(Clone, PartialEq, Default, Debug)] #[derive(Clone, PartialEq, Default, Debug)]
pub struct StretchLayout { pub struct StretchLayout {
pub style: Style, pub style: Style,
pub node: Option<Node>, pub node: Option<Node>,
} }
impl BubbledUpState for StretchLayout { impl ChildDepState for StretchLayout {
type Ctx = Stretch; type Ctx = Rc<RefCell<Stretch>>;
type DepState = Self;
// todo: update mask
const NODE_MASK: NodeMask = NodeMask::new(AttributeMask::All, false, false, true);
/// Setup the layout /// Setup the layout
fn reduce<'a, I>(&mut self, children: I, vnode: &VNode, stretch: &mut Self::Ctx) fn reduce<'a>(
&mut self,
node: NodeView,
children: impl Iterator<Item = &'a Self::DepState>,
ctx: &Self::Ctx,
) -> bool
where where
I: Iterator<Item = &'a Self>, Self::DepState: 'a,
Self: 'a,
{ {
match vnode { let mut stretch = ctx.borrow_mut();
VNode::Text(t) => { if let Some(text) = node.text() {
let char_len = t.text.chars().count(); let char_len = text.chars().count();
let style = Style { let style = Style {
size: Size { size: Size {
// characters are 1 point tall // characters are 1 point tall
height: Dimension::Points(1.0), height: Dimension::Points(1.0),
// text is as long as it is declared // text is as long as it is declared
width: Dimension::Points(char_len as f32), width: Dimension::Points(char_len as f32),
}, },
..Default::default() ..Default::default()
}; };
if let Some(n) = self.node { if let Some(n) = self.node {
if self.style != style { if self.style != style {
stretch.set_style(n, style).unwrap(); stretch.set_style(n, style).unwrap();
}
} else {
self.node = Some(stretch.new_node(style, &[]).unwrap());
} }
} else {
self.style = style; self.node = Some(stretch.new_node(style, &[]).unwrap());
} }
VNode::Element(el) => {
// gather up all the styles from the attribute list
let mut style = Style::default();
for &Attribute { name, value, .. } in el.attributes { self.style = style;
apply_layout_attributes(name, value, &mut style); } else {
} // gather up all the styles from the attribute list
let mut style = Style::default();
// the root node fills the entire area for &Attribute { name, value, .. } in node.attributes() {
if el.id.get() == Some(ElementId(0)) { apply_layout_attributes(name, value, &mut style);
apply_layout_attributes("width", "100%", &mut style);
apply_layout_attributes("height", "100%", &mut style);
}
// Set all direct nodes as our children
let mut child_layout = vec![];
for l in children {
child_layout.push(l.node.unwrap());
}
if let Some(n) = self.node {
if stretch.children(n).unwrap() != child_layout {
stretch.set_children(n, &child_layout).unwrap();
}
if self.style != style {
stretch.set_style(n, style).unwrap();
}
} else {
self.node = Some(stretch.new_node(style, &child_layout).unwrap());
}
self.style = style;
} }
_ => (),
// the root node fills the entire area
if node.id() == ElementId(0) {
apply_layout_attributes("width", "100%", &mut style);
apply_layout_attributes("height", "100%", &mut style);
}
// Set all direct nodes as our children
let mut child_layout = vec![];
for l in children {
child_layout.push(l.node.unwrap());
}
if let Some(n) = self.node {
if stretch.children(n).unwrap() != child_layout {
stretch.set_children(n, &child_layout).unwrap();
}
if self.style != style {
stretch.set_style(n, style).unwrap();
}
} else {
self.node = Some(stretch.new_node(style, &child_layout).unwrap());
}
self.style = style;
} }
true
} }
} }
+31 -27
View File
@@ -1,4 +1,5 @@
use anyhow::Result; use anyhow::Result;
use anymap::AnyMap;
use crossterm::{ use crossterm::{
event::{DisableMouseCapture, EnableMouseCapture, Event as TermEvent, KeyCode, KeyModifiers}, event::{DisableMouseCapture, EnableMouseCapture, Event as TermEvent, KeyCode, KeyModifiers},
execute, execute,
@@ -6,14 +7,14 @@ use crossterm::{
}; };
use dioxus_core::exports::futures_channel::mpsc::unbounded; use dioxus_core::exports::futures_channel::mpsc::unbounded;
use dioxus_core::*; use dioxus_core::*;
use dioxus_native_core::{ use dioxus_native_core::{dioxus_native_core_macro::State, real_dom::RealDom, state::*};
dioxus_native_core_macro::State, real_dom::RealDom, real_dom_new_api::State,
};
use futures::{ use futures::{
channel::mpsc::{UnboundedReceiver, UnboundedSender}, channel::mpsc::{UnboundedReceiver, UnboundedSender},
pin_mut, StreamExt, pin_mut, StreamExt,
}; };
use layout::StretchLayout; use layout::StretchLayout;
use std::cell::RefCell;
use std::rc::Rc;
use std::{io, time::Duration}; use std::{io, time::Duration};
use stretch2::{prelude::Size, Stretch}; use stretch2::{prelude::Size, Stretch};
use style_attributes::StyleModifier; use style_attributes::StyleModifier;
@@ -31,8 +32,17 @@ pub use config::*;
pub use hooks::*; pub use hooks::*;
pub use render::*; pub use render::*;
type Dom = RealDom<NodeState>;
type Node = dioxus_native_core::real_dom::Node<NodeState>;
#[derive(Debug, Clone, State, Default)] #[derive(Debug, Clone, State, Default)]
struct NodeState {} struct NodeState {
#[child_dep_state(StretchLayout, RefCell<Stretch>)]
layout: StretchLayout,
// depends on attributes, the C component of it's parent and a u8 context
#[parent_dep_state(StyleModifier)]
style: StyleModifier,
}
#[derive(Clone)] #[derive(Clone)]
pub struct TuiContext { pub struct TuiContext {
@@ -75,13 +85,13 @@ pub fn launch_cfg(app: Component<()>, cfg: Config) {
cx.provide_root_context(state); cx.provide_root_context(state);
cx.provide_root_context(TuiContext { tx: event_tx_clone }); cx.provide_root_context(TuiContext { tx: event_tx_clone });
let mut rdom: RealDom<StretchLayout, StyleModifier> = RealDom::new(); let mut rdom: Dom = RealDom::new();
let mutations = dom.rebuild(); let mutations = dom.rebuild();
let to_update = rdom.apply_mutations(vec![mutations]); let to_update = rdom.apply_mutations(vec![mutations]);
let mut stretch = Stretch::new(); let stretch = Rc::new(RefCell::new(Stretch::new()));
let _to_rerender = rdom let mut any_map = AnyMap::new();
.update_state(&dom, to_update, &mut stretch, &mut ()) any_map.insert(stretch.clone());
.unwrap(); let _to_rerender = rdom.update_state(&dom, to_update, any_map).unwrap();
render_vdom( render_vdom(
&mut dom, &mut dom,
@@ -100,8 +110,8 @@ fn render_vdom(
mut event_reciever: UnboundedReceiver<InputEvent>, mut event_reciever: UnboundedReceiver<InputEvent>,
handler: RinkInputHandler, handler: RinkInputHandler,
cfg: Config, cfg: Config,
mut rdom: RealDom<StretchLayout, StyleModifier>, mut rdom: Dom,
mut stretch: Stretch, mut stretch: Rc<RefCell<Stretch>>,
mut register_event: impl FnMut(crossterm::event::Event), mut register_event: impl FnMut(crossterm::event::Event),
) -> Result<()> { ) -> Result<()> {
tokio::runtime::Builder::new_current_thread() tokio::runtime::Builder::new_current_thread()
@@ -119,7 +129,7 @@ fn render_vdom(
terminal.clear().unwrap(); terminal.clear().unwrap();
} }
let mut to_rerender: fxhash::FxHashSet<usize> = vec![0].into_iter().collect(); let to_rerender: fxhash::FxHashSet<usize> = vec![0].into_iter().collect();
let mut resized = true; let mut resized = true;
loop { loop {
@@ -136,15 +146,11 @@ fn render_vdom(
if !to_rerender.is_empty() || resized { if !to_rerender.is_empty() || resized {
resized = false; resized = false;
fn resize( fn resize(dims: Rect, stretch: &mut Stretch, rdom: &Dom) {
dims: Rect,
stretch: &mut Stretch,
rdom: &RealDom<StretchLayout, StyleModifier>,
) {
let width = dims.width; let width = dims.width;
let height = dims.height; let height = dims.height;
let root_id = rdom.root_id(); let root_id = rdom.root_id();
let root_node = rdom[root_id].up_state.node.unwrap(); let root_node = rdom[root_id].state.layout.node.unwrap();
stretch stretch
.compute_layout( .compute_layout(
@@ -159,9 +165,9 @@ fn render_vdom(
if let Some(terminal) = &mut terminal { if let Some(terminal) = &mut terminal {
terminal.draw(|frame| { terminal.draw(|frame| {
// size is guaranteed to not change when rendering // size is guaranteed to not change when rendering
resize(frame.size(), &mut stretch, &rdom); resize(frame.size(), &mut stretch.borrow_mut(), &rdom);
let root = &rdom[rdom.root_id()]; let root = &rdom[rdom.root_id()];
render::render_vnode(frame, &stretch, &rdom, &root, cfg); render::render_vnode(frame, &stretch.borrow(), &rdom, &root, cfg);
})?; })?;
} else { } else {
resize( resize(
@@ -171,7 +177,7 @@ fn render_vdom(
width: 300, width: 300,
height: 300, height: 300,
}, },
&mut stretch, &mut stretch.borrow_mut(),
&rdom, &rdom,
); );
} }
@@ -212,7 +218,7 @@ fn render_vdom(
{ {
// resolve events before rendering // resolve events before rendering
let evts = handler.get_events(&stretch, &mut rdom); let evts = handler.get_events(&stretch.borrow(), &mut rdom);
for e in evts { for e in evts {
vdom.handle_message(SchedulerMsg::Event(e)); vdom.handle_message(SchedulerMsg::Event(e));
} }
@@ -220,11 +226,9 @@ fn render_vdom(
// updates the dom's nodes // updates the dom's nodes
let to_update = rdom.apply_mutations(mutations); let to_update = rdom.apply_mutations(mutations);
// update the style and layout // update the style and layout
to_rerender.extend( let mut any_map = AnyMap::new();
rdom.update_state(vdom, to_update, &mut stretch, &mut ()) any_map.insert(stretch.clone());
.unwrap() let _to_rerender = rdom.update_state(&vdom, to_update, any_map).unwrap();
.iter(),
)
} }
} }
+14 -17
View File
@@ -1,8 +1,5 @@
use crate::layout::StretchLayout; use crate::layout::StretchLayout;
use dioxus_native_core::{ use dioxus_native_core::layout_attributes::UnitSystem;
layout_attributes::UnitSystem,
real_dom::{Node, RealDom},
};
use std::io::Stdout; use std::io::Stdout;
use stretch2::{ use stretch2::{
geometry::Point, geometry::Point,
@@ -15,16 +12,16 @@ use crate::{
style::{RinkColor, RinkStyle}, style::{RinkColor, RinkStyle},
style_attributes::{BorderEdge, BorderStyle}, style_attributes::{BorderEdge, BorderStyle},
widget::{RinkBuffer, RinkCell, RinkWidget, WidgetWithContext}, widget::{RinkBuffer, RinkCell, RinkWidget, WidgetWithContext},
Config, StyleModifier, Config, Dom, Node, StyleModifier,
}; };
const RADIUS_MULTIPLIER: [f32; 2] = [1.0, 0.5]; const RADIUS_MULTIPLIER: [f32; 2] = [1.0, 0.5];
pub fn render_vnode( pub(crate) fn render_vnode(
frame: &mut tui::Frame<CrosstermBackend<Stdout>>, frame: &mut tui::Frame<CrosstermBackend<Stdout>>,
layout: &Stretch, layout: &Stretch,
rdom: &RealDom<StretchLayout, StyleModifier>, rdom: &Dom,
node: &Node<StretchLayout, StyleModifier>, node: &Node,
cfg: Config, cfg: Config,
) { ) {
use dioxus_native_core::real_dom::NodeType; use dioxus_native_core::real_dom::NodeType;
@@ -33,7 +30,7 @@ pub fn render_vnode(
return; return;
} }
let Layout { location, size, .. } = layout.layout(node.up_state.node.unwrap()).unwrap(); let Layout { location, size, .. } = layout.layout(node.state.layout.node.unwrap()).unwrap();
let Point { x, y } = location; let Point { x, y } = location;
let Size { width, height } = size; let Size { width, height } = size;
@@ -59,7 +56,7 @@ pub fn render_vnode(
let label = Label { let label = Label {
text, text,
style: node.down_state.style, style: node.state.style.style,
}; };
let area = Rect::new(*x as u16, *y as u16, *width as u16, *height as u16); let area = Rect::new(*x as u16, *y as u16, *width as u16, *height as u16);
@@ -84,7 +81,7 @@ pub fn render_vnode(
} }
} }
impl RinkWidget for &Node<StretchLayout, StyleModifier> { impl RinkWidget for &Node {
fn render(self, area: Rect, mut buf: RinkBuffer<'_>) { fn render(self, area: Rect, mut buf: RinkBuffer<'_>) {
use tui::symbols::line::*; use tui::symbols::line::*;
@@ -268,14 +265,14 @@ impl RinkWidget for &Node<StretchLayout, StyleModifier> {
for x in area.left()..area.right() { for x in area.left()..area.right() {
for y in area.top()..area.bottom() { for y in area.top()..area.bottom() {
let mut new_cell = RinkCell::default(); let mut new_cell = RinkCell::default();
if let Some(c) = self.down_state.style.bg { if let Some(c) = self.state.style.style.bg {
new_cell.bg = c; new_cell.bg = c;
} }
buf.set(x, y, new_cell); buf.set(x, y, new_cell);
} }
} }
let borders = &self.down_state.modifier.borders; let borders = &self.state.style.modifier.borders;
let last_edge = &borders.left; let last_edge = &borders.left;
let current_edge = &borders.top; let current_edge = &borders.top;
@@ -292,7 +289,7 @@ impl RinkWidget for &Node<StretchLayout, StyleModifier> {
(last_r * RADIUS_MULTIPLIER[0]) as u16, (last_r * RADIUS_MULTIPLIER[0]) as u16,
(last_r * RADIUS_MULTIPLIER[1]) as u16, (last_r * RADIUS_MULTIPLIER[1]) as u16,
]; ];
let color = current_edge.color.or(self.down_state.style.fg); let color = current_edge.color.or(self.state.style.style.fg);
let mut new_cell = RinkCell::default(); let mut new_cell = RinkCell::default();
if let Some(c) = color { if let Some(c) = color {
new_cell.fg = c; new_cell.fg = c;
@@ -327,7 +324,7 @@ impl RinkWidget for &Node<StretchLayout, StyleModifier> {
(last_r * RADIUS_MULTIPLIER[0]) as u16, (last_r * RADIUS_MULTIPLIER[0]) as u16,
(last_r * RADIUS_MULTIPLIER[1]) as u16, (last_r * RADIUS_MULTIPLIER[1]) as u16,
]; ];
let color = current_edge.color.or(self.down_state.style.fg); let color = current_edge.color.or(self.state.style.style.fg);
let mut new_cell = RinkCell::default(); let mut new_cell = RinkCell::default();
if let Some(c) = color { if let Some(c) = color {
new_cell.fg = c; new_cell.fg = c;
@@ -362,7 +359,7 @@ impl RinkWidget for &Node<StretchLayout, StyleModifier> {
(last_r * RADIUS_MULTIPLIER[0]) as u16, (last_r * RADIUS_MULTIPLIER[0]) as u16,
(last_r * RADIUS_MULTIPLIER[1]) as u16, (last_r * RADIUS_MULTIPLIER[1]) as u16,
]; ];
let color = current_edge.color.or(self.down_state.style.fg); let color = current_edge.color.or(self.state.style.style.fg);
let mut new_cell = RinkCell::default(); let mut new_cell = RinkCell::default();
if let Some(c) = color { if let Some(c) = color {
new_cell.fg = c; new_cell.fg = c;
@@ -397,7 +394,7 @@ impl RinkWidget for &Node<StretchLayout, StyleModifier> {
(last_r * RADIUS_MULTIPLIER[0]) as u16, (last_r * RADIUS_MULTIPLIER[0]) as u16,
(last_r * RADIUS_MULTIPLIER[1]) as u16, (last_r * RADIUS_MULTIPLIER[1]) as u16,
]; ];
let color = current_edge.color.or(self.down_state.style.fg); let color = current_edge.color.or(self.state.style.style.fg);
let mut new_cell = RinkCell::default(); let mut new_cell = RinkCell::default();
if let Some(c) = color { if let Some(c) = color {
new_cell.fg = c; new_cell.fg = c;
+16 -11
View File
@@ -32,7 +32,7 @@
use dioxus_core::{Attribute, VNode}; use dioxus_core::{Attribute, VNode};
use dioxus_native_core::{ use dioxus_native_core::{
layout_attributes::{parse_value, UnitSystem}, layout_attributes::{parse_value, UnitSystem},
real_dom::PushedDownState, state::{AttributeMask, NodeMask, NodeView, ParentDepState},
}; };
use crate::style::{RinkColor, RinkStyle}; use crate::style::{RinkColor, RinkStyle};
@@ -43,18 +43,22 @@ pub struct StyleModifier {
pub modifier: TuiModifier, pub modifier: TuiModifier,
} }
impl PushedDownState for StyleModifier { impl ParentDepState for StyleModifier {
type Ctx = (); type Ctx = ();
type DepState = Self;
// todo: seperate each attribute into it's own class
const NODE_MASK: NodeMask = NodeMask::new(AttributeMask::All, true, true, false);
fn reduce(&mut self, parent: Option<&Self>, vnode: &VNode, _ctx: &mut Self::Ctx) { fn reduce(&mut self, node: NodeView, parent: Option<&Self::DepState>, ctx: &Self::Ctx) -> bool {
*self = StyleModifier::default(); *self = StyleModifier::default();
if parent.is_some() { if parent.is_some() {
self.style.fg = None; self.style.fg = None;
} }
if let VNode::Element(el) = vnode {
// handle text modifier elements // handle text modifier elements
if el.namespace.is_none() { if node.namespace().is_none() {
match el.tag { if let Some(tag) = node.tag() {
match tag {
"b" => apply_style_attributes("font-weight", "bold", self), "b" => apply_style_attributes("font-weight", "bold", self),
"strong" => apply_style_attributes("font-weight", "bold", self), "strong" => apply_style_attributes("font-weight", "bold", self),
"u" => apply_style_attributes("text-decoration", "underline", self), "u" => apply_style_attributes("text-decoration", "underline", self),
@@ -68,11 +72,11 @@ impl PushedDownState for StyleModifier {
_ => (), _ => (),
} }
} }
}
// gather up all the styles from the attribute list // gather up all the styles from the attribute list
for &Attribute { name, value, .. } in el.attributes { for &Attribute { name, value, .. } in node.attributes() {
apply_style_attributes(name, value, self); apply_style_attributes(name, value, self);
}
} }
// keep the text styling from the parent element // keep the text styling from the parent element
@@ -81,6 +85,7 @@ impl PushedDownState for StyleModifier {
new_style.bg = self.style.bg; new_style.bg = self.style.bg;
self.style = new_style; self.style = new_style;
} }
true
} }
} }