guise/panegroup/
layout.rs1use crate::SplitDirection;
4use super::id::{PaneId, SplitId};
5use super::tree::{Node, PaneTree};
6
7#[derive(Debug, Clone, Copy, PartialEq)]
8pub struct Rect {
9 pub x: f32,
10 pub y: f32,
11 pub w: f32,
12 pub h: f32,
13}
14
15impl Rect {
16 pub fn new(x: f32, y: f32, w: f32, h: f32) -> Self {
17 Self { x, y, w, h }
18 }
19
20 pub fn center(&self) -> (f32, f32) {
21 (self.x + self.w / 2.0, self.y + self.h / 2.0)
22 }
23}
24
25#[derive(Debug, Clone, PartialEq)]
27pub struct Layout {
28 pub panes: Vec<(PaneId, Rect)>,
29 pub dividers: Vec<(SplitId, Rect, SplitDirection)>,
30}
31
32impl Layout {
33 pub fn pane_rect(&self, pane: PaneId) -> Option<Rect> {
34 self.panes.iter().find(|(p, _)| *p == pane).map(|(_, r)| *r)
35 }
36}
37
38pub fn compute_layout(tree: &PaneTree, rect: Rect, divider: f32) -> Layout {
40 let mut layout = Layout {
41 panes: Vec::new(),
42 dividers: Vec::new(),
43 };
44 walk(tree.root(), rect, divider, &mut layout);
45 layout
46}
47
48fn walk(node: &Node, rect: Rect, divider: f32, out: &mut Layout) {
49 match node {
50 Node::Leaf(pane) => out.panes.push((*pane, rect)),
51 Node::Split {
52 id,
53 axis,
54 ratio,
55 first,
56 second,
57 } => {
58 let (frect, drect, srect) = match axis {
59 SplitDirection::Horizontal => {
60 let avail = (rect.w - divider).max(0.0);
61 let fw = avail * ratio;
62 (
63 Rect::new(rect.x, rect.y, fw, rect.h),
64 Rect::new(rect.x + fw, rect.y, divider, rect.h),
65 Rect::new(rect.x + fw + divider, rect.y, avail - fw, rect.h),
66 )
67 }
68 SplitDirection::Vertical => {
69 let avail = (rect.h - divider).max(0.0);
70 let fh = avail * ratio;
71 (
72 Rect::new(rect.x, rect.y, rect.w, fh),
73 Rect::new(rect.x, rect.y + fh, rect.w, divider),
74 Rect::new(rect.x, rect.y + fh + divider, rect.w, avail - fh),
75 )
76 }
77 };
78 out.dividers.push((*id, drect, *axis));
79 walk(first, frect, divider, out);
80 walk(second, srect, divider, out);
81 }
82 }
83}