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 forward(&mut self, message: Message, receipt: Receipt) {
89 self.bus.forward(message, receipt);
90 }
91
92 pub fn capture_event(&mut self) {
97 self.event_status = event::Status::Captured;
98 }
99
100 #[must_use]
102 pub fn event_status(&self) -> event::Status {
103 self.event_status
104 }
105
106 #[must_use]
108 pub fn is_event_captured(&self) -> bool {
109 self.event_status == event::Status::Captured
110 }
111
112 pub fn request_redraw(&mut self) {
114 self.redraw_request = window::RedrawRequest::NextFrame;
115 }
116
117 pub fn request_redraw_at(&mut self, redraw_request: impl Into<window::RedrawRequest>) {
119 self.redraw_request = self.redraw_request.min(redraw_request.into());
120 }
121
122 #[must_use]
124 pub fn redraw_request(&self) -> window::RedrawRequest {
125 self.redraw_request
126 }
127
128 pub fn replace_redraw_request(shell: &mut Self, redraw_request: window::RedrawRequest) {
134 shell.redraw_request = redraw_request;
135 }
136
137 pub fn read_clipboard(&mut self, kind: clipboard::Kind) {
141 self.clipboard.reads.push(kind);
142 }
143
144 pub fn write_clipboard(&mut self, content: impl Into<clipboard::Content>) {
148 self.clipboard.write = Some(content.into());
149 }
150
151 pub fn clipboard_mut(&mut self) -> &mut Clipboard {
153 &mut self.clipboard
154 }
155
156 pub fn request_input_method<T: AsRef<str>>(&mut self, ime: &InputMethod<T>) {
161 self.input_method.merge(ime);
162 }
163
164 #[must_use]
166 pub fn input_method(&self) -> &InputMethod {
167 &self.input_method
168 }
169
170 #[must_use]
172 pub fn input_method_mut(&mut self) -> &mut InputMethod {
173 &mut self.input_method
174 }
175
176 #[must_use]
178 pub fn is_layout_invalid(&self) -> Option<Diff> {
179 self.is_layout_invalid
180 }
181
182 pub fn invalidate_layout(&mut self) {
186 self.invalidate_layout_with(Diff::Skip);
187 }
188
189 pub fn invalidate_layout_with(&mut self, diff: Diff) {
191 self.is_layout_invalid = Some(diff);
192 }
193
194 pub fn revalidate_layout(&mut self, f: impl FnOnce(Diff)) {
197 if let Some(diff) = self.is_layout_invalid.take() {
198 f(diff);
199 }
200 }
201
202 #[must_use]
205 pub fn are_widgets_invalid(&self) -> bool {
206 self.are_widgets_invalid
207 }
208
209 pub fn invalidate_widgets(&mut self) {
213 self.are_widgets_invalid = true;
214 }
215
216 pub fn merge<B>(&mut self, mut other: Shell<'_, B>, f: impl Fn(B) -> Message) {
221 self.bus.messages.extend(
222 other
223 .bus
224 .messages
225 .drain(..)
226 .map(|(message, receipt)| (f(message), receipt)),
227 );
228
229 self.is_layout_invalid = match (self.is_layout_invalid, other.is_layout_invalid) {
230 (Some(a), Some(b)) => Some(a.max(b)),
231 _ => self.is_layout_invalid.or(other.is_layout_invalid),
232 };
233
234 self.are_widgets_invalid = self.are_widgets_invalid || other.are_widgets_invalid;
235 self.redraw_request = self.redraw_request.min(other.redraw_request);
236 self.event_status = self.event_status.merge(other.event_status);
237
238 self.input_method.merge(&other.input_method);
239 self.clipboard.merge(&mut other.clipboard);
240 }
241}
242
243#[derive(Clone)]
246pub struct Waker {
247 wake: Arc<dyn Fn() + Send + Sync + 'static>,
248}
249
250impl Waker {
251 pub fn new(wake: impl Fn() + Send + Sync + 'static) -> Self {
253 Self {
254 wake: Arc::new(wake),
255 }
256 }
257
258 pub fn noop() -> Self {
260 Self::new(|| {})
261 }
262
263 pub fn wake(&self) {
267 (self.wake)();
268 }
269}
270
271impl std::fmt::Debug for Waker {
272 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
273 f.debug_struct("Waker").finish()
274 }
275}
276
277#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
279pub enum Diff {
280 Skip,
282 Perform,
284}
285
286#[derive(Debug)]
288pub struct Bus<T> {
289 messages: Vec<(T, Receipt)>,
290}
291
292impl<T> Bus<T> {
293 pub fn new() -> Self {
295 Self {
296 messages: Vec::new(),
297 }
298 }
299
300 pub fn is_empty(&self) -> bool {
302 self.messages.is_empty()
303 }
304
305 pub fn len(&self) -> usize {
307 self.messages.len()
308 }
309
310 pub fn push(&mut self, message: T) -> Tracking {
315 let receipt = Receipt::new();
316 let tracking = receipt.tracking();
317
318 self.messages.push((message, receipt));
319
320 tracking
321 }
322
323 pub fn forward(&mut self, message: T, receipt: Receipt) {
325 self.messages.push((message, receipt));
326 }
327
328 pub fn drain(&mut self) -> impl Iterator<Item = (T, Receipt)> {
330 self.messages.drain(..)
331 }
332}
333
334impl<T> Default for Bus<T> {
335 fn default() -> Self {
336 Self::new()
337 }
338}
339
340impl<T> IntoIterator for Bus<T> {
341 type Item = T;
342 type IntoIter = IntoIter<T>;
343
344 fn into_iter(self) -> Self::IntoIter {
345 IntoIter {
346 iter: self.messages.into_iter(),
347 }
348 }
349}
350
351pub struct IntoIter<T> {
353 iter: vec::IntoIter<(T, Receipt)>,
354}
355
356impl<T> Iterator for IntoIter<T> {
357 type Item = T;
358
359 fn next(&mut self) -> Option<Self::Item> {
360 Some(self.iter.next()?.0)
361 }
362}
363
364#[derive(Debug)]
366pub struct Receipt(Rc<()>);
367
368impl Receipt {
369 fn new() -> Self {
370 Self(Rc::new(()))
371 }
372
373 fn tracking(&self) -> Tracking {
374 Tracking(Rc::downgrade(&self.0))
375 }
376}
377
378#[derive(Debug, Clone)]
380pub struct Tracking(rc::Weak<()>);
381
382impl Tracking {
383 pub fn is_processed(&self) -> bool {
386 self.0.strong_count() == 0
387 }
388}