1use crate::InputMethod;
2use crate::event;
3use crate::window;
45/// A connection to the state of a shell.
6///
7/// A [`Widget`] can leverage a [`Shell`] to trigger changes in an application,
8/// like publishing messages or invalidating the current layout.
9///
10/// [`Widget`]: crate::Widget
11#[derive(Debug)]
12pub struct Shell<'a, Message> {
13 messages: &'a mut Vec<Message>,
14 event_status: event::Status,
15 redraw_request: window::RedrawRequest,
16 input_method: InputMethod,
17 is_layout_invalid: bool,
18 are_widgets_invalid: bool,
19}
2021impl<'a, Message> Shell<'a, Message> {
22/// Creates a new [`Shell`] with the provided buffer of messages.
23pub fn new(messages: &'a mut Vec<Message>) -> Self {
24Self {
25 messages,
26 event_status: event::Status::Ignored,
27 redraw_request: window::RedrawRequest::Wait,
28 is_layout_invalid: false,
29 are_widgets_invalid: false,
30 input_method: InputMethod::Disabled,
31 }
32 }
3334/// Returns true if the [`Shell`] contains no published messages
35#[must_use]
36pub fn is_empty(&self) -> bool {
37self.messages.is_empty()
38 }
3940/// Publish the given `Message` for an application to process it.
41pub fn publish(&mut self, message: Message) {
42self.messages.push(message);
43 }
4445/// Marks the current event as captured. Prevents "event bubbling".
46 ///
47 /// A widget should capture an event when no ancestor should
48 /// handle it.
49pub fn capture_event(&mut self) {
50self.event_status = event::Status::Captured;
51 }
5253/// Returns the current [`event::Status`] of the [`Shell`].
54#[must_use]
55pub fn event_status(&self) -> event::Status {
56self.event_status
57 }
5859/// Returns whether the current event has been captured.
60#[must_use]
61pub fn is_event_captured(&self) -> bool {
62self.event_status == event::Status::Captured
63 }
6465/// Requests a new frame to be drawn as soon as possible.
66pub fn request_redraw(&mut self) {
67self.redraw_request = window::RedrawRequest::NextFrame;
68 }
6970/// Requests a new frame to be drawn at the given [`window::RedrawRequest`].
71pub fn request_redraw_at(
72&mut self,
73 redraw_request: impl Into<window::RedrawRequest>,
74 ) {
75self.redraw_request = self.redraw_request.min(redraw_request.into());
76 }
7778/// Returns the request a redraw should happen, if any.
79#[must_use]
80pub fn redraw_request(&self) -> window::RedrawRequest {
81self.redraw_request
82 }
8384/// Replaces the redraw request of the [`Shell`]; without conflict resolution.
85 ///
86 /// This is useful if you want to overwrite the redraw request to a previous value.
87 /// Since it's a fairly advanced use case and should rarely be used, it is a static
88 /// method.
89pub fn replace_redraw_request(
90 shell: &mut Self,
91 redraw_request: window::RedrawRequest,
92 ) {
93 shell.redraw_request = redraw_request;
94 }
9596/// Requests the current [`InputMethod`] strategy.
97 ///
98 /// __Important__: This request will only be honored by the
99 /// [`Shell`] only during a [`window::Event::RedrawRequested`].
100pub fn request_input_method<T: AsRef<str>>(
101&mut self,
102 ime: &InputMethod<T>,
103 ) {
104self.input_method.merge(ime);
105 }
106107/// Returns the current [`InputMethod`] strategy.
108#[must_use]
109pub fn input_method(&self) -> &InputMethod {
110&self.input_method
111 }
112113/// Returns the current [`InputMethod`] strategy.
114#[must_use]
115pub fn input_method_mut(&mut self) -> &mut InputMethod {
116&mut self.input_method
117 }
118119/// Returns whether the current layout is invalid or not.
120#[must_use]
121pub fn is_layout_invalid(&self) -> bool {
122self.is_layout_invalid
123 }
124125/// Invalidates the current application layout.
126 ///
127 /// The shell will relayout the application widgets.
128pub fn invalidate_layout(&mut self) {
129self.is_layout_invalid = true;
130 }
131132/// Triggers the given function if the layout is invalid, cleaning it in the
133 /// process.
134pub fn revalidate_layout(&mut self, f: impl FnOnce()) {
135if self.is_layout_invalid {
136self.is_layout_invalid = false;
137138 f();
139 }
140 }
141142/// Returns whether the widgets of the current application have been
143 /// invalidated.
144#[must_use]
145pub fn are_widgets_invalid(&self) -> bool {
146self.are_widgets_invalid
147 }
148149/// Invalidates the current application widgets.
150 ///
151 /// The shell will rebuild and relayout the widget tree.
152pub fn invalidate_widgets(&mut self) {
153self.are_widgets_invalid = true;
154 }
155156/// Merges the current [`Shell`] with another one by applying the given
157 /// function to the messages of the latter.
158 ///
159 /// This method is useful for composition.
160pub fn merge<B>(&mut self, other: Shell<'_, B>, f: impl Fn(B) -> Message) {
161self.messages.extend(other.messages.drain(..).map(f));
162163self.is_layout_invalid =
164self.is_layout_invalid || other.is_layout_invalid;
165166self.are_widgets_invalid =
167self.are_widgets_invalid || other.are_widgets_invalid;
168169self.redraw_request = self.redraw_request.min(other.redraw_request);
170self.event_status = self.event_status.merge(other.event_status);
171self.input_method.merge(&other.input_method);
172 }
173}