iced_runtime/multi_window/
state.rs

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