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
35pub fn is_empty(&self) -> bool {
36self.messages.is_empty()
37 }
3839/// Publish the given `Message` for an application to process it.
40pub fn publish(&mut self, message: Message) {
41self.messages.push(message);
42 }
4344/// Marks the current event as captured. Prevents "event bubbling".
45 ///
46 /// A widget should capture an event when no ancestor should
47 /// handle it.
48pub fn capture_event(&mut self) {
49self.event_status = event::Status::Captured;
50 }
5152/// Returns the current [`event::Status`] of the [`Shell`].
53pub fn event_status(&self) -> event::Status {
54self.event_status
55 }
5657/// Returns whether the current event has been captured.
58pub fn is_event_captured(&self) -> bool {
59self.event_status == event::Status::Captured
60 }
6162/// Requests a new frame to be drawn as soon as possible.
63pub fn request_redraw(&mut self) {
64self.redraw_request = window::RedrawRequest::NextFrame;
65 }
6667/// Requests a new frame to be drawn at the given [`window::RedrawRequest`].
68pub fn request_redraw_at(
69&mut self,
70 redraw_request: impl Into<window::RedrawRequest>,
71 ) {
72self.redraw_request = self.redraw_request.min(redraw_request.into());
73 }
7475/// Returns the request a redraw should happen, if any.
76pub fn redraw_request(&self) -> window::RedrawRequest {
77self.redraw_request
78 }
7980/// Replaces the redraw request of the [`Shell`]; without conflict resolution.
81 ///
82 /// This is useful if you want to overwrite the redraw request to a previous value.
83 /// Since it's a fairly advanced use case and should rarely be used, it is a static
84 /// method.
85pub fn replace_redraw_request(
86 shell: &mut Self,
87 redraw_request: window::RedrawRequest,
88 ) {
89 shell.redraw_request = redraw_request;
90 }
9192/// Requests the current [`InputMethod`] strategy.
93 ///
94 /// __Important__: This request will only be honored by the
95 /// [`Shell`] only during a [`window::Event::RedrawRequested`].
96pub fn request_input_method<T: AsRef<str>>(
97&mut self,
98 ime: &InputMethod<T>,
99 ) {
100self.input_method.merge(ime);
101 }
102103/// Returns the current [`InputMethod`] strategy.
104pub fn input_method(&self) -> &InputMethod {
105&self.input_method
106 }
107108/// Returns the current [`InputMethod`] strategy.
109pub fn input_method_mut(&mut self) -> &mut InputMethod {
110&mut self.input_method
111 }
112113/// Returns whether the current layout is invalid or not.
114pub fn is_layout_invalid(&self) -> bool {
115self.is_layout_invalid
116 }
117118/// Invalidates the current application layout.
119 ///
120 /// The shell will relayout the application widgets.
121pub fn invalidate_layout(&mut self) {
122self.is_layout_invalid = true;
123 }
124125/// Triggers the given function if the layout is invalid, cleaning it in the
126 /// process.
127pub fn revalidate_layout(&mut self, f: impl FnOnce()) {
128if self.is_layout_invalid {
129self.is_layout_invalid = false;
130131 f();
132 }
133 }
134135/// Returns whether the widgets of the current application have been
136 /// invalidated.
137pub fn are_widgets_invalid(&self) -> bool {
138self.are_widgets_invalid
139 }
140141/// Invalidates the current application widgets.
142 ///
143 /// The shell will rebuild and relayout the widget tree.
144pub fn invalidate_widgets(&mut self) {
145self.are_widgets_invalid = true;
146 }
147148/// Merges the current [`Shell`] with another one by applying the given
149 /// function to the messages of the latter.
150 ///
151 /// This method is useful for composition.
152pub fn merge<B>(&mut self, other: Shell<'_, B>, f: impl Fn(B) -> Message) {
153self.messages.extend(other.messages.drain(..).map(f));
154155self.is_layout_invalid =
156self.is_layout_invalid || other.is_layout_invalid;
157158self.are_widgets_invalid =
159self.are_widgets_invalid || other.are_widgets_invalid;
160161self.redraw_request = self.redraw_request.min(other.redraw_request);
162self.event_status = self.event_status.merge(other.event_status);
163self.input_method.merge(&other.input_method);
164 }
165}