Skip to main content

lgui_core/core/component/runtime/
animation.rs

1use super::{input::event_target_ids, *};
2
3impl UiRuntime {
4    pub fn advance(&mut self, tree: &mut HostTree, elapsed_ms: f32) -> RuntimeOutput {
5        let animation_changed = self.animations.advance(elapsed_ms);
6        let mut frame_interval_ms = animation_changed.then_some(16);
7        let animation_ids = self.animations.take_dirty_ids();
8        self.mark_component_owners(tree, animation_ids.iter());
9        self.dirty.mark_animation_ids(animation_ids);
10        let component_invalidations = self.component_states.advance_invalidations(elapsed_ms);
11        let component_changed = !component_invalidations.is_empty();
12        let mut route_changed = false;
13        let mut retained_dirty_bounds: Option<UiRect> = None;
14        let mut regular_dirty_ids = Vec::new();
15        for invalidation in &component_invalidations {
16            frame_interval_ms = Some(
17                frame_interval_ms.map_or(invalidation.frame_interval_ms, |current| {
18                    current.min(invalidation.frame_interval_ms)
19                }),
20            );
21            if let Some(RetainedNodeUpdate::CompositingLayer(spec)) = invalidation.retained_update {
22                if let Some(bounds) = tree.update_compositing_layer(&invalidation.target_id, spec) {
23                    retained_dirty_bounds =
24                        Some(retained_dirty_bounds.map_or(bounds, |current| current.union(bounds)));
25                }
26            } else if let Some(owner) = invalidation.owner {
27                self.component_tree.mark_dirty(owner);
28                regular_dirty_ids.push(invalidation.target_id.clone());
29            } else {
30                self.mark_component_owners(tree, std::iter::once(&invalidation.target_id));
31                regular_dirty_ids.push(invalidation.target_id.clone());
32            }
33            route_changed |= self
34                .component_states
35                .take_route_invalidation(&invalidation.state_id);
36        }
37        self.dirty.mark_animation_ids(regular_dirty_ids);
38        let dirty_bounds = match (self.dirty.take().bounds(tree), retained_dirty_bounds) {
39            (Some(regular), Some(retained)) => Some(regular.union(retained)),
40            (Some(bounds), None) | (None, Some(bounds)) => Some(bounds),
41            (None, None) => None,
42        };
43        self.frame_interval_ms = frame_interval_ms;
44        RuntimeOutput {
45            events: Vec::new(),
46            handler_events: Vec::new(),
47            action_events: Vec::new(),
48            default_actions: Vec::new(),
49            dirty_bounds,
50            animation_changed: animation_changed || component_changed,
51            route_changed,
52        }
53    }
54
55    pub fn sync_tree_animation_targets(&mut self, tree: &HostTree) -> bool {
56        let mut changed = false;
57        let interaction_events = self.events.sync_interaction_for_tree(tree);
58        self.mark_component_owners(tree, interaction_events.iter().flat_map(event_target_ids));
59        for event in interaction_events.iter().cloned() {
60            self.dirty.mark_event(event);
61        }
62        changed |=
63            apply_events_to_animations(tree, &mut self.animations, interaction_events.into_iter());
64        changed |= self.animations.clear_absent_values_by(
65            |id| tree.node(id).is_some(),
66            &[
67                AnimProperty::Hover,
68                AnimProperty::Active,
69                AnimProperty::Pressed,
70                AnimProperty::Focus,
71            ],
72        );
73        let sync_ids = tree.animation_sync_ids().cloned().collect::<Vec<_>>();
74        for node in sync_ids.iter().filter_map(|id| tree.node(id)) {
75            for (property, active) in node.animation_targets.iter().copied() {
76                for binding in node
77                    .animation_bindings
78                    .iter()
79                    .copied()
80                    .filter(|binding| binding.property == property)
81                {
82                    if self
83                        .animations
84                        .sync_binding_target(node.id.clone(), binding, active)
85                    {
86                        if let Some(owner) = node.component_owner {
87                            self.component_tree.mark_dirty(owner);
88                        }
89                        self.dirty.mark_id(node.id.clone());
90                        changed = true;
91                    }
92                }
93            }
94        }
95        changed
96    }
97}