use crate::{Attribute, Class, GestureKV, StateKV, Style, StyleWrapper};
use elvis_core_support::Wrapper;
use std::{
cell::RefCell,
collections::hash_map::DefaultHasher,
fmt,
hash::Hasher,
rc::{Rc, Weak},
};
fn hash(s: &[u8]) -> String {
let mut hasher = DefaultHasher::new();
hasher.write(s);
let res = format!("{:x}", hasher.finish());
format!("elvis-{}", &res[0..6])
}
#[derive(Clone, Default, Wrapper)]
pub struct Node {
pub attr: Attribute,
pub class: Vec<Class>,
pub style: Vec<Style>,
pub children: Vec<Rc<RefCell<Node>>>,
pub pre: Option<Weak<RefCell<Node>>>,
pub state: Option<StateKV>,
pub gesture: Option<GestureKV>,
}
impl fmt::Debug for Node {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Node")
.field("children", &self.children)
.field("pre", &self.pre)
.finish()
}
}
impl Node {
pub fn attr(mut self, attr: Attribute) -> Node {
self.attr = attr;
self
}
pub fn children(mut self, children: Vec<Node>) -> Node {
self.children = children
.iter()
.map(|n| Rc::new(RefCell::new(n.clone())))
.collect::<Vec<Rc<RefCell<Node>>>>();
self
}
pub fn append_child(mut self, child: Node) -> Node {
self.children.push(Rc::new(RefCell::new(child)));
self
}
pub fn append_children(mut self, children: Vec<Node>) -> Node {
self.children.append(
&mut children
.iter()
.map(|n| Rc::new(RefCell::new(n.clone())))
.collect::<Vec<Rc<RefCell<Node>>>>(),
);
self
}
pub fn class(mut self, class: Vec<Class>) -> Node {
self.class = class;
self
}
pub fn append_class(mut self, class: &mut Vec<Class>) -> Node {
self.class.append(class);
self.class.sort();
self.class.dedup();
self
}
pub fn style(mut self, style: impl Into<Vec<Style>>) -> Node {
self.style = style.into();
self
}
pub fn append_style(mut self, styles: impl Into<Vec<Style>>) -> Node {
self.style.append(&mut styles.into());
self.style.sort();
self.style.dedup();
self
}
pub fn drain(t: Rc<RefCell<Node>>) {
if let Some(pre) = &t.borrow().pre {
let u = pre.upgrade().expect("drain child failed");
u.borrow_mut().remove(t.clone());
u.borrow_mut().update();
}
}
pub fn idx(&mut self, path: &mut Vec<u8>) {
self.attr.id = hash(&path);
path.push(0);
for t in self.children.iter() {
t.borrow_mut().idx(path);
if let Some(last) = path.last_mut() {
*last += 1;
}
}
}
pub fn locate(&self, mut path: Vec<usize>) -> Vec<usize> {
if let Some(pre) = &self.pre {
let u = pre.upgrade().expect("locate widget failed");
for (i, t) in u.borrow().children.iter().enumerate() {
if t.borrow().eq(self) {
path.push(i);
return u.borrow().locate(path);
}
}
}
path
}
pub fn push(r: Rc<RefCell<Node>>, c: Rc<RefCell<Node>>) {
let pre = Rc::downgrade(&r);
c.borrow_mut().pre = Some(pre.clone());
pre.upgrade()
.expect("push child to tree failed")
.borrow_mut()
.children
.push(c);
r.borrow_mut().update();
}
pub fn remove(&mut self, c: Rc<RefCell<Node>>) {
self.children.retain(|x| x != &c);
self.update();
}
pub fn replace(&mut self, mut t: Node) {
t.pre = self.pre.clone();
std::mem::swap(self, &mut t);
t.update();
}
pub fn update(&mut self) {}
}
impl PartialEq for Node {
fn eq(&self, other: &Self) -> bool {
let res =
self.attr.eq(&other.attr) && self.style.eq(&other.style) && self.class.eq(&other.class);
for (p, q) in self.children.iter().enumerate() {
if !q.eq(&other.children[p]) {
return false;
}
}
res
}
}
impl Eq for Node {}