1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
use crate::macros::id_newtype;
id_newtype!(
/// Opaque unique identifier for a node in the layout tree.
pub NodeId
);
id_newtype!(
/// Opaque unique identifier for a panel.
pub PanelId
);
id_newtype!(
/// Stable panel identity that survives tree rebuilds.
///
/// Assigned based on declaration order (sequence position).
/// Panels sharing the same kind get distinct keys. Used for
/// deterministic restore of focus and collapsed state when
/// multiple panels share a kind.
pub PanelKey
);
use std::sync::Arc;
use crate::panel::Constraints;
use crate::strategy::{CardSpan, GridColumnMode};
/// Node type in the layout tree arena.
///
/// Variants cover flex containers ([`Row`](Node::Row), [`Col`](Node::Col)),
/// CSS Grid ([`Grid`](Node::Grid), [`GridItemWrapper`](Node::GridItemWrapper)),
/// leaf panels ([`Panel`](Node::Panel)), and a raw Taffy escape hatch
/// ([`TaffyPassthrough`](Node::TaffyPassthrough)).
///
/// Construct trees via [`LayoutBuilder`](crate::LayoutBuilder) rather than
/// creating nodes directly.
#[derive(Debug, Clone)]
pub enum Node {
/// Horizontal container laying children left-to-right.
Row {
/// Space between children.
gap: f32,
/// Optional constraints for this container as a child.
constraints: Option<Constraints>,
/// Ordered child node ids.
children: Vec<NodeId>,
},
/// Vertical container laying children top-to-bottom.
Col {
/// Space between children.
gap: f32,
/// Optional constraints for this container as a child.
constraints: Option<Constraints>,
/// Ordered child node ids.
children: Vec<NodeId>,
},
/// Leaf node representing a single panel.
Panel {
/// Unique panel identifier.
id: PanelId,
/// Application-defined panel kind (e.g. "editor", "chat").
kind: Arc<str>,
/// Size constraints for this panel.
constraints: Constraints,
},
/// CSS Grid container with column mode, gap, and row sizing.
Grid {
/// Column layout mode (fixed count, auto-fill, or auto-fit).
columns: GridColumnMode,
/// Gap between grid items in pixels.
gap: f32,
/// When true, rows size to their tallest card instead of equal `1fr`.
auto_rows: bool,
/// Ordered child node ids.
children: Vec<NodeId>,
},
/// Wrapper for a grid item that carries a column span.
GridItemWrapper {
/// Column span for this grid item.
span: CardSpan,
/// The single child node (typically a Panel).
child: NodeId,
},
/// Raw Taffy node for escape-hatch styling.
TaffyPassthrough {
/// Custom Taffy style applied directly.
style: Box<taffy::Style>,
/// Ordered child node ids (immutable after construction).
children: Box<[NodeId]>,
},
}
impl Node {
/// Child node ids for containers, empty slice for leaf nodes.
pub fn children(&self) -> &[NodeId] {
match self {
Self::Row { children, .. }
| Self::Col { children, .. }
| Self::Grid { children, .. } => children,
Self::GridItemWrapper { child, .. } => std::slice::from_ref(child),
Self::TaffyPassthrough { children, .. } => children,
Self::Panel { .. } => &[],
}
}
/// Mutable access to a container's children list.
pub(crate) fn children_mut(&mut self) -> Option<&mut Vec<NodeId>> {
match self {
Self::Row { children, .. }
| Self::Col { children, .. }
| Self::Grid { children, .. } => Some(children),
Self::GridItemWrapper { .. } | Self::TaffyPassthrough { .. } | Self::Panel { .. } => {
None
}
}
}
}