lgui_core/core/view/tree/
mutation.rs1use super::*;
2
3impl HostTree {
4 pub fn new() -> Self {
5 Self {
6 nodes: Vec::new(),
7 node_indices: Arc::new(HashMap::new()),
8 owners: Arc::new(HashMap::new()),
9 projection_changes: ProjectionChanges::default(),
10 }
11 }
12
13 pub fn push(&mut self, node: UiNode) {
14 self.projection_changes.changed.insert(node.id.clone());
15 self.projection_changes.structure_changed = true;
16 self.mark_runtime_sync_for_insert(&node);
17 if let Some(parent_id) = node.parent.as_ref() {
18 if let Some(parent) = self.node_mut(parent_id) {
19 parent.children.push(node.id.clone());
20 }
21 }
22 if let Some(owner) = node.component_owner {
23 Arc::make_mut(&mut self.owners)
24 .entry(owner)
25 .or_default()
26 .insert(node.id.clone());
27 }
28 let index = self.nodes.len();
29 Arc::make_mut(&mut self.node_indices).insert(node.id.clone(), index);
30 self.nodes.push(Arc::new(node));
31 }
32
33 pub(crate) fn upsert(&mut self, node: UiNode) {
34 if let Some(index) = self.node_indices.get(&node.id).copied() {
35 if !self.nodes[index].projection_eq(&node) {
36 self.projection_changes.changed.insert(node.id.clone());
37 }
38 let previous = Arc::clone(&self.nodes[index]);
39 self.mark_runtime_sync_for_update(&previous, &node);
40 let previous_owner = self.nodes[index].component_owner;
41 if previous_owner != node.component_owner {
42 if let Some(owner) = previous_owner {
43 if let Some(ids) = Arc::make_mut(&mut self.owners).get_mut(&owner) {
44 ids.remove(&node.id);
45 }
46 }
47 if let Some(owner) = node.component_owner {
48 Arc::make_mut(&mut self.owners)
49 .entry(owner)
50 .or_default()
51 .insert(node.id.clone());
52 }
53 }
54 self.nodes[index] = Arc::new(node);
55 } else {
56 self.push(node);
57 }
58 }
59
60 pub(crate) fn set_children(&mut self, parent: &UiId, children: Vec<UiId>) {
61 let changed = {
62 let Some(parent) = self.node_mut(parent) else {
63 return;
64 };
65 if parent.children == children {
66 false
67 } else {
68 parent.children = children;
69 true
70 }
71 };
72 if changed {
73 self.projection_changes.changed.insert(parent.clone());
74 self.projection_changes.structure_changed = true;
75 }
76 }
77
78 pub(crate) fn retain_owner_nodes(
79 &mut self,
80 owner: ComponentId,
81 keep: &std::collections::HashSet<UiId>,
82 ) -> bool {
83 let remove = self
84 .owners
85 .get(&owner)
86 .into_iter()
87 .flatten()
88 .filter(|id| !keep.contains(*id))
89 .cloned()
90 .collect::<std::collections::HashSet<_>>();
91 self.remove_ids(&remove)
92 }
93
94 pub(crate) fn prune_dead_component_owners(&mut self, components: &ComponentTree) -> bool {
95 let remove = self
96 .owners
97 .keys()
98 .copied()
99 .filter(|owner| !components.is_alive(*owner))
100 .flat_map(|owner| self.owners.get(&owner).into_iter().flatten().cloned())
101 .collect::<std::collections::HashSet<_>>();
102 self.remove_ids(&remove)
103 }
104
105 fn remove_ids(&mut self, remove: &std::collections::HashSet<UiId>) -> bool {
106 if remove.is_empty() {
107 return false;
108 }
109 for id in remove {
110 if let Some(index) = self.node_indices.get(id).copied() {
111 let node = Arc::clone(&self.nodes[index]);
112 self.mark_runtime_sync_for_remove(&node);
113 }
114 }
115 self.nodes.retain(|node| !remove.contains(&node.id));
116 self.projection_changes
117 .removed
118 .extend(remove.iter().cloned());
119 self.projection_changes.structure_changed = true;
120 for node in &mut self.nodes {
121 let children_changed = node.children.iter().any(|child| remove.contains(child));
122 let parent_changed = node
123 .parent
124 .as_ref()
125 .is_some_and(|parent| remove.contains(parent));
126 if !children_changed && !parent_changed {
127 continue;
128 }
129 let node = Arc::make_mut(node);
130 if children_changed {
131 node.children.retain(|child| !remove.contains(child));
132 }
133 if parent_changed {
134 node.parent = None;
135 }
136 }
137 Arc::make_mut(&mut self.owners).retain(|_, ids| {
138 ids.retain(|id| !remove.contains(id));
139 !ids.is_empty()
140 });
141 self.rebuild_node_indices();
142 true
143 }
144
145 pub(crate) fn reorder_by_hierarchy(&mut self) {
146 let previous_order = self
147 .nodes
148 .iter()
149 .map(|node| node.id.clone())
150 .collect::<Vec<_>>();
151 let nodes = self
152 .nodes
153 .drain(..)
154 .map(|node| (node.id.clone(), node))
155 .collect::<std::collections::HashMap<_, _>>();
156 let roots = previous_order
157 .iter()
158 .filter(|id| nodes.get(*id).is_some_and(|node| node.parent.is_none()))
159 .cloned()
160 .collect::<Vec<_>>();
161 let mut ordered = Vec::with_capacity(nodes.len());
162 let mut seen = std::collections::HashSet::new();
163 fn append(
164 id: &UiId,
165 nodes: &std::collections::HashMap<UiId, Arc<UiNode>>,
166 seen: &mut std::collections::HashSet<UiId>,
167 ordered: &mut Vec<Arc<UiNode>>,
168 ) {
169 if !seen.insert(id.clone()) {
170 return;
171 }
172 let Some(node) = nodes.get(id) else {
173 return;
174 };
175 ordered.push(node.clone());
176 for child in &node.children {
177 append(child, nodes, seen, ordered);
178 }
179 }
180 for root in roots {
181 append(&root, &nodes, &mut seen, &mut ordered);
182 }
183 for id in nodes.keys() {
184 append(id, &nodes, &mut seen, &mut ordered);
185 }
186 self.nodes = ordered;
187 self.rebuild_node_indices();
188 }
189
190 pub(crate) fn take_projection_changes(&mut self) -> ProjectionChanges {
191 std::mem::take(&mut self.projection_changes)
192 }
193
194 pub fn nodes(&self) -> &[Arc<UiNode>] {
195 &self.nodes
196 }
197
198 pub fn node(&self, id: &UiId) -> Option<&UiNode> {
199 self.node_indices
200 .get(id)
201 .and_then(|index| self.nodes.get(*index))
202 .map(Arc::as_ref)
203 }
204
205 pub fn node_mut(&mut self, id: &UiId) -> Option<&mut UiNode> {
206 let index = self.node_indices.get(id).copied()?;
207 self.nodes.get_mut(index).map(Arc::make_mut)
208 }
209
210 pub(crate) fn changed_nodes(&self, changed: &HashSet<UiId>) -> Vec<&UiNode> {
211 let mut indices = changed
212 .iter()
213 .filter_map(|id| self.node_indices.get(id).copied())
214 .collect::<Vec<_>>();
215 indices.sort_unstable();
216 indices
217 .into_iter()
218 .filter_map(|index| self.nodes.get(index).map(Arc::as_ref))
219 .collect()
220 }
221
222 pub(crate) fn animation_sync_ids(&self) -> impl Iterator<Item = &UiId> {
223 self.projection_changes.animation_sync.iter()
224 }
225
226 pub(crate) fn needs_focus_sync(&self) -> bool {
227 self.projection_changes.focus_sync
228 }
229
230 pub(crate) fn update_compositing_layer(
231 &mut self,
232 id: &UiId,
233 spec: CompositingLayerSpec,
234 ) -> Option<UiRect> {
235 let index = self.node_indices.get(id).copied()?;
236 let node = Arc::make_mut(&mut self.nodes[index]);
237 let previous = node.compositing_layer?;
238 if previous == spec {
239 return None;
240 }
241
242 let visible_bounds = |spec: CompositingLayerSpec| {
243 (spec.opacity > 0).then(|| {
244 spec.transform
245 .transformed_bounds(node.layout_rect)
246 .inflate(node.animation_outset.0, node.animation_outset.1)
247 })
248 };
249 let old_bounds = visible_bounds(previous);
250 let new_bounds = visible_bounds(spec);
251 node.compositing_layer = Some(spec);
252 self.projection_changes.changed.insert(id.clone());
253
254 match (old_bounds, new_bounds) {
255 (Some(old), Some(new)) => Some(old.union(new)),
256 (Some(bounds), None) | (None, Some(bounds)) => Some(bounds),
257 (None, None) => None,
258 }
259 }
260
261 fn rebuild_node_indices(&mut self) {
262 self.node_indices = Arc::new(
263 self.nodes
264 .iter()
265 .enumerate()
266 .map(|(index, node)| (node.id.clone(), index))
267 .collect(),
268 );
269 }
270
271 fn mark_runtime_sync_for_insert(&mut self, node: &UiNode) {
272 if node_needs_animation_sync(node) {
273 self.projection_changes
274 .animation_sync
275 .insert(node.id.clone());
276 }
277 self.projection_changes.focus_sync |= node_affects_focus(node);
278 }
279
280 fn mark_runtime_sync_for_update(&mut self, previous: &UiNode, next: &UiNode) {
281 if previous.animation_bindings != next.animation_bindings
282 || previous.animation_targets != next.animation_targets
283 {
284 self.projection_changes
285 .animation_sync
286 .insert(next.id.clone());
287 }
288 self.projection_changes.focus_sync |= !focus_projection_eq(previous, next);
289 }
290
291 fn mark_runtime_sync_for_remove(&mut self, node: &UiNode) {
292 if node_needs_animation_sync(node) {
293 self.projection_changes
294 .animation_sync
295 .insert(node.id.clone());
296 }
297 self.projection_changes.focus_sync |= node_affects_focus(node);
298 }
299}
300
301fn node_needs_animation_sync(node: &UiNode) -> bool {
302 !node.animation_bindings.is_empty() || !node.animation_targets.is_empty()
303}
304
305fn node_affects_focus(node: &UiNode) -> bool {
306 node.event_policy.focus || node.auto_focus || node.focus_scope
307}
308
309fn focus_projection_eq(previous: &UiNode, next: &UiNode) -> bool {
310 previous.parent == next.parent
311 && previous.render_phase == next.render_phase
312 && previous.event_policy.focus == next.event_policy.focus
313 && previous.auto_focus == next.auto_focus
314 && previous.focus_scope == next.focus_scope
315}