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#[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 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 pub fn program(&self) -> &P {
56 &self.program
57 }
58
59 pub fn queue_event(&mut self, event: Event) {
63 self.queued_events.push(event);
64 }
65
66 pub fn queue_message(&mut self, message: P::Message) {
70 self.queued_messages.push(message);
71 }
72
73 pub fn is_queue_empty(&self) -> bool {
75 self.queued_events.is_empty() && self.queued_messages.is_empty()
76 }
77
78 pub fn mouse_interaction(&self) -> mouse::Interaction {
80 self.mouse_interaction
81 }
82
83 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 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 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}