1use crate::clipboard;
3use crate::event;
4use crate::window;
5use crate::{Clipboard, InputMethod, Window};
6
7use std::rc::{self, Rc};
8use std::sync::Arc;
9use std::vec;
10
11#[derive(Debug)]
18pub struct Shell<'a, Message> {
19 window: &'a dyn Window,
20 bus: &'a mut Bus<Message>,
21 waker: Waker,
22 event_status: event::Status,
23 redraw_request: window::RedrawRequest,
24 input_method: InputMethod,
25 is_layout_invalid: Option<Diff>,
26 are_widgets_invalid: bool,
27 clipboard: Clipboard,
28}
29
30impl<'a, Message> Shell<'a, Message> {
31 pub fn new(window: &'a dyn Window, waker: Waker, bus: &'a mut Bus<Message>) -> Self {
33 Self {
34 window,
35 bus,
36 waker,
37 event_status: event::Status::Ignored,
38 redraw_request: window::RedrawRequest::Wait,
39 is_layout_invalid: None,
40 are_widgets_invalid: false,
41 input_method: InputMethod::Disabled,
42 clipboard: Clipboard {
43 reads: Vec::new(),
44 write: None,
45 },
46 }
47 }
48
49 pub fn local<'b, A>(&self, bus: &'b mut Bus<A>) -> Shell<'b, A>
51 where
52 'a: 'b,
53 {
54 Shell::new(self.window, self.waker.clone(), bus)
55 }
56
57 pub fn window(&self) -> &'a dyn Window {
59 self.window
60 }
61
62 pub fn waker(&self) -> &Waker {
64 &self.waker
65 }
66
67 #[must_use]
69 pub fn is_empty(&self) -> bool {
70 self.bus.messages.is_empty()
71 }
72
73 pub fn publish(&mut self, message: Message) {
75 let _ = self.publish_and_track(message);
76 }
77
78 pub fn publish_and_track(&mut self, message: Message) -> Tracking {
83 self.bus.push(message)
84 }
85
86 pub fn capture_event(&mut self) {
91 self.event_status = event::Status::Captured;
92 }
93
94 #[must_use]
96 pub fn event_status(&self) -> event::Status {
97 self.event_status
98 }
99
100 #[must_use]
102 pub fn is_event_captured(&self) -> bool {
103 self.event_status == event::Status::Captured
104 }
105
106 pub fn request_redraw(&mut self) {
108 self.redraw_request = window::RedrawRequest::NextFrame;
109 }
110
111 pub fn request_redraw_at(&mut self, redraw_request: impl Into<window::RedrawRequest>) {
113 self.redraw_request = self.redraw_request.min(redraw_request.into());
114 }
115
116 #[must_use]
118 pub fn redraw_request(&self) -> window::RedrawRequest {
119 self.redraw_request
120 }
121
122 pub fn replace_redraw_request(shell: &mut Self, redraw_request: window::RedrawRequest) {
128 shell.redraw_request = redraw_request;
129 }
130
131 pub fn read_clipboard(&mut self, kind: clipboard::Kind) {
135 self.clipboard.reads.push(kind);
136 }
137
138 pub fn write_clipboard(&mut self, content: impl Into<clipboard::Content>) {
142 self.clipboard.write = Some(content.into());
143 }
144
145 pub fn clipboard_mut(&mut self) -> &mut Clipboard {
147 &mut self.clipboard
148 }
149
150 pub fn request_input_method<T: AsRef<str>>(&mut self, ime: &InputMethod<T>) {
155 self.input_method.merge(ime);
156 }
157
158 #[must_use]
160 pub fn input_method(&self) -> &InputMethod {
161 &self.input_method
162 }
163
164 #[must_use]
166 pub fn input_method_mut(&mut self) -> &mut InputMethod {
167 &mut self.input_method
168 }
169
170 #[must_use]
172 pub fn is_layout_invalid(&self) -> Option<Diff> {
173 self.is_layout_invalid
174 }
175
176 pub fn invalidate_layout(&mut self) {
180 self.invalidate_layout_with(Diff::Skip);
181 }
182
183 pub fn invalidate_layout_with(&mut self, diff: Diff) {
185 self.is_layout_invalid = Some(diff);
186 }
187
188 pub fn revalidate_layout(&mut self, f: impl FnOnce(Diff)) {
191 if let Some(diff) = self.is_layout_invalid.take() {
192 f(diff);
193 }
194 }
195
196 #[must_use]
199 pub fn are_widgets_invalid(&self) -> bool {
200 self.are_widgets_invalid
201 }
202
203 pub fn invalidate_widgets(&mut self) {
207 self.are_widgets_invalid = true;
208 }
209
210 pub fn merge<B>(&mut self, mut other: Shell<'_, B>, f: impl Fn(B) -> Message) {
215 self.bus.messages.extend(
216 other
217 .bus
218 .messages
219 .drain(..)
220 .map(|(message, receipt)| (f(message), receipt)),
221 );
222
223 self.is_layout_invalid = match (self.is_layout_invalid, other.is_layout_invalid) {
224 (Some(a), Some(b)) => Some(a.max(b)),
225 _ => self.is_layout_invalid.or(other.is_layout_invalid),
226 };
227
228 self.are_widgets_invalid = self.are_widgets_invalid || other.are_widgets_invalid;
229 self.redraw_request = self.redraw_request.min(other.redraw_request);
230 self.event_status = self.event_status.merge(other.event_status);
231
232 self.input_method.merge(&other.input_method);
233 self.clipboard.merge(&mut other.clipboard);
234 }
235}
236
237#[derive(Clone)]
240pub struct Waker {
241 wake: Arc<dyn Fn() + Send + Sync + 'static>,
242}
243
244impl Waker {
245 pub fn new(wake: impl Fn() + Send + Sync + 'static) -> Self {
247 Self {
248 wake: Arc::new(wake),
249 }
250 }
251
252 pub fn noop() -> Self {
254 Self::new(|| {})
255 }
256
257 pub fn wake(&self) {
261 (self.wake)();
262 }
263}
264
265impl std::fmt::Debug for Waker {
266 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
267 f.debug_struct("Waker").finish()
268 }
269}
270
271#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
273pub enum Diff {
274 Skip,
276 Perform,
278}
279
280#[derive(Debug)]
282pub struct Bus<T> {
283 messages: Vec<(T, Rc<()>)>,
284}
285
286impl<T> Bus<T> {
287 pub fn new() -> Self {
289 Self {
290 messages: Vec::new(),
291 }
292 }
293
294 pub fn is_empty(&self) -> bool {
296 self.messages.is_empty()
297 }
298
299 pub fn len(&self) -> usize {
301 self.messages.len()
302 }
303
304 pub fn push(&mut self, message: T) -> Tracking {
309 let receipt = Rc::new(());
310 let tracking = Tracking(Rc::downgrade(&receipt));
311
312 self.messages.push((message, receipt));
313
314 tracking
315 }
316
317 pub fn drain(&mut self) -> impl Iterator<Item = T> {
319 self.messages.drain(..).map(|(message, _receipt)| message)
320 }
321}
322
323impl<T> Default for Bus<T> {
324 fn default() -> Self {
325 Self::new()
326 }
327}
328
329impl<T> IntoIterator for Bus<T> {
330 type Item = T;
331 type IntoIter = IntoIter<T>;
332
333 fn into_iter(self) -> Self::IntoIter {
334 IntoIter {
335 iter: self.messages.into_iter(),
336 }
337 }
338}
339
340pub struct IntoIter<T> {
342 iter: vec::IntoIter<(T, Rc<()>)>,
343}
344
345impl<T> Iterator for IntoIter<T> {
346 type Item = T;
347
348 fn next(&mut self) -> Option<Self::Item> {
349 Some(self.iter.next()?.0)
350 }
351}
352
353#[derive(Debug, Clone)]
355pub struct Tracking(rc::Weak<()>);
356
357impl Tracking {
358 pub fn is_processed(&self) -> bool {
361 self.0.strong_count() == 0
362 }
363}