lgui_core/core/component/runtime/
state.rs1use super::*;
2
3pub struct RuntimeOutput {
4 pub events: Vec<UiEvent>,
5 pub handler_events: Vec<UiHandlerEvent>,
6 pub action_events: Vec<UiActionEvent>,
7 pub default_actions: Vec<UiDefaultAction>,
8 pub dirty_bounds: Option<UiRect>,
9 pub animation_changed: bool,
10 pub route_changed: bool,
11}
12
13#[derive(Clone, Debug, Default, PartialEq, Eq)]
14pub struct PendingUpdateOutput {
15 pub dirty_ids: Vec<UiId>,
16 pub focus_changed: bool,
17 pub frame_requested: bool,
18}
19
20#[derive(Clone, Debug)]
21pub struct UiDefaultAction {
22 pub event_target: UiId,
23 pub action_target: UiId,
24 pub action: UiAction,
25}
26
27#[derive(Default)]
28pub struct UiRuntime {
29 pub(super) events: UiEventDispatcher,
30 pub(super) animations: AnimationRegistry,
31 pub(super) component_states: ComponentStateStore,
32 pub(super) component_tree: ComponentTree,
33 pub(super) contexts: ContextRegistry,
34 pub(super) hook_states: HookStateStore,
35 pub(super) hook_updates: Arc<UiUpdateQueue>,
36 pub(super) task_spawner: Option<UiTaskSpawner>,
37 pub(super) effects: EffectRegistry,
38 pub(super) dirty: DirtyTracker,
39 pub(super) frame_interval_ms: Option<u64>,
40}
41
42impl UiRuntime {
43 pub fn new() -> Self {
44 Self::default()
45 }
46
47 pub fn reset(&mut self) {
48 let hook_updates = Arc::clone(&self.hook_updates);
49 let task_spawner = self.task_spawner.clone();
50 hook_updates.clear();
51 *self = Self {
52 hook_updates,
53 task_spawner,
54 ..Self::default()
55 };
56 }
57
58 pub fn animations(&self) -> &AnimationRegistry {
59 &self.animations
60 }
61
62 pub fn animations_mut(&mut self) -> &mut AnimationRegistry {
63 &mut self.animations
64 }
65
66 pub fn component_states(&self) -> &ComponentStateStore {
67 &self.component_states
68 }
69
70 pub fn component_tree(&self) -> &ComponentTree {
71 &self.component_tree
72 }
73
74 pub fn frame_interval_ms(&self) -> Option<u64> {
75 [
76 self.frame_interval_ms,
77 self.animations.is_running().then_some(16),
78 self.component_states.requested_frame_interval_ms(),
79 ]
80 .into_iter()
81 .flatten()
82 .min()
83 }
84
85 pub fn invalidate_all_components(&self) {
86 self.component_tree.mark_all_dirty();
87 }
88
89 pub fn contexts(&self) -> &ContextRegistry {
90 &self.contexts
91 }
92
93 pub fn hook_states(&self) -> &HookStateStore {
94 &self.hook_states
95 }
96
97 pub fn hook_updates(&self) -> &Arc<UiUpdateQueue> {
98 &self.hook_updates
99 }
100
101 pub fn set_wake(&self, wake: UiWake) {
102 self.hook_updates.set_wake(wake);
103 }
104
105 pub fn set_task_spawner(&mut self, spawner: UiTaskSpawner) {
106 self.task_spawner = Some(spawner);
107 }
108
109 pub fn task_spawner(&self) -> Option<&UiTaskSpawner> {
110 self.task_spawner.as_ref()
111 }
112
113 pub fn apply_pending_updates(&mut self, tree: &HostTree) -> PendingUpdateOutput {
114 let dirty = self
115 .hook_updates
116 .apply(&self.hook_states, &self.component_tree);
117 let focus_changed = self
118 .hook_updates
119 .take_focus_request()
120 .is_some_and(|target| self.focus_node(tree, &target));
121 if focus_changed {
122 let _ = self.dirty.take();
125 }
126 let frame_requested = self.hook_updates.take_frame_request();
127 PendingUpdateOutput {
128 dirty_ids: dirty,
129 focus_changed,
130 frame_requested,
131 }
132 }
133
134 pub fn effects(&self) -> &EffectRegistry {
135 &self.effects
136 }
137
138 pub fn run_effects(&self) {
139 self.effects.run_pending();
140 }
141
142 pub fn interaction_state(&self) -> super::UiInteractionState {
143 self.events.state()
144 }
145
146 pub fn clear_interaction_state(&mut self) -> bool {
147 let state_changed = self.events.clear_interaction_state();
148 let animation_changed = self.animations.clear_targets(&[
149 AnimProperty::Hover,
150 AnimProperty::Pressed,
151 AnimProperty::Focus,
152 ]);
153 state_changed || animation_changed
154 }
155
156 pub fn clear_effects(&mut self) {
157 self.effects.clear();
158 }
159
160 pub fn clear_hook_state(&mut self) {
161 self.hook_updates.clear();
162 self.hook_states.clear();
163 }
164
165 pub(crate) fn suspend_rendering(&mut self) {
166 self.clear_interaction_state();
167 self.dirty = DirtyTracker::default();
168 }
169
170 pub(super) fn mark_component_owners<'a>(
171 &self,
172 tree: &HostTree,
173 ids: impl IntoIterator<Item = &'a UiId>,
174 ) {
175 for id in ids {
176 if let Some(owner) = tree.node(id).and_then(|node| node.component_owner) {
177 self.component_tree.mark_dirty(owner);
178 }
179 }
180 }
181}