1use std::sync::{
2 Arc,
3 Mutex,
4};
5
6use freya_core::{
7 dom::FreyaDOM,
8 node::{
9 get_node_state,
10 NodeState,
11 },
12};
13use freya_native_core::{
14 prelude::{
15 NodeId,
16 NodeImmutable,
17 },
18 tags::TagName,
19};
20use tokio::sync::watch;
21use torin::prelude::LayoutNode;
22
23pub type DevtoolsReceiver = watch::Receiver<Vec<NodeInfo>>;
24pub type HoveredNode = Option<Arc<Mutex<Option<NodeId>>>>;
25
26#[derive(Clone)]
27pub struct Devtools {
28 sender: watch::Sender<Vec<NodeInfo>>,
29}
30
31impl Devtools {
32 pub fn new() -> (Self, DevtoolsReceiver) {
33 let (sender, receiver) = watch::channel(Vec::new());
34
35 (Self { sender }, receiver)
36 }
37
38 pub fn update(&self, fdom: &FreyaDOM) {
39 let rdom = fdom.rdom();
40 let layout = fdom.layout();
41
42 let mut new_nodes = Vec::new();
43
44 let mut root_found = false;
45 let mut devtools_found = false;
46
47 rdom.traverse_depth_first(|node| {
48 let height = node.height();
49 if height == 3 {
50 if !root_found {
51 root_found = true;
52 } else {
53 devtools_found = true;
54 }
55 }
56
57 if !devtools_found && root_found {
58 let layout_node = layout.get(node.id()).cloned();
59 if let Some(layout_node) = layout_node {
60 let node_type = node.node_type();
61 new_nodes.push(NodeInfo {
62 id: node.id(),
63 parent_id: node.parent_id(),
64 children_len: node
65 .children()
66 .iter()
67 .filter(|node| layout.get(node.id()).is_some())
68 .count(),
69 tag: *node_type.tag().unwrap(),
70 height: node.height(),
71 state: get_node_state(&node),
72 layout_node,
73 });
74 }
75 }
76 });
77
78 self.sender
79 .send(new_nodes)
80 .expect("Failed to sync the Devtools.");
81 }
82}
83
84#[derive(Clone, PartialEq)]
85pub struct NodeInfo {
86 pub id: NodeId,
87 pub parent_id: Option<NodeId>,
88 pub children_len: usize,
89 pub tag: TagName,
90 pub height: u16,
91 pub state: NodeState,
92 pub layout_node: LayoutNode,
93}