Skip to main content

lgui_core/core/view/tree/
mutation.rs

1use 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}