update TUI renderer to new approach
This commit is contained in:
1 parent
ce59ccfd44
commit
9efff74c0c
14 files changed
+339
-270
No files matched your search
@@ -4,6 +4,7 @@ use std::hash::BuildHasherDefault;
|
|||||||
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};
|
||||||
|
pub use real_dom::{NodeMut, NodeRef, RealDom};
|
||||||
use rustc_hash::FxHasher;
|
use rustc_hash::FxHasher;
|
||||||
pub use tree::NodeId;
|
pub use tree::NodeId;
|
||||||
|
|
||||||
|
|||||||
@@ -262,15 +262,16 @@ impl NodeMaskBuilder {
|
|||||||
/// A node mask with no parts visible.
|
/// A node mask with no parts visible.
|
||||||
pub const NONE: Self = Self::new();
|
pub const NONE: Self = Self::new();
|
||||||
/// A node mask with every part visible.
|
/// A node mask with every part visible.
|
||||||
pub const ALL: Self = Self::new_with_attrs(AttributeMaskBuilder::All)
|
pub const ALL: Self = Self::new()
|
||||||
|
.with_attrs(AttributeMaskBuilder::All)
|
||||||
.with_text()
|
.with_text()
|
||||||
.with_element()
|
.with_element()
|
||||||
.with_listeners();
|
.with_listeners();
|
||||||
|
|
||||||
/// Create a new node mask with the given attributes
|
/// Create a empty node mask
|
||||||
pub const fn new_with_attrs(attritutes: AttributeMaskBuilder) -> Self {
|
pub const fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
attritutes,
|
attritutes: AttributeMaskBuilder::Some(&[]),
|
||||||
tag: false,
|
tag: false,
|
||||||
namespace: false,
|
namespace: false,
|
||||||
text: false,
|
text: false,
|
||||||
@@ -278,9 +279,10 @@ impl NodeMaskBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a empty node mask
|
/// Allow the mask to view the given attributes
|
||||||
pub const fn new() -> Self {
|
pub const fn with_attrs(mut self, attritutes: AttributeMaskBuilder) -> Self {
|
||||||
Self::new_with_attrs(AttributeMaskBuilder::Some(&[]))
|
self.attritutes = attritutes;
|
||||||
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allow the mask to view the tag
|
/// Allow the mask to view the tag
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ use crate::{FxDashSet, SendAnyMap};
|
|||||||
///
|
///
|
||||||
/// # Custom values
|
/// # Custom values
|
||||||
/// To allow custom values to be passed into attributes implement FromAnyValue on a type that can represent your custom value and specify the V generic to be that type. If you have many different custom values, it can be useful to use a enum type to represent the varients.
|
/// To allow custom values to be passed into attributes implement FromAnyValue on a type that can represent your custom value and specify the V generic to be that type. If you have many different custom values, it can be useful to use a enum type to represent the varients.
|
||||||
pub struct RealDom<V: FromAnyValue + Send = ()> {
|
pub struct RealDom<V: FromAnyValue + Send + Sync = ()> {
|
||||||
pub(crate) tree: Tree,
|
pub(crate) tree: Tree,
|
||||||
/// a map from element id to real node id
|
/// a map from element id to real node id
|
||||||
node_id_mapping: Vec<Option<NodeId>>,
|
node_id_mapping: Vec<Option<NodeId>>,
|
||||||
@@ -38,7 +38,7 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
|||||||
pub fn new(mut passes: Box<[TypeErasedPass<V>]>) -> RealDom<V> {
|
pub fn new(mut passes: Box<[TypeErasedPass<V>]>) -> RealDom<V> {
|
||||||
let mut tree = Tree::new();
|
let mut tree = Tree::new();
|
||||||
let root_id = tree.root();
|
let root_id = tree.root();
|
||||||
let root: &mut NodeData<V> = tree.write(root_id).unwrap();
|
let root: &mut NodeData<V> = tree.get_mut(root_id).unwrap();
|
||||||
let mut root_node: NodeData<V> = NodeData::new(NodeType::Element(ElementNode {
|
let mut root_node: NodeData<V> = NodeData::new(NodeType::Element(ElementNode {
|
||||||
tag: "Root".to_string(),
|
tag: "Root".to_string(),
|
||||||
namespace: Some("Root".to_string()),
|
namespace: Some("Root".to_string()),
|
||||||
@@ -95,7 +95,7 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn set_element_id(&mut self, node_id: NodeId, element_id: ElementId) {
|
fn set_element_id(&mut self, node_id: NodeId, element_id: ElementId) {
|
||||||
let mut node = self.tree.write::<NodeData>(node_id).unwrap();
|
let mut node = self.tree.get_mut::<NodeData>(node_id).unwrap();
|
||||||
let node_id = node.node_id;
|
let node_id = node.node_id;
|
||||||
node.element_id = Some(element_id);
|
node.element_id = Some(element_id);
|
||||||
if self.node_id_mapping.len() <= element_id.0 {
|
if self.node_id_mapping.len() <= element_id.0 {
|
||||||
@@ -342,14 +342,17 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
|||||||
|
|
||||||
/// Find all nodes that are listening for an event, sorted by there height in the dom progressing starting at the bottom and progressing up.
|
/// Find all nodes that are listening for an event, sorted by there height in the dom progressing starting at the bottom and progressing up.
|
||||||
/// This can be useful to avoid creating duplicate events.
|
/// This can be useful to avoid creating duplicate events.
|
||||||
pub fn get_listening_sorted(&self, event: &'static str) -> Vec<NodeId> {
|
pub fn get_listening_sorted(&self, event: &'static str) -> Vec<NodeRef<V>> {
|
||||||
if let Some(nodes) = self.nodes_listening.get(event) {
|
if let Some(nodes) = self.nodes_listening.get(event) {
|
||||||
let mut listening: Vec<_> = nodes
|
let mut listening: Vec<_> = nodes
|
||||||
.iter()
|
.iter()
|
||||||
.map(|id| (*id, self.tree.height(*id).unwrap()))
|
.map(|id| (*id, self.tree.height(*id).unwrap()))
|
||||||
.collect();
|
.collect();
|
||||||
listening.sort_by(|(_, h1), (_, h2)| h1.cmp(h2).reverse());
|
listening.sort_by(|(_, h1), (_, h2)| h1.cmp(h2).reverse());
|
||||||
listening.into_iter().map(|(id, _)| id).collect()
|
listening
|
||||||
|
.into_iter()
|
||||||
|
.map(|(id, _)| NodeRef { id, dom: self })
|
||||||
|
.collect()
|
||||||
} else {
|
} else {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
@@ -371,7 +374,8 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
|||||||
let new_node = node.node_data().clone();
|
let new_node = node.node_data().clone();
|
||||||
let new_id = self.create_node(new_node, None, true).id();
|
let new_id = self.create_node(new_node, None, true).id();
|
||||||
|
|
||||||
for child in self.tree.children_ids(node_id).unwrap() {
|
let children = self.tree.children_ids(node_id).unwrap().to_vec();
|
||||||
|
for child in children {
|
||||||
let child_id = self.clone_node(child);
|
let child_id = self.clone_node(child);
|
||||||
self.add_child(new_id, child_id);
|
self.add_child(new_id, child_id);
|
||||||
}
|
}
|
||||||
@@ -382,11 +386,13 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
|||||||
self.tree.root()
|
self.tree.root()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, id: NodeId) -> Option<NodeRef<'_, V>> {
|
pub fn get(&self, id: impl IntoNodeId<V>) -> Option<NodeRef<'_, V>> {
|
||||||
|
let id = id.into_node_id(self);
|
||||||
self.tree.contains(id).then_some(NodeRef { id, dom: self })
|
self.tree.contains(id).then_some(NodeRef { id, dom: self })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_mut(&mut self, id: NodeId) -> Option<NodeMut<'_, V>> {
|
pub fn get_mut(&mut self, id: impl IntoNodeId<V>) -> Option<NodeMut<'_, V>> {
|
||||||
|
let id = id.into_node_id(self);
|
||||||
self.tree.contains(id).then(|| NodeMut {
|
self.tree.contains(id).then(|| NodeMut {
|
||||||
id,
|
id,
|
||||||
dirty: NodeMask::default(),
|
dirty: NodeMask::default(),
|
||||||
@@ -395,8 +401,11 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// WARNING: This escapes the reactive system that the real dom uses. Any changes made with this method will not trigger updates in states when [RealDom::update_state] is called.
|
/// WARNING: This escapes the reactive system that the real dom uses. Any changes made with this method will not trigger updates in states when [RealDom::update_state] is called.
|
||||||
pub fn get_mut_raw(&mut self, id: NodeId) -> Option<&mut NodeData<V>> {
|
pub fn get_mut_raw(&mut self, id: impl IntoNodeId<V>) -> Option<NodeMutRaw<V>> {
|
||||||
self.tree.write(id)
|
let id = id.into_node_id(self);
|
||||||
|
self.tree
|
||||||
|
.contains(id)
|
||||||
|
.then_some(NodeMutRaw { id, dom: self })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the state of the dom, after appling some mutations. This will keep the nodes in the dom up to date with their VNode counterparts.
|
/// Update the state of the dom, after appling some mutations. This will keep the nodes in the dom up to date with their VNode counterparts.
|
||||||
@@ -499,7 +508,7 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
|||||||
f(node);
|
f(node);
|
||||||
if let Some(children) = self.tree.children_ids(id) {
|
if let Some(children) = self.tree.children_ids(id) {
|
||||||
for id in children {
|
for id in children {
|
||||||
queue.push_back(id);
|
queue.push_back(*id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -510,10 +519,11 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
|||||||
let mut stack = vec![self.root()];
|
let mut stack = vec![self.root()];
|
||||||
while let Some(id) = stack.pop() {
|
while let Some(id) = stack.pop() {
|
||||||
if let Some(children) = self.tree.children_ids(id) {
|
if let Some(children) = self.tree.children_ids(id) {
|
||||||
|
let children = children.iter().copied().rev().collect::<Vec<_>>();
|
||||||
if let Some(node) = self.get_mut(id) {
|
if let Some(node) = self.get_mut(id) {
|
||||||
let node = node;
|
let node = node;
|
||||||
f(node);
|
f(node);
|
||||||
stack.extend(children.iter().copied().rev());
|
stack.extend(children.iter());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -524,6 +534,7 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
|||||||
queue.push_back(self.root());
|
queue.push_back(self.root());
|
||||||
while let Some(id) = queue.pop_front() {
|
while let Some(id) = queue.pop_front() {
|
||||||
if let Some(children) = self.tree.children_ids(id) {
|
if let Some(children) = self.tree.children_ids(id) {
|
||||||
|
let children = children.to_vec();
|
||||||
if let Some(node) = self.get_mut(id) {
|
if let Some(node) = self.get_mut(id) {
|
||||||
f(node);
|
f(node);
|
||||||
for id in children {
|
for id in children {
|
||||||
@@ -535,75 +546,116 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl<V: FromAnyValue> Index<ElementId> for RealDom<V> {
|
pub trait IntoNodeId<V: FromAnyValue + Send + Sync> {
|
||||||
// type Output = Node<V>;
|
fn into_node_id(self, rdom: &RealDom<V>) -> NodeId;
|
||||||
|
}
|
||||||
|
|
||||||
// fn index(&self, id: ElementId) -> &Self::Output {
|
impl<V: FromAnyValue + Send + Sync> IntoNodeId<V> for NodeId {
|
||||||
// self.tree.get(self.element_to_node_id(id)).unwrap()
|
fn into_node_id(self, _rdom: &RealDom<V>) -> NodeId {
|
||||||
// }
|
self
|
||||||
// }
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// impl<V: FromAnyValue> Index<NodeId> for RealDom<V> {
|
impl<V: FromAnyValue + Send + Sync> IntoNodeId<V> for ElementId {
|
||||||
// type Output = Node<V>;
|
fn into_node_id(self, rdom: &RealDom<V>) -> NodeId {
|
||||||
|
rdom.element_to_node_id(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// fn index(&self, idx: NodeId) -> &Self::Output {
|
pub trait NodeImmutable<V: FromAnyValue + Send + Sync>: Sized {
|
||||||
// self.tree.get(idx).unwrap()
|
fn real_dom(&self) -> &RealDom<V>;
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// impl<V: FromAnyValue> IndexMut<ElementId> for RealDom<V> {
|
fn id(&self) -> NodeId;
|
||||||
// fn index_mut(&mut self, id: ElementId) -> &mut Self::Output {
|
|
||||||
// self.tree.get_mut(self.element_to_node_id(id)).unwrap()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// impl<V: FromAnyValue> IndexMut<NodeId> for RealDom<V> {
|
fn mounted_id(&self) -> Option<ElementId> {
|
||||||
// fn index_mut(&mut self, idx: NodeId) -> &mut Self::Output {
|
self.node_data().mounted_id()
|
||||||
// self.tree.get_mut(idx).unwrap()
|
}
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
pub struct NodeRef<'a, V: FromAnyValue + Send = ()> {
|
fn node_data(&self) -> &NodeData<V> {
|
||||||
|
self.get().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn node_type(&self) -> &NodeType<V> {
|
||||||
|
&self.node_data().node_type
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get<T: Any>(&self) -> Option<&T> {
|
||||||
|
self.real_dom().tree.get(self.id())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn child_ids(&self) -> Option<&[NodeId]> {
|
||||||
|
self.real_dom().tree.children_ids(self.id())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn children(&self) -> Option<Vec<NodeRef<V>>> {
|
||||||
|
self.child_ids().map(|ids| {
|
||||||
|
ids.iter()
|
||||||
|
.map(|id| NodeRef {
|
||||||
|
id: *id,
|
||||||
|
dom: self.real_dom(),
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parent_id(&self) -> Option<NodeId> {
|
||||||
|
self.real_dom().tree.parent_id(self.id())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parent(&self) -> Option<NodeRef<V>> {
|
||||||
|
self.parent_id().map(|id| NodeRef {
|
||||||
|
id,
|
||||||
|
dom: self.real_dom(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait NodeMutable<V: FromAnyValue + Send + Sync>: Sized + NodeImmutable<V> {
|
||||||
|
fn get_mut<T: Any>(&mut self) -> Option<&mut T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct NodeRef<'a, V: FromAnyValue + Send + Sync = ()> {
|
||||||
id: NodeId,
|
id: NodeId,
|
||||||
dom: &'a RealDom<V>,
|
dom: &'a RealDom<V>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, V: FromAnyValue + Send> NodeRef<'a, V> {
|
impl<'a, V: FromAnyValue + Send + Sync> NodeImmutable<V> for NodeRef<'a, V> {
|
||||||
pub fn node_data(&self) -> &NodeData<V> {
|
fn real_dom(&self) -> &RealDom<V> {
|
||||||
self.read().unwrap()
|
self.dom
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn node_type(&self) -> &NodeType<V> {
|
fn id(&self) -> NodeId {
|
||||||
&self.node_data().node_type
|
self.id
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read<T: Any>(&self) -> Option<&T> {
|
|
||||||
self.dom.tree.read(self.id)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct NodeMut<'a, V: FromAnyValue + Send = ()> {
|
pub struct NodeMut<'a, V: FromAnyValue + Send + Sync = ()> {
|
||||||
id: NodeId,
|
id: NodeId,
|
||||||
dom: &'a mut RealDom<V>,
|
dom: &'a mut RealDom<V>,
|
||||||
dirty: NodeMask,
|
dirty: NodeMask,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, V: FromAnyValue + Send> NodeMut<'a, V> {
|
impl<'a, V: FromAnyValue + Send + Sync> NodeImmutable<V> for NodeMut<'a, V> {
|
||||||
fn node_data(&self) -> &NodeData<V> {
|
fn real_dom(&self) -> &RealDom<V> {
|
||||||
self.read().unwrap()
|
self.dom
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node_data_mut(&mut self) -> &mut NodeData<V> {
|
fn id(&self) -> NodeId {
|
||||||
self.dom.tree.write(self.id).unwrap()
|
self.id
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn node_type(&self) -> &NodeType<V> {
|
impl<'a, V: FromAnyValue + Send + Sync> NodeMutable<V> for NodeMut<'a, V> {
|
||||||
&self.node_data().node_type
|
fn get_mut<T: Any>(&mut self) -> Option<&mut T> {
|
||||||
|
todo!("get_mut with mark as dirty")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> {
|
||||||
pub fn node_type_mut(&mut self) -> NodeTypeMut<'_, V> {
|
pub fn node_type_mut(&mut self) -> NodeTypeMut<'_, V> {
|
||||||
let Self { id, dom, dirty } = self;
|
let Self { id, dom, dirty } = self;
|
||||||
let node_type = &mut dom.tree.write::<NodeData<V>>(*id).unwrap().node_type;
|
let node_type = &mut dom.tree.get_mut::<NodeData<V>>(*id).unwrap().node_type;
|
||||||
match node_type {
|
match node_type {
|
||||||
NodeType::Element(element) => NodeTypeMut::Element(ElementNodeMut { element, dirty }),
|
NodeType::Element(element) => NodeTypeMut::Element(ElementNodeMut { element, dirty }),
|
||||||
NodeType::Text(text) => {
|
NodeType::Text(text) => {
|
||||||
@@ -615,20 +667,16 @@ impl<'a, V: FromAnyValue + Send> NodeMut<'a, V> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_type(&mut self, new: NodeType<V>) {
|
pub fn set_type(&mut self, new: NodeType<V>) {
|
||||||
self.node_data_mut().node_type = new;
|
self.dom
|
||||||
|
.tree
|
||||||
|
.get_mut::<NodeData<V>>(self.id)
|
||||||
|
.unwrap()
|
||||||
|
.node_type = new;
|
||||||
self.dirty = NodeMaskBuilder::ALL.build();
|
self.dirty = NodeMaskBuilder::ALL.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read<T: Any>(&self) -> Option<&T> {
|
|
||||||
self.dom.tree.read(self.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write<T: Any>(&mut self) -> Option<&T> {
|
|
||||||
todo!("get_mut with mark as dirty")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: FromAnyValue + Send> Drop for NodeMut<'_, V> {
|
impl<V: FromAnyValue + Send + Sync> Drop for NodeMut<'_, V> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let node_id = self.node_data().node_id;
|
let node_id = self.node_data().node_id;
|
||||||
let mask = std::mem::take(&mut self.dirty);
|
let mask = std::mem::take(&mut self.dirty);
|
||||||
@@ -716,3 +764,24 @@ impl<V: FromAnyValue> ElementNodeMut<'_, V> {
|
|||||||
&mut self.element.listeners
|
&mut self.element.listeners
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct NodeMutRaw<'a, V: FromAnyValue + Send + Sync = ()> {
|
||||||
|
id: NodeId,
|
||||||
|
dom: &'a mut RealDom<V>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, V: FromAnyValue + Send + Sync> NodeImmutable<V> for NodeMutRaw<'a, V> {
|
||||||
|
fn real_dom(&self) -> &RealDom<V> {
|
||||||
|
self.dom
|
||||||
|
}
|
||||||
|
|
||||||
|
fn id(&self) -> NodeId {
|
||||||
|
self.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, V: FromAnyValue + Send + Sync> NodeMutable<V> for NodeMutRaw<'a, V> {
|
||||||
|
fn get_mut<T: Any>(&mut self) -> Option<&mut T> {
|
||||||
|
self.dom.tree.get_mut::<T>(self.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -164,11 +164,11 @@ impl Tree {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read<T: Any>(&self, id: NodeId) -> Option<&T> {
|
pub fn get<T: Any>(&self, id: NodeId) -> Option<&T> {
|
||||||
self.nodes.read_slab().get(id)
|
self.nodes.read_slab().get(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write<T: Any>(&mut self, id: NodeId) -> Option<&mut T> {
|
pub fn get_mut<T: Any>(&mut self, id: NodeId) -> Option<&mut T> {
|
||||||
self.nodes.write_slab().get_mut(id)
|
self.nodes.write_slab().get_mut(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,8 +184,8 @@ impl Tree {
|
|||||||
self.get_node_data(id).parent
|
self.get_node_data(id).parent
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn children_ids(&self, id: NodeId) -> Option<Vec<NodeId>> {
|
pub fn children_ids(&self, id: NodeId) -> Option<&[NodeId]> {
|
||||||
Some(self.get_node_data(id).children.clone())
|
Some(&self.get_node_data(id).children)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn height(&self, id: NodeId) -> Option<u16> {
|
pub fn height(&self, id: NodeId) -> Option<u16> {
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
// mod persistant_iterator;
|
mod persistant_iterator;
|
||||||
// pub use persistant_iterator::*;
|
pub use persistant_iterator::*;
|
||||||
pub mod cursor;
|
pub mod cursor;
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
node::{ElementNode, FromAnyValue, NodeType},
|
node::{ElementNode, FromAnyValue, NodeType},
|
||||||
passes::{AnyMapLike, TypeErasedPass},
|
real_dom::{NodeImmutable, RealDom},
|
||||||
real_dom::RealDom,
|
|
||||||
NodeId,
|
NodeId,
|
||||||
};
|
};
|
||||||
use dioxus_core::{Mutation, Mutations};
|
use dioxus_core::{Mutation, Mutations};
|
||||||
@@ -72,10 +71,10 @@ impl PersistantElementIter {
|
|||||||
|
|
||||||
/// remove stale element refreneces
|
/// remove stale element refreneces
|
||||||
/// returns true if the focused element is removed
|
/// returns true if the focused element is removed
|
||||||
pub fn prune<S: State<V>, V: FromAnyValue>(
|
pub fn prune<V: FromAnyValue + Send + Sync>(
|
||||||
&mut self,
|
&mut self,
|
||||||
mutations: &Mutations,
|
mutations: &Mutations,
|
||||||
rdom: &RealDom<S, V>,
|
rdom: &RealDom<V>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let mut changed = false;
|
let mut changed = false;
|
||||||
let ids_removed: Vec<_> = mutations
|
let ids_removed: Vec<_> = mutations
|
||||||
@@ -102,7 +101,7 @@ impl PersistantElementIter {
|
|||||||
// if a child is removed or inserted before or at the current element, update the child index
|
// if a child is removed or inserted before or at the current element, update the child index
|
||||||
for (el_id, child_idx) in self.stack.iter_mut() {
|
for (el_id, child_idx) in self.stack.iter_mut() {
|
||||||
if let NodePosition::InChild(child_idx) = child_idx {
|
if let NodePosition::InChild(child_idx) = child_idx {
|
||||||
if let Some(children) = &rdom.children_ids(*el_id) {
|
if let Some(children) = &rdom.get(*el_id).unwrap().child_ids() {
|
||||||
for m in &mutations.edits {
|
for m in &mutations.edits {
|
||||||
match m {
|
match m {
|
||||||
Mutation::Remove { id } => {
|
Mutation::Remove { id } => {
|
||||||
@@ -133,7 +132,7 @@ impl PersistantElementIter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// get the next element
|
/// get the next element
|
||||||
pub fn next<S: State<V>, V: FromAnyValue>(&mut self, rdom: &RealDom<S, V>) -> ElementProduced {
|
pub fn next<V: FromAnyValue + Send + Sync>(&mut self, rdom: &RealDom<V>) -> ElementProduced {
|
||||||
if self.stack.is_empty() {
|
if self.stack.is_empty() {
|
||||||
let id = NodeId(0);
|
let id = NodeId(0);
|
||||||
let new = (id, NodePosition::AtNode);
|
let new = (id, NodePosition::AtNode);
|
||||||
@@ -142,9 +141,9 @@ impl PersistantElementIter {
|
|||||||
} else {
|
} else {
|
||||||
let (last, old_child_idx) = self.stack.last_mut().unwrap();
|
let (last, old_child_idx) = self.stack.last_mut().unwrap();
|
||||||
let node = rdom.get(*last).unwrap();
|
let node = rdom.get(*last).unwrap();
|
||||||
match &node.node_data.node_type {
|
match &node.node_data().node_type {
|
||||||
NodeType::Element(ElementNode { .. }) => {
|
NodeType::Element(ElementNode { .. }) => {
|
||||||
let children = rdom.children_ids(*last).unwrap();
|
let children = node.child_ids().unwrap();
|
||||||
*old_child_idx = old_child_idx.map(|i| i + 1);
|
*old_child_idx = old_child_idx.map(|i| i + 1);
|
||||||
// if we have children, go to the next child
|
// if we have children, go to the next child
|
||||||
let child_idx = old_child_idx.get_or_insert(0);
|
let child_idx = old_child_idx.get_or_insert(0);
|
||||||
@@ -154,7 +153,7 @@ impl PersistantElementIter {
|
|||||||
} else {
|
} else {
|
||||||
let id = children[child_idx];
|
let id = children[child_idx];
|
||||||
if let NodeType::Element(ElementNode { .. }) =
|
if let NodeType::Element(ElementNode { .. }) =
|
||||||
rdom.get(id).unwrap().node_data.node_type
|
rdom.get(id).unwrap().node_data().node_type
|
||||||
{
|
{
|
||||||
self.stack.push((id, NodePosition::AtNode));
|
self.stack.push((id, NodePosition::AtNode));
|
||||||
}
|
}
|
||||||
@@ -171,19 +170,17 @@ impl PersistantElementIter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// get the previous element
|
/// get the previous element
|
||||||
pub fn prev<S: State<V> + Send, V: FromAnyValue>(
|
pub fn prev<V: FromAnyValue + Send + Sync>(&mut self, rdom: &RealDom<V>) -> ElementProduced {
|
||||||
&mut self,
|
|
||||||
rdom: &RealDom<S, V>,
|
|
||||||
) -> ElementProduced {
|
|
||||||
// recursively add the last child element to the stack
|
// recursively add the last child element to the stack
|
||||||
fn push_back<S: State<V> + Send, V: FromAnyValue>(
|
fn push_back<V: FromAnyValue + Send + Sync>(
|
||||||
stack: &mut smallvec::SmallVec<[(NodeId, NodePosition); 5]>,
|
stack: &mut smallvec::SmallVec<[(NodeId, NodePosition); 5]>,
|
||||||
new_node: NodeId,
|
new_node: NodeId,
|
||||||
rdom: &RealDom<S, V>,
|
rdom: &RealDom<V>,
|
||||||
) -> NodeId {
|
) -> NodeId {
|
||||||
match &rdom[new_node].node_data.node_type {
|
let node = rdom.get(new_node).unwrap();
|
||||||
|
match &node.node_data().node_type {
|
||||||
NodeType::Element(ElementNode { .. }) => {
|
NodeType::Element(ElementNode { .. }) => {
|
||||||
let children = rdom.children_ids(new_node).unwrap();
|
let children = node.child_ids().unwrap();
|
||||||
if children.is_empty() {
|
if children.is_empty() {
|
||||||
new_node
|
new_node
|
||||||
} else {
|
} else {
|
||||||
@@ -199,10 +196,10 @@ impl PersistantElementIter {
|
|||||||
ElementProduced::Looped(push_back(&mut self.stack, new_node, rdom))
|
ElementProduced::Looped(push_back(&mut self.stack, new_node, rdom))
|
||||||
} else {
|
} else {
|
||||||
let (last, old_child_idx) = self.stack.last_mut().unwrap();
|
let (last, old_child_idx) = self.stack.last_mut().unwrap();
|
||||||
let node = &rdom[*last];
|
let node = rdom.get(*last).unwrap();
|
||||||
match &node.node_data.node_type {
|
match &node.node_data().node_type {
|
||||||
NodeType::Element(ElementNode { .. }) => {
|
NodeType::Element(ElementNode { .. }) => {
|
||||||
let children = rdom.children_ids(*last).unwrap();
|
let children = node.child_ids().unwrap();
|
||||||
// if we have children, go to the next child
|
// if we have children, go to the next child
|
||||||
if let NodePosition::InChild(0) = old_child_idx {
|
if let NodePosition::InChild(0) = old_child_idx {
|
||||||
ElementProduced::Progressed(self.pop())
|
ElementProduced::Progressed(self.pop())
|
||||||
@@ -240,23 +237,6 @@ impl PersistantElementIter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone, Debug)]
|
|
||||||
struct Empty {}
|
|
||||||
impl AnyMapLike for Empty {
|
|
||||||
fn get<T: std::any::Any>(&self) -> Option<&T> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_mut<T: std::any::Any>(&mut self) -> Option<&mut T> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl State for Empty {
|
|
||||||
fn create_passes() -> Box<[TypeErasedPass<Self>]> {
|
|
||||||
Box::new([])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn traverse() {
|
fn traverse() {
|
||||||
@@ -279,7 +259,7 @@ fn traverse() {
|
|||||||
let mut vdom = VirtualDom::new(Base);
|
let mut vdom = VirtualDom::new(Base);
|
||||||
let mutations = vdom.rebuild();
|
let mutations = vdom.rebuild();
|
||||||
|
|
||||||
let mut rdom: RealDom<Empty> = RealDom::new();
|
let mut rdom: RealDom = RealDom::new(Box::new([]));
|
||||||
|
|
||||||
let _to_update = rdom.apply_mutations(mutations);
|
let _to_update = rdom.apply_mutations(mutations);
|
||||||
|
|
||||||
@@ -378,7 +358,7 @@ fn persist_removes() {
|
|||||||
}
|
}
|
||||||
let mut vdom = VirtualDom::new(Base);
|
let mut vdom = VirtualDom::new(Base);
|
||||||
|
|
||||||
let mut rdom: RealDom<Empty> = RealDom::new();
|
let mut rdom: RealDom = RealDom::new(Box::new([]));
|
||||||
|
|
||||||
let build = vdom.rebuild();
|
let build = vdom.rebuild();
|
||||||
println!("{:#?}", build);
|
println!("{:#?}", build);
|
||||||
@@ -460,7 +440,7 @@ fn persist_instertions_before() {
|
|||||||
}
|
}
|
||||||
let mut vdom = VirtualDom::new(Base);
|
let mut vdom = VirtualDom::new(Base);
|
||||||
|
|
||||||
let mut rdom: RealDom<Empty> = RealDom::new();
|
let mut rdom: RealDom = RealDom::new(Box::new([]));
|
||||||
|
|
||||||
let build = vdom.rebuild();
|
let build = vdom.rebuild();
|
||||||
let _to_update = rdom.apply_mutations(build);
|
let _to_update = rdom.apply_mutations(build);
|
||||||
@@ -516,7 +496,7 @@ fn persist_instertions_after() {
|
|||||||
}
|
}
|
||||||
let mut vdom = VirtualDom::new(Base);
|
let mut vdom = VirtualDom::new(Base);
|
||||||
|
|
||||||
let mut rdom: RealDom<Empty> = RealDom::new();
|
let mut rdom: RealDom = RealDom::new(Box::new([]));
|
||||||
|
|
||||||
let build = vdom.rebuild();
|
let build = vdom.rebuild();
|
||||||
let _to_update = rdom.apply_mutations(build);
|
let _to_update = rdom.apply_mutations(build);
|
||||||
|
|||||||
+41
-38
@@ -1,15 +1,17 @@
|
|||||||
use crate::{node::PreventDefault, TuiDom};
|
use crate::node::PreventDefault;
|
||||||
|
|
||||||
use dioxus_native_core::{
|
use dioxus_native_core::{
|
||||||
tree::TreeView,
|
node_ref::{AttributeMaskBuilder, NodeMaskBuilder},
|
||||||
|
real_dom::{NodeImmutable, NodeMutable},
|
||||||
utils::{ElementProduced, PersistantElementIter},
|
utils::{ElementProduced, PersistantElementIter},
|
||||||
NodeId, Pass, SendAnyMap,
|
Dependancy, NodeId, Pass, RealDom, SendAnyMap,
|
||||||
};
|
};
|
||||||
use dioxus_native_core_macro::sorted_str_slice;
|
|
||||||
|
|
||||||
use std::{cmp::Ordering, num::NonZeroU16};
|
use std::{cmp::Ordering, num::NonZeroU16};
|
||||||
|
|
||||||
use dioxus_native_core::node_ref::{AttributeMask, NodeMask, NodeView};
|
use dioxus_native_core::node_ref::NodeView;
|
||||||
|
|
||||||
|
pub struct Focused(pub bool);
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
pub(crate) enum FocusLevel {
|
pub(crate) enum FocusLevel {
|
||||||
@@ -62,8 +64,9 @@ pub(crate) struct Focus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Pass for Focus {
|
impl Pass for Focus {
|
||||||
const NODE_MASK: NodeMask =
|
const NODE_MASK: NodeMaskBuilder = NodeMaskBuilder::new()
|
||||||
NodeMask::new_with_attrs(AttributeMask::Static(FOCUS_ATTRIBUTES)).with_listeners();
|
.with_attrs(AttributeMaskBuilder::Some(FOCUS_ATTRIBUTES))
|
||||||
|
.with_listeners();
|
||||||
|
|
||||||
type ParentDependencies = ();
|
type ParentDependencies = ();
|
||||||
type ChildDependencies = ();
|
type ChildDependencies = ();
|
||||||
@@ -72,18 +75,10 @@ impl Pass for Focus {
|
|||||||
fn pass<'a>(
|
fn pass<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
node_view: NodeView,
|
node_view: NodeView,
|
||||||
_: <Self::NodeDependencies as dioxus_native_core::Dependancy>::ElementBorrowed<'a>,
|
node: <Self::NodeDependencies as Dependancy>::ElementBorrowed<'a>,
|
||||||
_: Option<
|
parent: Option<<Self::ParentDependencies as Dependancy>::ElementBorrowed<'a>>,
|
||||||
<Self::ParentDependencies as dioxus_native_core::Dependancy>::ElementBorrowed<'a>,
|
children: Option<Vec<<Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>>,
|
||||||
>,
|
context: &SendAnyMap,
|
||||||
_: Option<
|
|
||||||
impl Iterator<
|
|
||||||
Item = <Self::ChildDependencies as dioxus_native_core::Dependancy>::ElementBorrowed<
|
|
||||||
'a,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
_: &SendAnyMap,
|
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let new = Focus {
|
let new = Focus {
|
||||||
level: if let Some(a) = node_view
|
level: if let Some(a) = node_view
|
||||||
@@ -128,8 +123,8 @@ impl Pass for Focus {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const FOCUS_EVENTS: &[&str] = &sorted_str_slice!(["keydown", "keypress", "keyup"]);
|
const FOCUS_EVENTS: &[&str] = &["keydown", "keypress", "keyup"];
|
||||||
const FOCUS_ATTRIBUTES: &[&str] = &sorted_str_slice!(["tabindex"]);
|
const FOCUS_ATTRIBUTES: &[&str] = &["tabindex"];
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub(crate) struct FocusState {
|
pub(crate) struct FocusState {
|
||||||
@@ -141,9 +136,11 @@ pub(crate) struct FocusState {
|
|||||||
|
|
||||||
impl FocusState {
|
impl FocusState {
|
||||||
/// Returns true if the focus has changed.
|
/// Returns true if the focus has changed.
|
||||||
pub fn progress(&mut self, rdom: &mut TuiDom, 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 {
|
||||||
if rdom[last].state.prevent_default == PreventDefault::KeyDown {
|
if rdom.get(last).unwrap().get::<PreventDefault>().copied()
|
||||||
|
== Some(PreventDefault::KeyDown)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -165,7 +162,7 @@ impl FocusState {
|
|||||||
if forward {
|
if forward {
|
||||||
// find the closest focusable element after the current level
|
// find the closest focusable element after the current level
|
||||||
rdom.traverse_depth_first(|n| {
|
rdom.traverse_depth_first(|n| {
|
||||||
let node_level = n.state.focus.level;
|
let node_level = n.get::<Focus>().unwrap().level;
|
||||||
if node_level != *focus_level
|
if node_level != *focus_level
|
||||||
&& node_level.focusable()
|
&& node_level.focusable()
|
||||||
&& node_level > *focus_level
|
&& node_level > *focus_level
|
||||||
@@ -182,7 +179,7 @@ impl FocusState {
|
|||||||
} else {
|
} else {
|
||||||
// find the closest focusable element before the current level
|
// find the closest focusable element before the current level
|
||||||
rdom.traverse_depth_first(|n| {
|
rdom.traverse_depth_first(|n| {
|
||||||
let node_level = n.state.focus.level;
|
let node_level = n.get::<Focus>().unwrap().level;
|
||||||
if node_level != *focus_level
|
if node_level != *focus_level
|
||||||
&& node_level.focusable()
|
&& node_level.focusable()
|
||||||
&& node_level < *focus_level
|
&& node_level < *focus_level
|
||||||
@@ -219,7 +216,7 @@ impl FocusState {
|
|||||||
loop_marker_id = Some(new_id);
|
loop_marker_id = Some(new_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
let current_level = rdom[new_id].state.focus.level;
|
let current_level = rdom.get(new_id).unwrap().get::<Focus>().unwrap().level;
|
||||||
let after_previous_focused = if forward {
|
let after_previous_focused = if forward {
|
||||||
current_level >= *focus_level
|
current_level >= *focus_level
|
||||||
} else {
|
} else {
|
||||||
@@ -233,12 +230,16 @@ impl FocusState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(id) = next_focus {
|
if let Some(id) = next_focus {
|
||||||
if !rdom[id].state.focus.level.focusable() {
|
let mut node = rdom.get_mut_raw(id).unwrap();
|
||||||
|
if !node.get::<Focus>().unwrap().level.focusable() {
|
||||||
panic!()
|
panic!()
|
||||||
}
|
}
|
||||||
rdom[id].state.focused = true;
|
let focused = node.get_mut::<Focused>().unwrap();
|
||||||
|
focused.0 = true;
|
||||||
if let Some(old) = self.last_focused_id.replace(id) {
|
if let Some(old) = self.last_focused_id.replace(id) {
|
||||||
rdom[old].state.focused = false;
|
let mut old = rdom.get_mut_raw(old).unwrap();
|
||||||
|
let focused = old.get_mut::<Focused>().unwrap();
|
||||||
|
focused.0 = false;
|
||||||
}
|
}
|
||||||
// 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 {}
|
||||||
@@ -249,8 +250,8 @@ impl FocusState {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn prune(&mut self, mutations: &dioxus_core::Mutations, rdom: &TuiDom) {
|
pub(crate) fn prune(&mut self, mutations: &dioxus_core::Mutations, rdom: &RealDom) {
|
||||||
fn remove_children(to_prune: &mut [&mut Option<NodeId>], rdom: &TuiDom, removed: NodeId) {
|
fn remove_children(to_prune: &mut [&mut Option<NodeId>], rdom: &RealDom, removed: NodeId) {
|
||||||
for opt in to_prune.iter_mut() {
|
for opt in to_prune.iter_mut() {
|
||||||
if let Some(id) = opt {
|
if let Some(id) = opt {
|
||||||
if *id == removed {
|
if *id == removed {
|
||||||
@@ -258,8 +259,9 @@ impl FocusState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(children) = &rdom.children_ids(removed) {
|
let node = rdom.get(removed).unwrap();
|
||||||
for child in *children {
|
if let Some(children) = node.child_ids() {
|
||||||
|
for child in children {
|
||||||
remove_children(to_prune, rdom, *child);
|
remove_children(to_prune, rdom, *child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -284,13 +286,14 @@ impl FocusState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn set_focus(&mut self, rdom: &mut TuiDom, 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) {
|
||||||
rdom[old].state.focused = false;
|
let mut node = rdom.get_mut_raw(old).unwrap();
|
||||||
|
node.get_mut::<Focused>().unwrap().0 = false;
|
||||||
}
|
}
|
||||||
let state = &mut rdom[id].state;
|
let mut node = &mut rdom.get_mut_raw(id).unwrap();
|
||||||
state.focused = true;
|
node.get_mut::<Focused>().unwrap().0 = true;
|
||||||
self.focus_level = state.focus.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 {}
|
||||||
self.dirty = true;
|
self.dirty = true;
|
||||||
|
|||||||
+31
-23
@@ -2,8 +2,8 @@ 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_core::*;
|
||||||
use dioxus_native_core::tree::TreeView;
|
use dioxus_native_core::real_dom::NodeImmutable;
|
||||||
use dioxus_native_core::NodeId;
|
use dioxus_native_core::{NodeId, NodeRef, RealDom};
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
|
|
||||||
use dioxus_html::geometry::euclid::{Point2D, Rect, Size2D};
|
use dioxus_html::geometry::euclid::{Point2D, Rect, Size2D};
|
||||||
@@ -23,8 +23,9 @@ use std::{
|
|||||||
use taffy::geometry::{Point, Size};
|
use taffy::geometry::{Point, Size};
|
||||||
use taffy::{prelude::Layout, Taffy};
|
use taffy::{prelude::Layout, Taffy};
|
||||||
|
|
||||||
|
use crate::focus::{Focus, Focused};
|
||||||
|
use crate::layout::TaffyLayout;
|
||||||
use crate::{layout_to_screen_space, FocusState};
|
use crate::{layout_to_screen_space, FocusState};
|
||||||
use crate::{TuiDom, TuiNode};
|
|
||||||
|
|
||||||
pub(crate) struct Event {
|
pub(crate) struct Event {
|
||||||
pub id: ElementId,
|
pub id: ElementId,
|
||||||
@@ -173,7 +174,7 @@ impl InnerInputState {
|
|||||||
evts: &mut Vec<EventCore>,
|
evts: &mut Vec<EventCore>,
|
||||||
resolved_events: &mut Vec<Event>,
|
resolved_events: &mut Vec<Event>,
|
||||||
layout: &Taffy,
|
layout: &Taffy,
|
||||||
dom: &mut TuiDom,
|
dom: &mut RealDom,
|
||||||
) {
|
) {
|
||||||
let previous_mouse = self.mouse.clone();
|
let previous_mouse = self.mouse.clone();
|
||||||
|
|
||||||
@@ -201,7 +202,7 @@ 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 {
|
if let Some(id) = element.node_data().element_id {
|
||||||
resolved_events.push(Event {
|
resolved_events.push(Event {
|
||||||
name: "focus",
|
name: "focus",
|
||||||
id,
|
id,
|
||||||
@@ -218,7 +219,7 @@ impl InnerInputState {
|
|||||||
}
|
}
|
||||||
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 {
|
if let Some(id) = element.node_data().element_id {
|
||||||
resolved_events.push(Event {
|
resolved_events.push(Event {
|
||||||
name: "focusout",
|
name: "focusout",
|
||||||
id,
|
id,
|
||||||
@@ -239,7 +240,7 @@ impl InnerInputState {
|
|||||||
previous_mouse: Option<MouseData>,
|
previous_mouse: Option<MouseData>,
|
||||||
resolved_events: &mut Vec<Event>,
|
resolved_events: &mut Vec<Event>,
|
||||||
layout: &Taffy,
|
layout: &Taffy,
|
||||||
dom: &mut TuiDom,
|
dom: &mut RealDom,
|
||||||
) {
|
) {
|
||||||
fn layout_contains_point(layout: &Layout, point: ScreenPoint) -> bool {
|
fn layout_contains_point(layout: &Layout, point: ScreenPoint) -> bool {
|
||||||
let Point { x, y } = layout.location;
|
let Point { x, y } = layout.location;
|
||||||
@@ -262,17 +263,17 @@ impl InnerInputState {
|
|||||||
data: Rc<dyn Any>,
|
data: Rc<dyn Any>,
|
||||||
will_bubble: &mut FxHashSet<NodeId>,
|
will_bubble: &mut FxHashSet<NodeId>,
|
||||||
resolved_events: &mut Vec<Event>,
|
resolved_events: &mut Vec<Event>,
|
||||||
node: &TuiNode,
|
node: NodeRef,
|
||||||
dom: &TuiDom,
|
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.node_data().node_id;
|
||||||
if will_bubble.insert(id) {
|
if will_bubble.insert(id) {
|
||||||
let mut parent = dom.parent(id);
|
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.node_data().node_id;
|
||||||
will_bubble.insert(parent_id);
|
will_bubble.insert(parent_id);
|
||||||
parent = dom.parent(parent_id);
|
parent = current_parent.parent_id().and_then(|id| dom.get(id));
|
||||||
}
|
}
|
||||||
if let Some(id) = node.mounted_id() {
|
if let Some(id) = node.mounted_id() {
|
||||||
resolved_events.push(Event {
|
resolved_events.push(Event {
|
||||||
@@ -564,11 +565,13 @@ impl InnerInputState {
|
|||||||
if was_released {
|
if was_released {
|
||||||
let mut focus_id = None;
|
let mut focus_id = None;
|
||||||
dom.traverse_depth_first(|node| {
|
dom.traverse_depth_first(|node| {
|
||||||
let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
|
let node_layout = layout
|
||||||
|
.layout(node.get::<TaffyLayout>().unwrap().node.unwrap())
|
||||||
|
.unwrap();
|
||||||
let currently_contains = layout_contains_point(node_layout, new_pos);
|
let currently_contains = layout_contains_point(node_layout, new_pos);
|
||||||
|
|
||||||
if currently_contains && node.state.focus.level.focusable() {
|
if currently_contains && node.get::<Focus>().unwrap().level.focusable() {
|
||||||
focus_id = Some(node.node_data.node_id);
|
focus_id = Some(node.node_data().node_id);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if let Some(id) = focus_id {
|
if let Some(id) = focus_id {
|
||||||
@@ -583,13 +586,18 @@ impl InnerInputState {
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_abs_layout(node: &TuiNode, dom: &TuiDom, taffy: &Taffy) -> Layout {
|
fn get_abs_layout(node: NodeRef, dom: &RealDom, taffy: &Taffy) -> Layout {
|
||||||
let mut node_layout = *taffy.layout(node.state.layout.node.unwrap()).unwrap();
|
let mut node_layout = *taffy
|
||||||
|
.layout(node.get::<TaffyLayout>().unwrap().node.unwrap())
|
||||||
|
.unwrap();
|
||||||
let mut current = node;
|
let mut current = node;
|
||||||
|
|
||||||
while let Some(parent) = dom.parent(current.node_data.node_id) {
|
while let Some(parent) = current.parent_id() {
|
||||||
|
let parent = dom.get(parent).unwrap();
|
||||||
current = parent;
|
current = parent;
|
||||||
let parent_layout = taffy.layout(parent.state.layout.node.unwrap()).unwrap();
|
let parent_layout = taffy
|
||||||
|
.layout(parent.get::<TaffyLayout>().unwrap().node.unwrap())
|
||||||
|
.unwrap();
|
||||||
node_layout.location.x += parent_layout.location.x;
|
node_layout.location.x += parent_layout.location.x;
|
||||||
node_layout.location.y += parent_layout.location.y;
|
node_layout.location.y += parent_layout.location.y;
|
||||||
}
|
}
|
||||||
@@ -632,11 +640,11 @@ impl RinkInputHandler {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn prune(&self, mutations: &dioxus_core::Mutations, rdom: &TuiDom) {
|
pub(crate) fn prune(&self, mutations: &dioxus_core::Mutations, rdom: &RealDom) {
|
||||||
self.state.borrow_mut().focus_state.prune(mutations, rdom);
|
self.state.borrow_mut().focus_state.prune(mutations, rdom);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_events(&self, layout: &Taffy, dom: &mut TuiDom) -> 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();
|
||||||
|
|
||||||
(*self.state).borrow_mut().update(
|
(*self.state).borrow_mut().update(
|
||||||
@@ -680,7 +688,7 @@ impl RinkInputHandler {
|
|||||||
for (event, datas) in hm {
|
for (event, datas) in hm {
|
||||||
for node in dom.get_listening_sorted(event) {
|
for node in dom.get_listening_sorted(event) {
|
||||||
for data in &datas {
|
for data in &datas {
|
||||||
if node.state.focused {
|
if node.get::<Focused>().unwrap().0 {
|
||||||
if let Some(id) = node.mounted_id() {
|
if let Some(id) = node.mounted_id() {
|
||||||
resolved_events.push(Event {
|
resolved_events.push(Event {
|
||||||
name: event,
|
name: event,
|
||||||
|
|||||||
+11
-19
@@ -4,9 +4,8 @@ use dioxus_native_core::layout_attributes::{
|
|||||||
apply_layout_attributes_cfg, BorderWidths, LayoutConfigeration,
|
apply_layout_attributes_cfg, BorderWidths, LayoutConfigeration,
|
||||||
};
|
};
|
||||||
use dioxus_native_core::node::OwnedAttributeView;
|
use dioxus_native_core::node::OwnedAttributeView;
|
||||||
use dioxus_native_core::node_ref::{AttributeMask, NodeMask, NodeView};
|
use dioxus_native_core::node_ref::{AttributeMaskBuilder, NodeMaskBuilder, NodeView};
|
||||||
use dioxus_native_core::{Pass, SendAnyMap};
|
use dioxus_native_core::{Dependancy, Pass, SendAnyMap};
|
||||||
use dioxus_native_core_macro::sorted_str_slice;
|
|
||||||
use taffy::prelude::*;
|
use taffy::prelude::*;
|
||||||
|
|
||||||
use crate::{screen_to_layout_space, unit_to_layout_space};
|
use crate::{screen_to_layout_space, unit_to_layout_space};
|
||||||
@@ -48,23 +47,16 @@ impl Pass for TaffyLayout {
|
|||||||
type ParentDependencies = ();
|
type ParentDependencies = ();
|
||||||
type NodeDependencies = ();
|
type NodeDependencies = ();
|
||||||
|
|
||||||
const NODE_MASK: NodeMask =
|
const NODE_MASK: NodeMaskBuilder = NodeMaskBuilder::new()
|
||||||
NodeMask::new_with_attrs(AttributeMask::Static(SORTED_LAYOUT_ATTRS)).with_text();
|
.with_attrs(AttributeMaskBuilder::Some(SORTED_LAYOUT_ATTRS))
|
||||||
|
.with_text();
|
||||||
|
|
||||||
fn pass<'a>(
|
fn pass<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
node_view: NodeView,
|
node_view: NodeView,
|
||||||
_: <Self::NodeDependencies as dioxus_native_core::Dependancy>::ElementBorrowed<'a>,
|
node: <Self::NodeDependencies as Dependancy>::ElementBorrowed<'a>,
|
||||||
_: Option<
|
parent: Option<<Self::ParentDependencies as Dependancy>::ElementBorrowed<'a>>,
|
||||||
<Self::ParentDependencies as dioxus_native_core::Dependancy>::ElementBorrowed<'a>,
|
children: Option<Vec<<Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>>,
|
||||||
>,
|
|
||||||
children: Option<
|
|
||||||
impl Iterator<
|
|
||||||
Item = <Self::ChildDependencies as dioxus_native_core::Dependancy>::ElementBorrowed<
|
|
||||||
'a,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
ctx: &SendAnyMap,
|
ctx: &SendAnyMap,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let mut changed = false;
|
let mut changed = false;
|
||||||
@@ -203,7 +195,7 @@ impl Pass for TaffyLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// these are the attributes in layout_attiributes in native-core
|
// these are the attributes in layout_attiributes in native-core
|
||||||
const SORTED_LAYOUT_ATTRS: &[&str] = &sorted_str_slice!([
|
const SORTED_LAYOUT_ATTRS: &[&str] = &[
|
||||||
"align-content",
|
"align-content",
|
||||||
"align-items",
|
"align-items",
|
||||||
"align-self",
|
"align-self",
|
||||||
@@ -355,5 +347,5 @@ const SORTED_LAYOUT_ATTRS: &[&str] = &sorted_str_slice!([
|
|||||||
"word-break",
|
"word-break",
|
||||||
"word-spacing",
|
"word-spacing",
|
||||||
"word-wrap",
|
"word-wrap",
|
||||||
"z-index"
|
"z-index",
|
||||||
]);
|
];
|
||||||
+17
-6
@@ -6,6 +6,7 @@ use crossterm::{
|
|||||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||||
};
|
};
|
||||||
use dioxus_core::*;
|
use dioxus_core::*;
|
||||||
|
use dioxus_native_core::{node_ref::NodeMaskBuilder, real_dom::NodeImmutable, Pass};
|
||||||
use dioxus_native_core::{real_dom::RealDom, FxDashSet, NodeId, NodeMask, SendAnyMap};
|
use dioxus_native_core::{real_dom::RealDom, FxDashSet, NodeId, NodeMask, SendAnyMap};
|
||||||
use focus::FocusState;
|
use focus::FocusState;
|
||||||
use futures::{
|
use futures::{
|
||||||
@@ -13,6 +14,7 @@ use futures::{
|
|||||||
pin_mut, StreamExt,
|
pin_mut, StreamExt,
|
||||||
};
|
};
|
||||||
use futures_channel::mpsc::unbounded;
|
use futures_channel::mpsc::unbounded;
|
||||||
|
use layout::TaffyLayout;
|
||||||
use query::Query;
|
use query::Query;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::{
|
use std::{
|
||||||
@@ -101,7 +103,9 @@ pub fn launch_cfg_with_props<Props: 'static>(app: Component<Props>, props: Props
|
|||||||
}
|
}
|
||||||
|
|
||||||
let cx = dom.base_scope();
|
let cx = dom.base_scope();
|
||||||
let rdom = Rc::new(RefCell::new(RealDom::new()));
|
let rdom = Rc::new(RefCell::new(RealDom::new(Box::new([
|
||||||
|
TaffyLayout::to_type_erased(),
|
||||||
|
]))));
|
||||||
let taffy = Arc::new(Mutex::new(Taffy::new()));
|
let taffy = Arc::new(Mutex::new(Taffy::new()));
|
||||||
cx.provide_context(state);
|
cx.provide_context(state);
|
||||||
cx.provide_context(TuiContext { tx: event_tx_clone });
|
cx.provide_context(TuiContext { tx: event_tx_clone });
|
||||||
@@ -136,7 +140,7 @@ fn render_vdom(
|
|||||||
mut event_reciever: UnboundedReceiver<InputEvent>,
|
mut event_reciever: UnboundedReceiver<InputEvent>,
|
||||||
handler: RinkInputHandler,
|
handler: RinkInputHandler,
|
||||||
cfg: Config,
|
cfg: Config,
|
||||||
rdom: Rc<RefCell<TuiDom>>,
|
rdom: Rc<RefCell<RealDom>>,
|
||||||
taffy: Arc<Mutex<Taffy>>,
|
taffy: Arc<Mutex<Taffy>>,
|
||||||
mut register_event: impl FnMut(crossterm::event::Event),
|
mut register_event: impl FnMut(crossterm::event::Event),
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
@@ -177,10 +181,16 @@ fn render_vdom(
|
|||||||
|
|
||||||
if !to_rerender.is_empty() || updated {
|
if !to_rerender.is_empty() || updated {
|
||||||
updated = false;
|
updated = false;
|
||||||
fn resize(dims: Rect, taffy: &mut Taffy, rdom: &TuiDom) {
|
fn resize(dims: Rect, taffy: &mut Taffy, rdom: &RealDom) {
|
||||||
let width = screen_to_layout_space(dims.width);
|
let width = screen_to_layout_space(dims.width);
|
||||||
let height = screen_to_layout_space(dims.height);
|
let height = screen_to_layout_space(dims.height);
|
||||||
let root_node = rdom[NodeId(0)].state.layout.node.unwrap();
|
let root_node = rdom
|
||||||
|
.get(NodeId(0))
|
||||||
|
.unwrap()
|
||||||
|
.get::<TaffyLayout>()
|
||||||
|
.unwrap()
|
||||||
|
.node
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// the root node fills the entire area
|
// the root node fills the entire area
|
||||||
|
|
||||||
@@ -204,7 +214,7 @@ fn render_vdom(
|
|||||||
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[NodeId(0)];
|
let root = rdom.get(NodeId(0)).unwrap();
|
||||||
render::render_vnode(frame, &taffy, &rdom, root, cfg, Point::ZERO);
|
render::render_vnode(frame, &taffy, &rdom, root, cfg, Point::ZERO);
|
||||||
})?;
|
})?;
|
||||||
execute!(terminal.backend_mut(), RestorePosition, Show).unwrap();
|
execute!(terminal.backend_mut(), RestorePosition, Show).unwrap();
|
||||||
@@ -277,8 +287,9 @@ fn render_vdom(
|
|||||||
any_map.insert(taffy.clone());
|
any_map.insert(taffy.clone());
|
||||||
let (new_to_rerender, dirty) = rdom.update_state(any_map);
|
let (new_to_rerender, dirty) = rdom.update_state(any_map);
|
||||||
to_rerender = new_to_rerender;
|
to_rerender = new_to_rerender;
|
||||||
|
let text_mask = NodeMaskBuilder::new().with_text().build();
|
||||||
for (id, mask) in dirty {
|
for (id, mask) in dirty {
|
||||||
if mask.overlaps(&NodeMask::new().with_text()) {
|
if mask.overlaps(&text_mask) {
|
||||||
to_rerender.insert(id);
|
to_rerender.insert(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-22
@@ -1,23 +1,18 @@
|
|||||||
use crate::focus::Focus;
|
use crate::focus::Focus;
|
||||||
use crate::layout::TaffyLayout;
|
use crate::layout::TaffyLayout;
|
||||||
use crate::style_attributes::StyleModifier;
|
use crate::style_attributes::StyleModifier;
|
||||||
use dioxus_native_core::{real_dom::RealDom, Dependancy, Pass, SendAnyMap};
|
use dioxus_native_core::{node_ref::NodeView, Dependancy, Pass, SendAnyMap};
|
||||||
use dioxus_native_core_macro::{sorted_str_slice, AnyMapLike, State};
|
|
||||||
|
|
||||||
pub(crate) type TuiDom = RealDom<NodeState>;
|
#[derive(Debug, Clone, Default)]
|
||||||
pub(crate) type TuiNode = dioxus_native_core::node::Node<NodeState>;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, State, AnyMapLike, Default)]
|
|
||||||
pub(crate) struct NodeState {
|
pub(crate) struct NodeState {
|
||||||
pub layout: TaffyLayout,
|
pub layout: TaffyLayout,
|
||||||
pub style: StyleModifier,
|
pub style: StyleModifier,
|
||||||
pub prevent_default: PreventDefault,
|
pub prevent_default: PreventDefault,
|
||||||
pub focus: Focus,
|
pub focus: Focus,
|
||||||
#[skip]
|
|
||||||
pub focused: bool,
|
pub focused: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Debug, Clone)]
|
#[derive(PartialEq, Debug, Clone, Copy)]
|
||||||
pub(crate) enum PreventDefault {
|
pub(crate) enum PreventDefault {
|
||||||
Focus,
|
Focus,
|
||||||
KeyPress,
|
KeyPress,
|
||||||
@@ -47,23 +42,20 @@ impl Pass for PreventDefault {
|
|||||||
type ChildDependencies = ();
|
type ChildDependencies = ();
|
||||||
type NodeDependencies = ();
|
type NodeDependencies = ();
|
||||||
|
|
||||||
const NODE_MASK: dioxus_native_core::node_ref::NodeMask =
|
const NODE_MASK: dioxus_native_core::node_ref::NodeMaskBuilder =
|
||||||
dioxus_native_core::node_ref::NodeMask::new_with_attrs(
|
dioxus_native_core::node_ref::NodeMaskBuilder::new()
|
||||||
dioxus_native_core::node_ref::AttributeMask::Static(&sorted_str_slice!([
|
.with_attrs(dioxus_native_core::node_ref::AttributeMaskBuilder::Some(&[
|
||||||
"dioxus-prevent-default"
|
"dioxus-prevent-default",
|
||||||
])),
|
]))
|
||||||
)
|
.with_listeners();
|
||||||
.with_listeners();
|
|
||||||
|
|
||||||
fn pass<'a>(
|
fn pass<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
node_view: dioxus_native_core::node_ref::NodeView,
|
node_view: NodeView,
|
||||||
_: <Self::NodeDependencies as Dependancy>::ElementBorrowed<'a>,
|
node: <Self::NodeDependencies as Dependancy>::ElementBorrowed<'a>,
|
||||||
_: Option<<Self::ParentDependencies as Dependancy>::ElementBorrowed<'a>>,
|
parent: Option<<Self::ParentDependencies as Dependancy>::ElementBorrowed<'a>>,
|
||||||
_: Option<
|
children: Option<Vec<<Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>>,
|
||||||
impl Iterator<Item = <Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>,
|
context: &SendAnyMap,
|
||||||
>,
|
|
||||||
_: &SendAnyMap,
|
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let new = match node_view.attributes().and_then(|mut attrs| {
|
let new = match node_view.attributes().and_then(|mut attrs| {
|
||||||
attrs
|
attrs
|
||||||
|
|||||||
@@ -5,13 +5,14 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use dioxus_core::ElementId;
|
use dioxus_core::ElementId;
|
||||||
|
use dioxus_native_core::{real_dom::NodeImmutable, RealDom};
|
||||||
use taffy::{
|
use taffy::{
|
||||||
geometry::Point,
|
geometry::Point,
|
||||||
prelude::{Layout, Size},
|
prelude::{Layout, Size},
|
||||||
Taffy,
|
Taffy,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{layout_to_screen_space, TuiDom};
|
use crate::{layout::TaffyLayout, layout_to_screen_space};
|
||||||
|
|
||||||
/// Allows querying the layout of nodes after rendering. It will only provide a correct value after a node is rendered.
|
/// Allows querying the layout of nodes after rendering. It will only provide a correct value after a node is rendered.
|
||||||
/// Provided as a root context for all tui applictions.
|
/// Provided as a root context for all tui applictions.
|
||||||
@@ -46,7 +47,7 @@ use crate::{layout_to_screen_space, TuiDom};
|
|||||||
/// ```
|
/// ```
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Query {
|
pub struct Query {
|
||||||
pub(crate) rdom: Rc<RefCell<TuiDom>>,
|
pub(crate) rdom: Rc<RefCell<RealDom>>,
|
||||||
pub(crate) stretch: Arc<Mutex<Taffy>>,
|
pub(crate) stretch: Arc<Mutex<Taffy>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,13 +62,13 @@ impl Query {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct ElementRef<'a> {
|
pub struct ElementRef<'a> {
|
||||||
inner: Ref<'a, TuiDom>,
|
inner: Ref<'a, RealDom>,
|
||||||
stretch: MutexGuard<'a, Taffy>,
|
stretch: MutexGuard<'a, Taffy>,
|
||||||
id: ElementId,
|
id: ElementId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ElementRef<'a> {
|
impl<'a> ElementRef<'a> {
|
||||||
fn new(inner: Ref<'a, TuiDom>, stretch: MutexGuard<'a, Taffy>, id: ElementId) -> Self {
|
fn new(inner: Ref<'a, RealDom>, stretch: MutexGuard<'a, Taffy>, id: ElementId) -> Self {
|
||||||
Self { inner, stretch, id }
|
Self { inner, stretch, id }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,7 +86,15 @@ impl<'a> ElementRef<'a> {
|
|||||||
pub fn layout(&self) -> Option<Layout> {
|
pub fn layout(&self) -> Option<Layout> {
|
||||||
let layout = self
|
let layout = self
|
||||||
.stretch
|
.stretch
|
||||||
.layout(self.inner[self.id].state.layout.node.ok()?)
|
.layout(
|
||||||
|
self.inner
|
||||||
|
.get(self.id)
|
||||||
|
.unwrap()
|
||||||
|
.get::<TaffyLayout>()
|
||||||
|
.unwrap()
|
||||||
|
.node
|
||||||
|
.ok()?,
|
||||||
|
)
|
||||||
.ok();
|
.ok();
|
||||||
layout.map(|layout| Layout {
|
layout.map(|layout| Layout {
|
||||||
order: layout.order,
|
order: layout.order,
|
||||||
|
|||||||
+30
-20
@@ -1,18 +1,24 @@
|
|||||||
use dioxus_native_core::tree::TreeView;
|
use dioxus_native_core::{real_dom::NodeImmutable, NodeRef, RealDom};
|
||||||
use std::io::Stdout;
|
use std::io::Stdout;
|
||||||
use taffy::{
|
use taffy::{
|
||||||
geometry::Point,
|
geometry::Point,
|
||||||
prelude::{Dimension, Layout, Size},
|
prelude::{Dimension, Layout, Size},
|
||||||
Taffy,
|
Taffy,
|
||||||
};
|
};
|
||||||
use tui::{backend::CrosstermBackend, layout::Rect, style::Color};
|
use tui::{
|
||||||
|
backend::CrosstermBackend,
|
||||||
|
layout::Rect,
|
||||||
|
style::{Color, Style},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
focus::Focused,
|
||||||
|
layout::TaffyLayout,
|
||||||
layout_to_screen_space,
|
layout_to_screen_space,
|
||||||
style::{RinkColor, RinkStyle},
|
style::{RinkColor, RinkStyle},
|
||||||
style_attributes::{BorderEdge, BorderStyle},
|
style_attributes::{BorderEdge, BorderStyle, StyleModifier},
|
||||||
widget::{RinkBuffer, RinkCell, RinkWidget, WidgetWithContext},
|
widget::{RinkBuffer, RinkCell, RinkWidget, WidgetWithContext},
|
||||||
Config, TuiDom, TuiNode,
|
Config,
|
||||||
};
|
};
|
||||||
|
|
||||||
const RADIUS_MULTIPLIER: [f32; 2] = [1.0, 0.5];
|
const RADIUS_MULTIPLIER: [f32; 2] = [1.0, 0.5];
|
||||||
@@ -20,20 +26,22 @@ const RADIUS_MULTIPLIER: [f32; 2] = [1.0, 0.5];
|
|||||||
pub(crate) fn render_vnode(
|
pub(crate) fn render_vnode(
|
||||||
frame: &mut tui::Frame<CrosstermBackend<Stdout>>,
|
frame: &mut tui::Frame<CrosstermBackend<Stdout>>,
|
||||||
layout: &Taffy,
|
layout: &Taffy,
|
||||||
rdom: &TuiDom,
|
rdom: &RealDom,
|
||||||
node: &TuiNode,
|
node: NodeRef,
|
||||||
cfg: Config,
|
cfg: Config,
|
||||||
parent_location: Point<f32>,
|
parent_location: Point<f32>,
|
||||||
) {
|
) {
|
||||||
use dioxus_native_core::node::NodeType;
|
use dioxus_native_core::node::NodeType;
|
||||||
|
|
||||||
if let NodeType::Placeholder = &node.node_data.node_type {
|
if let NodeType::Placeholder = &node.node_type() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let Layout {
|
let Layout {
|
||||||
mut location, size, ..
|
mut location, size, ..
|
||||||
} = layout.layout(node.state.layout.node.unwrap()).unwrap();
|
} = layout
|
||||||
|
.layout(node.get::<TaffyLayout>().unwrap().node.unwrap())
|
||||||
|
.unwrap();
|
||||||
location.x += parent_location.x;
|
location.x += parent_location.x;
|
||||||
location.y += parent_location.y;
|
location.y += parent_location.y;
|
||||||
|
|
||||||
@@ -44,7 +52,7 @@ pub(crate) fn render_vnode(
|
|||||||
let width = layout_to_screen_space(fx + width).round() as u16 - x;
|
let width = layout_to_screen_space(fx + width).round() as u16 - x;
|
||||||
let height = layout_to_screen_space(fy + height).round() as u16 - y;
|
let height = layout_to_screen_space(fy + height).round() as u16 - y;
|
||||||
|
|
||||||
match &node.node_data.node_type {
|
match node.node_type() {
|
||||||
NodeType::Text(text) => {
|
NodeType::Text(text) => {
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct Label<'a> {
|
struct Label<'a> {
|
||||||
@@ -65,7 +73,7 @@ pub(crate) fn render_vnode(
|
|||||||
|
|
||||||
let label = Label {
|
let label = Label {
|
||||||
text,
|
text,
|
||||||
style: node.state.style.core,
|
style: node.get::<StyleModifier>().unwrap().core,
|
||||||
};
|
};
|
||||||
let area = Rect::new(x, y, width, height);
|
let area = Rect::new(x, y, width, height);
|
||||||
|
|
||||||
@@ -82,15 +90,15 @@ pub(crate) fn render_vnode(
|
|||||||
frame.render_widget(WidgetWithContext::new(node, cfg), area);
|
frame.render_widget(WidgetWithContext::new(node, cfg), area);
|
||||||
}
|
}
|
||||||
|
|
||||||
for c in rdom.children_ids(node.node_data.node_id).unwrap() {
|
for c in node.children().unwrap() {
|
||||||
render_vnode(frame, layout, rdom, &rdom[*c], cfg, location);
|
render_vnode(frame, layout, rdom, c, cfg, location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NodeType::Placeholder => unreachable!(),
|
NodeType::Placeholder => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RinkWidget for &TuiNode {
|
impl RinkWidget for NodeRef<'_> {
|
||||||
fn render(self, area: Rect, mut buf: RinkBuffer<'_>) {
|
fn render(self, area: Rect, mut buf: RinkBuffer<'_>) {
|
||||||
use tui::symbols::line::*;
|
use tui::symbols::line::*;
|
||||||
|
|
||||||
@@ -275,10 +283,10 @@ impl RinkWidget for &TuiNode {
|
|||||||
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.state.style.core.bg {
|
if let Some(c) = self.get::<StyleModifier>().unwrap().core.bg {
|
||||||
new_cell.bg = c;
|
new_cell.bg = c;
|
||||||
}
|
}
|
||||||
if self.state.focused {
|
if self.get::<Focused>().unwrap().0 {
|
||||||
new_cell.bg.alpha = 100;
|
new_cell.bg.alpha = 100;
|
||||||
new_cell.bg.color = new_cell.bg.blend(Color::White);
|
new_cell.bg.color = new_cell.bg.blend(Color::White);
|
||||||
}
|
}
|
||||||
@@ -286,7 +294,9 @@ impl RinkWidget for &TuiNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let borders = &self.state.style.modifier.borders;
|
let style = self.get::<StyleModifier>().unwrap();
|
||||||
|
|
||||||
|
let borders = &style.modifier.borders;
|
||||||
|
|
||||||
let last_edge = &borders.left;
|
let last_edge = &borders.left;
|
||||||
let current_edge = &borders.top;
|
let current_edge = &borders.top;
|
||||||
@@ -303,7 +313,7 @@ impl RinkWidget for &TuiNode {
|
|||||||
(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.state.style.core.fg);
|
let color = current_edge.color.or(style.core.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;
|
||||||
@@ -338,7 +348,7 @@ impl RinkWidget for &TuiNode {
|
|||||||
(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.state.style.core.fg);
|
let color = current_edge.color.or(style.core.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;
|
||||||
@@ -373,7 +383,7 @@ impl RinkWidget for &TuiNode {
|
|||||||
(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.state.style.core.fg);
|
let color = current_edge.color.or(style.core.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;
|
||||||
@@ -408,7 +418,7 @@ impl RinkWidget for &TuiNode {
|
|||||||
(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.state.style.core.fg);
|
let color = current_edge.color.or(style.core.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;
|
||||||
|
|||||||
@@ -32,10 +32,9 @@
|
|||||||
use dioxus_native_core::{
|
use dioxus_native_core::{
|
||||||
layout_attributes::parse_value,
|
layout_attributes::parse_value,
|
||||||
node::OwnedAttributeView,
|
node::OwnedAttributeView,
|
||||||
node_ref::{AttributeMask, NodeMask, NodeView},
|
node_ref::{AttributeMaskBuilder, NodeMaskBuilder, NodeView},
|
||||||
Pass, SendAnyMap,
|
Dependancy, Pass, SendAnyMap,
|
||||||
};
|
};
|
||||||
use dioxus_native_core_macro::sorted_str_slice;
|
|
||||||
use taffy::prelude::*;
|
use taffy::prelude::*;
|
||||||
|
|
||||||
use crate::style::{RinkColor, RinkStyle};
|
use crate::style::{RinkColor, RinkStyle};
|
||||||
@@ -52,24 +51,17 @@ 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: NodeMask =
|
const NODE_MASK: NodeMaskBuilder = NodeMaskBuilder::new()
|
||||||
NodeMask::new_with_attrs(AttributeMask::Static(SORTED_STYLE_ATTRS)).with_element();
|
.with_attrs(AttributeMaskBuilder::Some(SORTED_STYLE_ATTRS))
|
||||||
|
.with_element();
|
||||||
|
|
||||||
fn pass<'a>(
|
fn pass<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
node_view: NodeView,
|
node_view: NodeView,
|
||||||
_: <Self::NodeDependencies as dioxus_native_core::Dependancy>::ElementBorrowed<'a>,
|
node: <Self::NodeDependencies as Dependancy>::ElementBorrowed<'a>,
|
||||||
parent: Option<
|
parent: Option<<Self::ParentDependencies as Dependancy>::ElementBorrowed<'a>>,
|
||||||
<Self::ParentDependencies as dioxus_native_core::Dependancy>::ElementBorrowed<'a>,
|
children: Option<Vec<<Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>>,
|
||||||
>,
|
context: &SendAnyMap,
|
||||||
_: Option<
|
|
||||||
impl Iterator<
|
|
||||||
Item = <Self::ChildDependencies as dioxus_native_core::Dependancy>::ElementBorrowed<
|
|
||||||
'a,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
_: &SendAnyMap,
|
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let mut new = StyleModifier::default();
|
let mut new = StyleModifier::default();
|
||||||
if parent.is_some() {
|
if parent.is_some() {
|
||||||
@@ -615,7 +607,7 @@ fn apply_transition(_name: &str, _value: &str, _style: &mut StyleModifier) {
|
|||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
const SORTED_STYLE_ATTRS: &[&str] = &sorted_str_slice!([
|
const SORTED_STYLE_ATTRS: &[&str] = &[
|
||||||
"animation",
|
"animation",
|
||||||
"animation-delay",
|
"animation-delay",
|
||||||
"animation-direction",
|
"animation-direction",
|
||||||
@@ -816,5 +808,5 @@ const SORTED_STYLE_ATTRS: &[&str] = &sorted_str_slice!([
|
|||||||
"text-justify",
|
"text-justify",
|
||||||
"text-overflow",
|
"text-overflow",
|
||||||
"text-shadow",
|
"text-shadow",
|
||||||
"text-transform"
|
"text-transform",
|
||||||
]);
|
];
|
||||||
Reference in new issue
Block a user