iced_runtime/program/
state.rs

1use crate::core::event::{self, Event};
2use crate::core::mouse;
3use crate::core::renderer;
4use crate::core::widget::operation::{self, Operation};
5use crate::core::{Clipboard, Size};
6use crate::user_interface::{self, UserInterface};
7use crate::{Debug, Program, Task};
8
9/// The execution state of a [`Program`]. It leverages caching, event
10/// processing, and rendering primitive storage.
11#[allow(missing_debug_implementations)]
12pub struct State<P>
13where
14    P: Program + 'static,
15{
16    program: P,
17    cache: Option<user_interface::Cache>,
18    queued_events: Vec<Event>,
19    queued_messages: Vec<P::Message>,
20    mouse_interaction: mouse::Interaction,
21}
22
23impl<P> State<P>
24where
25    P: Program + 'static,
26{
27    /// Creates a new [`State`] with the provided [`Program`], initializing its
28    /// primitive with the given logical bounds and renderer.
29    pub fn new(
30        mut program: P,
31        bounds: Size,
32        renderer: &mut P::Renderer,
33        debug: &mut Debug,
34    ) -> Self {
35        let user_interface = build_user_interface(
36            &mut program,
37            user_interface::Cache::default(),
38            renderer,
39            bounds,
40            debug,
41        );
42
43        let cache = Some(user_interface.into_cache());
44
45        State {
46            program,
47            cache,
48            queued_events: Vec::new(),
49            queued_messages: Vec::new(),
50            mouse_interaction: mouse::Interaction::None,
51        }
52    }
53
54    /// Returns a reference to the [`Program`] of the [`State`].
55    pub fn program(&self) -> &P {
56        &self.program
57    }
58
59    /// Queues an event in the [`State`] for processing during an [`update`].
60    ///
61    /// [`update`]: Self::update
62    pub fn queue_event(&mut self, event: Event) {
63        self.queued_events.push(event);
64    }
65
66    /// Queues a message in the [`State`] for processing during an [`update`].
67    ///
68    /// [`update`]: Self::update
69    pub fn queue_message(&mut self, message: P::Message) {
70        self.queued_messages.push(message);
71    }
72
73    /// Returns whether the event queue of the [`State`] is empty or not.
74    pub fn is_queue_empty(&self) -> bool {
75        self.queued_events.is_empty() && self.queued_messages.is_empty()
76    }
77
78    /// Returns the current [`mouse::Interaction`] of the [`State`].
79    pub fn mouse_interaction(&self) -> mouse::Interaction {
80        self.mouse_interaction
81    }
82
83    /// Processes all the queued events and messages, rebuilding and redrawing
84    /// the widgets of the linked [`Program`] if necessary.
85    ///
86    /// Returns a list containing the instances of [`Event`] that were not
87    /// captured by any widget, and the [`Task`] obtained from [`Program`]
88    /// after updating it, only if an update was necessary.
89    pub fn update(
90        &mut self,
91        bounds: Size,
92        cursor: mouse::Cursor,
93        renderer: &mut P::Renderer,
94        theme: &P::Theme,
95        style: &renderer::Style,
96        clipboard: &mut dyn Clipboard,
97        debug: &mut Debug,
98    ) -> (Vec<Event>, Option<Task<P::Message>>) {
99        let mut user_interface = build_user_interface(
100            &mut self.program,
101            self.cache.take().unwrap(),
102            renderer,
103            bounds,
104            debug,
105        );
106
107        debug.event_processing_started();
108        let mut messages = Vec::new();
109
110        let (_, event_statuses) = user_interface.update(
111            &self.queued_events,
112            cursor,
113            renderer,
114            clipboard,
115            &mut messages,
116        );
117
118        let uncaptured_events = self
119            .queued_events
120            .iter()
121            .zip(event_statuses)
122            .filter_map(|(event, status)| {
123                matches!(status, event::Status::Ignored).then_some(event)
124            })
125            .cloned()
126            .collect();
127
128        self.queued_events.clear();
129        messages.append(&mut self.queued_messages);
130        debug.event_processing_finished();
131
132        let task = if messages.is_empty() {
133            debug.draw_started();
134            self.mouse_interaction =
135                user_interface.draw(renderer, theme, style, cursor);
136            debug.draw_finished();
137
138            self.cache = Some(user_interface.into_cache());
139
140            None
141        } else {
142            // When there are messages, we are forced to rebuild twice
143            // for now :^)
144            let temp_cache = user_interface.into_cache();
145
146            let tasks = Task::batch(messages.into_iter().map(|message| {
147                debug.log_message(&message);
148
149                debug.update_started();
150                let task = self.program.update(message);
151                debug.update_finished();
152
153                task
154            }));
155
156            let mut user_interface = build_user_interface(
157                &mut self.program,
158                temp_cache,
159                renderer,
160                bounds,
161                debug,
162            );
163
164            debug.draw_started();
165            self.mouse_interaction =
166                user_interface.draw(renderer, theme, style, cursor);
167            debug.draw_finished();
168
169            self.cache = Some(user_interface.into_cache());
170
171            Some(tasks)
172        };
173
174        (uncaptured_events, task)
175    }
176
177    /// Applies [`Operation`]s to the [`State`]
178    pub fn operate(
179        &mut self,
180        renderer: &mut P::Renderer,
181        operations: impl Iterator<Item = Box<dyn Operation>>,
182        bounds: Size,
183        debug: &mut Debug,
184    ) {
185        let mut user_interface = build_user_interface(
186            &mut self.program,
187            self.cache.take().unwrap(),
188            renderer,
189            bounds,
190            debug,
191        );
192
193        for operation in operations {
194            let mut current_operation = Some(operation);
195
196            while let Some(mut operation) = current_operation.take() {
197                user_interface.operate(renderer, operation.as_mut());
198
199                match operation.finish() {
200                    operation::Outcome::None => {}
201                    operation::Outcome::Some(()) => {}
202                    operation::Outcome::Chain(next) => {
203                        current_operation = Some(next);
204                    }
205                };
206            }
207        }
208
209        self.cache = Some(user_interface.into_cache());
210    }
211}
212
213fn build_user_interface<'a, P: Program>(
214    program: &'a mut P,
215    cache: user_interface::Cache,
216    renderer: &mut P::Renderer,
217    size: Size,
218    debug: &mut Debug,
219) -> UserInterface<'a, P::Message, P::Theme, P::Renderer> {
220    debug.view_started();
221    let view = program.view();
222    debug.view_finished();
223
224    debug.layout_started();
225    let user_interface = UserInterface::build(view, size, cache, renderer);
226    debug.layout_finished();
227
228    user_interface
229}