1use crate::clipboard;
3use crate::event;
4use crate::window;
5use crate::{Clipboard, InputMethod, Window};
6
7use std::sync::Arc;
8
9#[derive(Debug)]
16pub struct Shell<'a, Message> {
17 window: &'a dyn Window,
18 messages: &'a mut Vec<Message>,
19 waker: Waker,
20 event_status: event::Status,
21 redraw_request: window::RedrawRequest,
22 input_method: InputMethod,
23 is_layout_invalid: Option<Diff>,
24 are_widgets_invalid: bool,
25 clipboard: Clipboard,
26}
27
28impl<'a, Message> Shell<'a, Message> {
29 pub fn new(window: &'a dyn Window, waker: Waker, messages: &'a mut Vec<Message>) -> Self {
31 Self {
32 window,
33 messages,
34 waker,
35 event_status: event::Status::Ignored,
36 redraw_request: window::RedrawRequest::Wait,
37 is_layout_invalid: None,
38 are_widgets_invalid: false,
39 input_method: InputMethod::Disabled,
40 clipboard: Clipboard {
41 reads: Vec::new(),
42 write: None,
43 },
44 }
45 }
46
47 pub fn local<'b, A>(&self, messages: &'b mut Vec<A>) -> Shell<'b, A>
49 where
50 'a: 'b,
51 {
52 Shell::new(self.window, self.waker.clone(), messages)
53 }
54
55 pub fn window(&self) -> &'a dyn Window {
57 self.window
58 }
59
60 pub fn waker(&self) -> &Waker {
62 &self.waker
63 }
64
65 #[must_use]
67 pub fn is_empty(&self) -> bool {
68 self.messages.is_empty()
69 }
70
71 pub fn publish(&mut self, message: Message) {
73 self.messages.push(message);
74 }
75
76 pub fn capture_event(&mut self) {
81 self.event_status = event::Status::Captured;
82 }
83
84 #[must_use]
86 pub fn event_status(&self) -> event::Status {
87 self.event_status
88 }
89
90 #[must_use]
92 pub fn is_event_captured(&self) -> bool {
93 self.event_status == event::Status::Captured
94 }
95
96 pub fn request_redraw(&mut self) {
98 self.redraw_request = window::RedrawRequest::NextFrame;
99 }
100
101 pub fn request_redraw_at(&mut self, redraw_request: impl Into<window::RedrawRequest>) {
103 self.redraw_request = self.redraw_request.min(redraw_request.into());
104 }
105
106 #[must_use]
108 pub fn redraw_request(&self) -> window::RedrawRequest {
109 self.redraw_request
110 }
111
112 pub fn replace_redraw_request(shell: &mut Self, redraw_request: window::RedrawRequest) {
118 shell.redraw_request = redraw_request;
119 }
120
121 pub fn read_clipboard(&mut self, kind: clipboard::Kind) {
125 self.clipboard.reads.push(kind);
126 }
127
128 pub fn write_clipboard(&mut self, content: clipboard::Content) {
132 self.clipboard.write = Some(content);
133 }
134
135 pub fn clipboard_mut(&mut self) -> &mut Clipboard {
137 &mut self.clipboard
138 }
139
140 pub fn request_input_method<T: AsRef<str>>(&mut self, ime: &InputMethod<T>) {
145 self.input_method.merge(ime);
146 }
147
148 #[must_use]
150 pub fn input_method(&self) -> &InputMethod {
151 &self.input_method
152 }
153
154 #[must_use]
156 pub fn input_method_mut(&mut self) -> &mut InputMethod {
157 &mut self.input_method
158 }
159
160 #[must_use]
162 pub fn is_layout_invalid(&self) -> Option<Diff> {
163 self.is_layout_invalid
164 }
165
166 pub fn invalidate_layout(&mut self) {
170 self.invalidate_layout_with(Diff::Skip);
171 }
172
173 pub fn invalidate_layout_with(&mut self, diff: Diff) {
175 self.is_layout_invalid = Some(diff);
176 }
177
178 pub fn revalidate_layout(&mut self, f: impl FnOnce(Diff)) {
181 if let Some(diff) = self.is_layout_invalid.take() {
182 f(diff);
183 }
184 }
185
186 #[must_use]
189 pub fn are_widgets_invalid(&self) -> bool {
190 self.are_widgets_invalid
191 }
192
193 pub fn invalidate_widgets(&mut self) {
197 self.are_widgets_invalid = true;
198 }
199
200 pub fn merge<B>(&mut self, mut other: Shell<'_, B>, f: impl Fn(B) -> Message) {
205 self.messages.extend(other.messages.drain(..).map(f));
206
207 self.is_layout_invalid = match (self.is_layout_invalid, other.is_layout_invalid) {
208 (Some(a), Some(b)) => Some(a.max(b)),
209 _ => self.is_layout_invalid.or(other.is_layout_invalid),
210 };
211
212 self.are_widgets_invalid = self.are_widgets_invalid || other.are_widgets_invalid;
213 self.redraw_request = self.redraw_request.min(other.redraw_request);
214 self.event_status = self.event_status.merge(other.event_status);
215
216 self.input_method.merge(&other.input_method);
217 self.clipboard.merge(&mut other.clipboard);
218 }
219}
220
221#[derive(Clone)]
224pub struct Waker {
225 wake: Arc<dyn Fn() + Send + Sync + 'static>,
226}
227
228impl Waker {
229 pub fn new(wake: impl Fn() + Send + Sync + 'static) -> Self {
231 Self {
232 wake: Arc::new(wake),
233 }
234 }
235
236 pub fn noop() -> Self {
238 Self::new(|| {})
239 }
240
241 pub fn wake(&self) {
245 (self.wake)();
246 }
247}
248
249impl std::fmt::Debug for Waker {
250 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
251 f.debug_struct("Waker").finish()
252 }
253}
254
255#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
257pub enum Diff {
258 Skip,
260 Perform,
262}