Skip to main content

iced_core/
shell.rs

1use crate::clipboard;
2use crate::event;
3use crate::window;
4use crate::{Clipboard, InputMethod};
5
6/// A connection to the state of a shell.
7///
8/// A [`Widget`] can leverage a [`Shell`] to trigger changes in an application,
9/// like publishing messages or invalidating the current layout.
10///
11/// [`Widget`]: crate::Widget
12#[derive(Debug)]
13pub struct Shell<'a, Message> {
14    messages: &'a mut Vec<Message>,
15    event_status: event::Status,
16    redraw_request: window::RedrawRequest,
17    input_method: InputMethod,
18    is_layout_invalid: bool,
19    are_widgets_invalid: bool,
20    clipboard: Clipboard,
21}
22
23impl<'a, Message> Shell<'a, Message> {
24    /// Creates a new [`Shell`] with the provided buffer of messages.
25    pub fn new(messages: &'a mut Vec<Message>) -> Self {
26        Self {
27            messages,
28            event_status: event::Status::Ignored,
29            redraw_request: window::RedrawRequest::Wait,
30            is_layout_invalid: false,
31            are_widgets_invalid: false,
32            input_method: InputMethod::Disabled,
33            clipboard: Clipboard {
34                reads: Vec::new(),
35                write: None,
36            },
37        }
38    }
39
40    /// Returns true if the [`Shell`] contains no published messages
41    #[must_use]
42    pub fn is_empty(&self) -> bool {
43        self.messages.is_empty()
44    }
45
46    /// Publish the given `Message` for an application to process it.
47    pub fn publish(&mut self, message: Message) {
48        self.messages.push(message);
49    }
50
51    /// Marks the current event as captured. Prevents "event bubbling".
52    ///
53    /// A widget should capture an event when no ancestor should
54    /// handle it.
55    pub fn capture_event(&mut self) {
56        self.event_status = event::Status::Captured;
57    }
58
59    /// Returns the current [`event::Status`] of the [`Shell`].
60    #[must_use]
61    pub fn event_status(&self) -> event::Status {
62        self.event_status
63    }
64
65    /// Returns whether the current event has been captured.
66    #[must_use]
67    pub fn is_event_captured(&self) -> bool {
68        self.event_status == event::Status::Captured
69    }
70
71    /// Requests a new frame to be drawn as soon as possible.
72    pub fn request_redraw(&mut self) {
73        self.redraw_request = window::RedrawRequest::NextFrame;
74    }
75
76    /// Requests a new frame to be drawn at the given [`window::RedrawRequest`].
77    pub fn request_redraw_at(&mut self, redraw_request: impl Into<window::RedrawRequest>) {
78        self.redraw_request = self.redraw_request.min(redraw_request.into());
79    }
80
81    /// Returns the request a redraw should happen, if any.
82    #[must_use]
83    pub fn redraw_request(&self) -> window::RedrawRequest {
84        self.redraw_request
85    }
86
87    /// Replaces the redraw request of the [`Shell`]; without conflict resolution.
88    ///
89    /// This is useful if you want to overwrite the redraw request to a previous value.
90    /// Since it's a fairly advanced use case and should rarely be used, it is a static
91    /// method.
92    pub fn replace_redraw_request(shell: &mut Self, redraw_request: window::RedrawRequest) {
93        shell.redraw_request = redraw_request;
94    }
95
96    /// Requests the runtime to read the clipboard contents expecting the given [`clipboard::Kind`].
97    ///
98    /// The runtime will produce a [`clipboard::Event::Read`] when the contents have been read.
99    pub fn read_clipboard(&mut self, kind: clipboard::Kind) {
100        self.clipboard.reads.push(kind);
101    }
102
103    /// Requests the runtime to write the given [`clipboard::Content`] to the clipboard.
104    ///
105    /// The runtime will produce a [`clipboard::Event::Written`] when the contents have been written.
106    pub fn write_clipboard(&mut self, content: clipboard::Content) {
107        self.clipboard.write = Some(content);
108    }
109
110    /// Returns the [`Clipboard`] requests of the [`Shell`], mutably.
111    pub fn clipboard_mut(&mut self) -> &mut Clipboard {
112        &mut self.clipboard
113    }
114
115    /// Requests the current [`InputMethod`] strategy.
116    ///
117    /// __Important__: This request will only be honored by the
118    /// [`Shell`] only during a [`window::Event::RedrawRequested`].
119    pub fn request_input_method<T: AsRef<str>>(&mut self, ime: &InputMethod<T>) {
120        self.input_method.merge(ime);
121    }
122
123    /// Returns the current [`InputMethod`] strategy.
124    #[must_use]
125    pub fn input_method(&self) -> &InputMethod {
126        &self.input_method
127    }
128
129    /// Returns the current [`InputMethod`] strategy.
130    #[must_use]
131    pub fn input_method_mut(&mut self) -> &mut InputMethod {
132        &mut self.input_method
133    }
134
135    /// Returns whether the current layout is invalid or not.
136    #[must_use]
137    pub fn is_layout_invalid(&self) -> bool {
138        self.is_layout_invalid
139    }
140
141    /// Invalidates the current application layout.
142    ///
143    /// The shell will relayout the application widgets.
144    pub fn invalidate_layout(&mut self) {
145        self.is_layout_invalid = true;
146    }
147
148    /// Triggers the given function if the layout is invalid, cleaning it in the
149    /// process.
150    pub fn revalidate_layout(&mut self, f: impl FnOnce()) {
151        if self.is_layout_invalid {
152            self.is_layout_invalid = false;
153
154            f();
155        }
156    }
157
158    /// Returns whether the widgets of the current application have been
159    /// invalidated.
160    #[must_use]
161    pub fn are_widgets_invalid(&self) -> bool {
162        self.are_widgets_invalid
163    }
164
165    /// Invalidates the current application widgets.
166    ///
167    /// The shell will rebuild and relayout the widget tree.
168    pub fn invalidate_widgets(&mut self) {
169        self.are_widgets_invalid = true;
170    }
171
172    /// Merges the current [`Shell`] with another one by applying the given
173    /// function to the messages of the latter.
174    ///
175    /// This method is useful for composition.
176    pub fn merge<B>(&mut self, mut other: Shell<'_, B>, f: impl Fn(B) -> Message) {
177        self.messages.extend(other.messages.drain(..).map(f));
178
179        self.is_layout_invalid = self.is_layout_invalid || other.is_layout_invalid;
180        self.are_widgets_invalid = self.are_widgets_invalid || other.are_widgets_invalid;
181        self.redraw_request = self.redraw_request.min(other.redraw_request);
182        self.event_status = self.event_status.merge(other.event_status);
183
184        self.input_method.merge(&other.input_method);
185        self.clipboard.merge(&mut other.clipboard);
186    }
187}