Skip to main content

repose_tree/
node.rs

1//! Tree node definitions.
2
3use repose_core::{Modifier, Rect, Semantics, ViewId, ViewKind};
4use slotmap::new_key_type;
5use smallvec::SmallVec;
6
7new_key_type! {
8 /// Internal node identifier, stable within a tree's lifetime.
9 pub struct NodeId;
10}
11
12/// A node in the persistent view tree.
13#[derive(Clone)]
14pub struct TreeNode {
15    /// Internal slotmap key.
16    pub id: NodeId,
17
18    /// User-facing stable view ID (for hit testing, focus, etc.).
19    pub view_id: ViewId,
20
21    /// The kind of view this node represents.
22    pub kind: ViewKind,
23
24    /// Layout and styling modifiers.
25    pub modifier: Modifier,
26
27    pub semantics: Option<Semantics>,
28
29    /// Child node IDs.
30    pub children: SmallVec<[NodeId; 4]>,
31
32    /// Parent node ID (None for root).
33    pub parent: Option<NodeId>,
34
35    /// Legacy aggregate hash of this node's immediate content.
36    pub content_hash: u64,
37
38    /// Hash of values that can change layout.
39    pub layout_hash: u64,
40
41    /// Hash of values that can change text or intrinsic measurement.
42    pub measurement_hash: u64,
43
44    /// Hash of values that can change painting.
45    pub paint_hash: u64,
46
47    /// Hash of accessibility semantics.
48    pub semantics_hash: u64,
49
50    /// Legacy aggregate hash including all descendants.
51    pub subtree_hash: u64,
52
53    pub layout_subtree_hash: u64,
54    pub measurement_subtree_hash: u64,
55    pub paint_subtree_hash: u64,
56    pub semantics_subtree_hash: u64,
57
58    /// Cached layout result.
59    pub layout_cache: Option<LayoutCache>,
60
61    /// Generation when this node was last updated.
62    pub generation: u64,
63
64    /// Key provided by user for stable identity in dynamic lists.
65    pub user_key: Option<u64>,
66
67    /// Depth in tree (root = 0).
68    pub depth: u32,
69
70    /// If this node is a scope boundary (set by `scope!` macro), this holds the
71    /// scope key (e.g., "title", "color_buttons"). `None` for non-scope nodes.
72    pub scope_key: Option<String>,
73}
74
75impl TreeNode {
76    /// Create a new tree node.
77    pub fn new(
78        id: NodeId,
79        view_id: ViewId,
80        kind: ViewKind,
81        modifier: Modifier,
82        generation: u64,
83    ) -> Self {
84        Self {
85            id,
86            view_id,
87            kind,
88            modifier,
89            semantics: None,
90            children: SmallVec::new(),
91            parent: None,
92            content_hash: 0,
93            layout_hash: 0,
94            measurement_hash: 0,
95            paint_hash: 0,
96            semantics_hash: 0,
97            subtree_hash: 0,
98            layout_subtree_hash: 0,
99            measurement_subtree_hash: 0,
100            paint_subtree_hash: 0,
101            semantics_subtree_hash: 0,
102            layout_cache: None,
103            generation,
104            user_key: None,
105            depth: 0,
106            scope_key: None,
107        }
108    }
109
110    /// Check if this node's layout cache is still valid.
111    pub fn has_valid_layout(&self) -> bool {
112        self.layout_cache.is_some()
113    }
114
115    /// Invalidate layout cache (called when content changes).
116    pub fn invalidate_layout(&mut self) {
117        self.layout_cache = None;
118    }
119
120    /// Get cached layout if available.
121    pub fn cached_rect(&self) -> Option<Rect> {
122        self.layout_cache.as_ref().map(|c| c.rect)
123    }
124
125    pub fn set_layout(&mut self, rect: Rect) {
126        self.layout_cache = Some(LayoutCache {
127            rect,
128            // constraints and screen_rect are less critical for basic paint
129            screen_rect: Rect::default(),
130            constraints: LayoutConstraints::default(),
131            generation: self.generation,
132        });
133    }
134}
135
136/// Cached layout information for a node.
137#[derive(Clone, Debug)]
138pub struct LayoutCache {
139    /// The computed rectangle in parent coordinates.
140    pub rect: Rect,
141
142    /// The computed rectangle in screen coordinates.
143    pub screen_rect: Rect,
144
145    /// Size constraints used when computing this layout.
146    pub constraints: LayoutConstraints,
147
148    /// Generation when this cache was computed.
149    pub generation: u64,
150}
151
152/// Constraints used during layout.
153#[derive(Clone, Debug, PartialEq)]
154pub struct LayoutConstraints {
155    pub min_width: f32,
156    pub max_width: f32,
157    pub min_height: f32,
158    pub max_height: f32,
159}
160
161impl Default for LayoutConstraints {
162    fn default() -> Self {
163        Self {
164            min_width: 0.0,
165            max_width: f32::INFINITY,
166            min_height: 0.0,
167            max_height: f32::INFINITY,
168        }
169    }
170}
171
172impl LayoutConstraints {
173    pub fn fixed(width: f32, height: f32) -> Self {
174        Self {
175            min_width: width,
176            max_width: width,
177            min_height: height,
178            max_height: height,
179        }
180    }
181
182    pub fn tight(size: (f32, f32)) -> Self {
183        Self::fixed(size.0, size.1)
184    }
185}
186
187/// Statistics about tree operations.
188#[derive(Clone, Debug, Default)]
189pub struct TreeStats {
190    pub total_nodes: usize,
191
192    pub dirty_nodes: usize,
193
194    pub reconciled_nodes: usize,
195
196    pub skipped_nodes: usize,
197
198    pub created_nodes: usize,
199
200    pub removed_nodes: usize,
201
202    pub layout_cache_hits: usize,
203
204    pub layout_cache_misses: usize,
205}