lgui_core/core/component/runtime/
animation.rs1use 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}