tidy_tree/
lib.rs

1#![allow(dead_code, unused_imports, unused_variables)]
2pub mod geometry;
3mod iter;
4mod layout;
5mod node;
6mod utils;
7pub use iter::Iter;
8use std::{any::Any, collections::HashMap, ptr::NonNull};
9
10use geometry::Coord;
11use layout::BoundingBox;
12pub use layout::{BasicLayout, Layout, TidyLayout};
13pub use node::Node;
14
15#[derive(PartialEq, Eq)]
16pub enum LayoutType {
17    Basic,
18    Tidy,
19    LayeredTidy,
20}
21
22pub struct TidyTree {
23    root: Node,
24    layout_type: LayoutType,
25    layout: Box<dyn Layout>,
26    map: HashMap<usize, NonNull<Node>>,
27}
28
29impl TidyTree {
30    pub fn with_basic_layout(parent_child_margin: Coord, peer_margin: Coord) -> Self {
31        TidyTree {
32            layout_type: LayoutType::Basic,
33            root: Default::default(),
34            layout: Box::new(BasicLayout {
35                parent_child_margin,
36                peer_margin,
37            }),
38            map: HashMap::new(),
39        }
40    }
41
42    pub fn with_tidy_layout(parent_child_margin: Coord, peer_margin: Coord) -> Self {
43        TidyTree {
44            layout_type: LayoutType::Tidy,
45            root: Default::default(),
46            layout: Box::new(TidyLayout::new(parent_child_margin, peer_margin)),
47            map: HashMap::new(),
48        }
49    }
50
51    pub fn with_layered_tidy(parent_child_margin: Coord, peer_margin: Coord) -> Self {
52        TidyTree {
53            layout_type: LayoutType::Tidy,
54            root: Default::default(),
55            layout: Box::new(TidyLayout::new_layered(parent_child_margin, peer_margin)),
56            map: HashMap::new(),
57        }
58    }
59
60    pub fn change_layout(&mut self, layout_type: LayoutType) {
61        if layout_type == self.layout_type {
62            return;
63        }
64
65        let parent_child_margin = self.layout.parent_child_margin();
66        let peer_margin = self.layout.peer_margin();
67        match layout_type {
68            LayoutType::Basic => {
69                self.layout = Box::new(BasicLayout {
70                    parent_child_margin,
71                    peer_margin,
72                });
73            }
74            LayoutType::Tidy => {
75                self.layout = Box::new(TidyLayout::new(parent_child_margin, peer_margin));
76            }
77            LayoutType::LayeredTidy => {
78                self.layout = Box::new(TidyLayout::new_layered(parent_child_margin, peer_margin))
79            }
80        }
81
82        self.layout_type = layout_type;
83    }
84
85    pub fn is_empty(&self) -> bool {
86        self.root.id == usize::MAX
87    }
88
89    pub fn add_node(&mut self, id: usize, width: Coord, height: Coord, parent_id: usize) {
90        let node = Node::new(id, width, height);
91        if self.is_empty() || parent_id == usize::MAX {
92            self.root = node;
93            self.map.insert(id, (&self.root).into());
94            return;
95        }
96
97        let mut parent = *self.map.get(&parent_id).unwrap();
98        let parent = unsafe { parent.as_mut() };
99
100        let ptr = parent.append_child(node);
101        self.map.insert(id, ptr);
102    }
103
104    pub fn remove_node(&mut self, id: usize) {
105        if self.is_empty() {
106            return;
107        }
108
109        if let Some(node) = self.map.get(&id) {
110            let node = unsafe { &mut *node.as_ptr() };
111            node.pre_order_traversal(|node| {
112                self.map.remove(&node.id);
113            });
114            node.parent_mut().unwrap().remove_child(id);
115        }
116    }
117
118    pub fn data(&mut self, id: &[usize], width: &[Coord], height: &[Coord], parent_id: &[usize]) {
119        for (i, &id) in id.iter().enumerate() {
120            let width = width[i];
121            let height = height[i];
122            let parent_id = parent_id[i];
123            self.add_node(id, width, height, parent_id);
124        }
125    }
126
127    pub fn layout(&mut self) {
128        if self.is_empty() {
129            return;
130        }
131
132        self.layout.layout(&mut self.root);
133    }
134
135    pub fn get_pos(&self) -> Vec<Coord> {
136        let mut ans = vec![];
137        for (id, node) in self.map.iter() {
138            let node = unsafe { node.as_ref() };
139            ans.push((*id) as Coord);
140            ans.push(node.x);
141            ans.push(node.y);
142        }
143
144        ans
145    }
146}
147
148pub const NULL_ID: usize = usize::MAX;