on 2158366 help sign in
474 lines 14 kB history raw
1use crate::{graphics::Rect, View, ViewId};
2use slotmap::HopSlotMap;
4// the dimensions are recomputed on window resize/tree change.
5//
6#[derive(Debug)]
7pub struct Tree {
8 root: ViewId,
9 // (container, index inside the container)
10 pub focus: ViewId,
11 // fullscreen: bool,
12 area: Rect,
14 nodes: HopSlotMap<ViewId, Node>,
16 // used for traversals
17 stack: Vec<(ViewId, Rect)>,
20#[derive(Debug)]
21pub struct Node {
22 parent: ViewId,
23 content: Content,
26#[derive(Debug)]
27pub enum Content {
28 View(Box<View>),
29 Container(Box<Container>),
32impl Node {
33 pub fn container(layout: Layout) -> Self {
34 Self {
35 parent: ViewId::default(),
36 content: Content::Container(Box::new(Container::new(layout))),
37 }
38 }
40 pub fn view(view: View) -> Self {
41 Self {
42 parent: ViewId::default(),
43 content: Content::View(Box::new(view)),
44 }
45 }
48// TODO: screen coord to container + container coordinate helpers
50#[derive(Debug, PartialEq, Eq)]
51pub enum Layout {
52 Horizontal,
53 Vertical,
54 // could explore stacked/tabbed
57#[derive(Debug)]
58pub struct Container {
59 layout: Layout,
60 children: Vec<ViewId>,
61 area: Rect,
64impl Container {
65 pub fn new(layout: Layout) -> Self {
66 Self {
67 layout,
68 children: Vec::new(),
69 area: Rect::default(),
70 }
71 }
74impl Default for Container {
75 fn default() -> Self {
76 Self::new(Layout::Vertical)
77 }
80impl Tree {
81 pub fn new(area: Rect) -> Self {
82 let root = Node::container(Layout::Vertical);
84 let mut nodes = HopSlotMap::with_key();
85 let root = nodes.insert(root);
87 // root is it's own parent
88 nodes[root].parent = root;
90 Self {
91 root,
92 focus: root,
93 // fullscreen: false,
94 area,
95 nodes,
96 stack: Vec::new(),
97 }
98 }
100 pub fn insert(&mut self, view: View) -> ViewId {
101 let focus = self.focus;
102 let parent = self.nodes[focus].parent;
103 let mut node = Node::view(view);
104 node.parent = parent;
105 let node = self.nodes.insert(node);
106 self.get_mut(node).id = node;
108 let container = match &mut self.nodes[parent] {
109 Node {
110 content: Content::Container(container),
111 ..
112 } => container,
113 _ => unreachable!(),
114 };
116 // insert node after the current item if there is children already
117 let pos = if container.children.is_empty() {
118 0
119 } else {
120 let pos = container
121 .children
122 .iter()
123 .position(|&child| child == focus)
124 .unwrap();
125 pos + 1
126 };
128 container.children.insert(pos, node);
129 // focus the new node
130 self.focus = node;
132 // recalculate all the sizes
133 self.recalculate();
135 node
136 }
138 pub fn split(&mut self, view: View, layout: Layout) -> ViewId {
139 let focus = self.focus;
140 let parent = self.nodes[focus].parent;
142 let node = Node::view(view);
143 let node = self.nodes.insert(node);
144 self.get_mut(node).id = node;
146 let container = match &mut self.nodes[parent] {
147 Node {
148 content: Content::Container(container),
149 ..
150 } => container,
151 _ => unreachable!(),
152 };
154 if container.layout == layout {
155 // insert node after the current item if there is children already
156 let pos = if container.children.is_empty() {
157 0
158 } else {
159 let pos = container
160 .children
161 .iter()
162 .position(|&child| child == focus)
163 .unwrap();
164 pos + 1
165 };
166 container.children.insert(pos, node);
167 self.nodes[node].parent = parent;
168 } else {
169 let mut split = Node::container(layout);
170 split.parent = parent;
171 let split = self.nodes.insert(split);
173 let container = match &mut self.nodes[split] {
174 Node {
175 content: Content::Container(container),
176 ..
177 } => container,
178 _ => unreachable!(),
179 };
180 container.children.push(focus);
181 container.children.push(node);
182 self.nodes[focus].parent = split;
183 self.nodes[node].parent = split;
185 let container = match &mut self.nodes[parent] {
186 Node {
187 content: Content::Container(container),
188 ..
189 } => container,
190 _ => unreachable!(),
191 };
193 let pos = container
194 .children
195 .iter()
196 .position(|&child| child == focus)
197 .unwrap();
199 // replace focus on parent with split
200 container.children[pos] = split;
201 }
203 // focus the new node
204 self.focus = node;
206 // recalculate all the sizes
207 self.recalculate();
209 node
210 }
212 pub fn remove(&mut self, index: ViewId) {
213 let mut stack = Vec::new();
215 if self.focus == index {
216 // focus on something else
217 self.focus_next();
218 }
220 stack.push(index);
222 while let Some(index) = stack.pop() {
223 let parent_id = self.nodes[index].parent;
224 if let Node {
225 content: Content::Container(container),
226 ..
227 } = &mut self.nodes[parent_id]
228 {
229 if let Some(pos) = container.children.iter().position(|&child| child == index) {
230 container.children.remove(pos);
232 // TODO: if container now only has one child, remove it and place child in parent
233 if container.children.is_empty() && parent_id != self.root {
234 // if container now empty, remove it
235 stack.push(parent_id);
236 }
237 }
238 }
239 self.nodes.remove(index);
240 }
242 self.recalculate()
243 }
245 pub fn views(&self) -> impl Iterator<Item = (&View, bool)> {
246 let focus = self.focus;
247 self.nodes.iter().filter_map(move |(key, node)| match node {
248 Node {
249 content: Content::View(view),
250 ..
251 } => Some((view.as_ref(), focus == key)),
252 _ => None,
253 })
254 }
256 pub fn views_mut(&mut self) -> impl Iterator<Item = (&mut View, bool)> {
257 let focus = self.focus;
258 self.nodes
259 .iter_mut()
260 .filter_map(move |(key, node)| match node {
261 Node {
262 content: Content::View(view),
263 ..
264 } => Some((view.as_mut(), focus == key)),
265 _ => None,
266 })
267 }
269 pub fn get(&self, index: ViewId) -> &View {
270 match &self.nodes[index] {
271 Node {
272 content: Content::View(view),
273 ..
274 } => view,
275 _ => unreachable!(),
276 }
277 }
279 pub fn get_mut(&mut self, index: ViewId) -> &mut View {
280 match &mut self.nodes[index] {
281 Node {
282 content: Content::View(view),
283 ..
284 } => view,
285 _ => unreachable!(),
286 }
287 }
289 pub fn is_empty(&self) -> bool {
290 match &self.nodes[self.root] {
291 Node {
292 content: Content::Container(container),
293 ..
294 } => container.children.is_empty(),
295 _ => unreachable!(),
296 }
297 }
299 pub fn resize(&mut self, area: Rect) -> bool {
300 if self.area != area {
301 self.area = area;
302 self.recalculate();
303 return true;
304 }
305 false
306 }
308 pub fn recalculate(&mut self) {
309 if self.is_empty() {
310 return;
311 }
313 self.stack.push((self.root, self.area));
315 // take the area
316 // fetch the node
317 // a) node is view, give it whole area
318 // b) node is container, calculate areas for each child and push them on the stack
320 while let Some((key, area)) = self.stack.pop() {
321 let node = &mut self.nodes[key];
323 match &mut node.content {
324 Content::View(view) => {
325 // debug!!("setting view area {:?}", area);
326 view.area = area;
327 } // TODO: call f()
328 Content::Container(container) => {
329 // debug!!("setting container area {:?}", area);
330 container.area = area;
332 match container.layout {
333 Layout::Horizontal => {
334 let len = container.children.len();
336 let height = area.height / len as u16;
338 let mut child_y = area.y;
340 for (i, child) in container.children.iter().enumerate() {
341 let mut area = Rect::new(
342 container.area.x,
343 child_y,
344 container.area.width,
345 height,
346 );
347 child_y += height;
349 // last child takes the remaining width because we can get uneven
350 // space from rounding
351 if i == len - 1 {
352 area.height = container.area.y + container.area.height - area.y;
353 }
355 self.stack.push((*child, area));
356 }
357 }
358 Layout::Vertical => {
359 let len = container.children.len();
361 let width = area.width / len as u16;
363 let inner_gap = 1u16;
364 // let total_gap = inner_gap * (len as u16 - 1);
366 let mut child_x = area.x;
368 for (i, child) in container.children.iter().enumerate() {
369 let mut area = Rect::new(
370 child_x,
371 container.area.y,
372 width,
373 container.area.height,
374 );
375 child_x += width + inner_gap;
377 // last child takes the remaining width because we can get uneven
378 // space from rounding
379 if i == len - 1 {
380 area.width = container.area.x + container.area.width - area.x;
381 }
383 self.stack.push((*child, area));
384 }
385 }
386 }
387 }
388 }
389 }
390 }
392 pub fn traverse(&self) -> Traverse {
393 Traverse::new(self)
394 }
396 pub fn focus_next(&mut self) {
397 // This function is very dumb, but that's because we don't store any parent links.
398 // (we'd be able to go parent.next_sibling() recursively until we find something)
399 // For now that's okay though, since it's unlikely you'll be able to open a large enough
400 // number of splits to notice.
402 // current = focus
403 // let found = loop do {
404 // node = focus.parent;
405 // let found = node.next_sibling_of(current)
406 // if some {
407 // break found;
408 // }
409 // // else
410 // if node == root {
411 // return first child of root;
412 // };
413 // current = parent;
414 // }
415 // }
416 //
417 // use found next sibling
418 // loop do {
419 // if found = view -> focus = found, return
420 // if found = container -> found = first child
421 // }
423 let iter = self.traverse();
425 let mut iter = iter.skip_while(|&(key, _view)| key != self.focus);
426 iter.next(); // take the focused value
428 if let Some((key, _)) = iter.next() {
429 self.focus = key;
430 } else {
431 // extremely crude, take the first item again
432 let (key, _) = self.traverse().next().unwrap();
433 self.focus = key;
434 }
435 }
437 pub fn area(&self) -> Rect {
438 self.area
439 }
442#[derive(Debug)]
443pub struct Traverse<'a> {
444 tree: &'a Tree,
445 stack: Vec<ViewId>, // TODO: reuse the one we use on update
448impl<'a> Traverse<'a> {
449 fn new(tree: &'a Tree) -> Self {
450 Self {
451 tree,
452 stack: vec![tree.root],
453 }
454 }
457impl<'a> Iterator for Traverse<'a> {
458 type Item = (ViewId, &'a View);
460 fn next(&mut self) -> Option<Self::Item> {
461 loop {
462 let key = self.stack.pop()?;
464 let node = &self.tree.nodes[key];
466 match &node.content {
467 Content::View(view) => return Some((key, view)),
468 Content::Container(container) => {
469 self.stack.extend(container.children.iter().rev());
470 }
471 }
472 }
473 }