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