Skip to main content

gpui_base/dock/layout/
node.rs

1use gpui::{Axis, EntityId, Pixels};
2
3/// Stable container identity. Survives structural edits and normalization so
4/// the `DockArea` view cache does not tear down and rebuild entities.
5#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
6pub struct NodeId(u64);
7
8impl NodeId {
9    pub(crate) fn from_u64(raw: u64) -> Self {
10        Self(raw)
11    }
12
13    pub fn as_u64(self) -> u64 {
14        self.0
15    }
16}
17
18/// Stable panel identity. Wraps the `EntityId` of the panel entity so the
19/// layout algebra can be exercised without an `App`.
20#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
21pub struct PanelId(u64);
22
23impl PanelId {
24    pub fn from_u64(raw: u64) -> Self {
25        Self(raw)
26    }
27
28    pub fn as_u64(self) -> u64 {
29        self.0
30    }
31}
32
33impl From<EntityId> for PanelId {
34    fn from(id: EntityId) -> Self {
35        Self(id.as_u64())
36    }
37}
38
39/// The shape of one container. Private: every mutation goes through
40/// [`PaneTree`] so normalization always runs.
41///
42/// [`PaneTree`]: super::PaneTree
43#[derive(Clone, PartialEq, Debug)]
44pub(crate) enum NodeKind {
45    Split {
46        axis: Axis,
47        children: Vec<PaneNode>,
48        sizes: Vec<Option<Pixels>>,
49    },
50    Tabs {
51        panels: Vec<PanelId>,
52        active_ix: usize,
53    },
54}
55
56/// Borrowed read-only projection of a node.
57pub enum PaneRef<'a> {
58    Split {
59        axis: Axis,
60        children: &'a [PaneNode],
61        sizes: &'a [Option<Pixels>],
62    },
63    Tabs {
64        panels: &'a [PanelId],
65        active_ix: usize,
66    },
67}
68
69#[derive(Clone, PartialEq, Debug)]
70pub struct PaneNode {
71    id: NodeId,
72    kind: NodeKind,
73}
74
75impl PaneNode {
76    pub(crate) fn new(id: NodeId, kind: NodeKind) -> Self {
77        Self { id, kind }
78    }
79
80    pub fn id(&self) -> NodeId {
81        self.id
82    }
83
84    pub fn kind(&self) -> PaneRef<'_> {
85        match &self.kind {
86            NodeKind::Split {
87                axis,
88                children,
89                sizes,
90            } => PaneRef::Split {
91                axis: *axis,
92                children,
93                sizes,
94            },
95            NodeKind::Tabs { panels, active_ix } => PaneRef::Tabs {
96                panels,
97                active_ix: *active_ix,
98            },
99        }
100    }
101
102    pub(crate) fn kind_mut(&mut self) -> &mut NodeKind {
103        &mut self.kind
104    }
105
106    pub(crate) fn kind_ref(&self) -> &NodeKind {
107        &self.kind
108    }
109
110    /// Depth-first pre-order walk over this node and its descendants.
111    pub fn walk(&self, f: &mut impl FnMut(&PaneNode)) {
112        f(self);
113        if let NodeKind::Split { children, .. } = &self.kind {
114            for child in children {
115                child.walk(f);
116            }
117        }
118    }
119}