1use crate::window;
23/// A connection to the state of a shell.
4///
5/// A [`Widget`] can leverage a [`Shell`] to trigger changes in an application,
6/// like publishing messages or invalidating the current layout.
7///
8/// [`Widget`]: crate::Widget
9#[derive(Debug)]
10pub struct Shell<'a, Message> {
11 messages: &'a mut Vec<Message>,
12 redraw_request: Option<window::RedrawRequest>,
13 is_layout_invalid: bool,
14 are_widgets_invalid: bool,
15}
1617impl<'a, Message> Shell<'a, Message> {
18/// Creates a new [`Shell`] with the provided buffer of messages.
19pub fn new(messages: &'a mut Vec<Message>) -> Self {
20Self {
21 messages,
22 redraw_request: None,
23 is_layout_invalid: false,
24 are_widgets_invalid: false,
25 }
26 }
2728/// Returns true if the [`Shell`] contains no published messages
29pub fn is_empty(&self) -> bool {
30self.messages.is_empty()
31 }
3233/// Publish the given `Message` for an application to process it.
34pub fn publish(&mut self, message: Message) {
35self.messages.push(message);
36 }
3738/// Requests a new frame to be drawn.
39pub fn request_redraw(&mut self, request: window::RedrawRequest) {
40match self.redraw_request {
41None => {
42self.redraw_request = Some(request);
43 }
44Some(current) if request < current => {
45self.redraw_request = Some(request);
46 }
47_ => {}
48 }
49 }
5051/// Returns the request a redraw should happen, if any.
52pub fn redraw_request(&self) -> Option<window::RedrawRequest> {
53self.redraw_request
54 }
5556/// Returns whether the current layout is invalid or not.
57pub fn is_layout_invalid(&self) -> bool {
58self.is_layout_invalid
59 }
6061/// Invalidates the current application layout.
62 ///
63 /// The shell will relayout the application widgets.
64pub fn invalidate_layout(&mut self) {
65self.is_layout_invalid = true;
66 }
6768/// Triggers the given function if the layout is invalid, cleaning it in the
69 /// process.
70pub fn revalidate_layout(&mut self, f: impl FnOnce()) {
71if self.is_layout_invalid {
72self.is_layout_invalid = false;
7374 f();
75 }
76 }
7778/// Returns whether the widgets of the current application have been
79 /// invalidated.
80pub fn are_widgets_invalid(&self) -> bool {
81self.are_widgets_invalid
82 }
8384/// Invalidates the current application widgets.
85 ///
86 /// The shell will rebuild and relayout the widget tree.
87pub fn invalidate_widgets(&mut self) {
88self.are_widgets_invalid = true;
89 }
9091/// Merges the current [`Shell`] with another one by applying the given
92 /// function to the messages of the latter.
93 ///
94 /// This method is useful for composition.
95pub fn merge<B>(&mut self, other: Shell<'_, B>, f: impl Fn(B) -> Message) {
96self.messages.extend(other.messages.drain(..).map(f));
9798if let Some(at) = other.redraw_request {
99self.request_redraw(at);
100 }
101102self.is_layout_invalid =
103self.is_layout_invalid || other.is_layout_invalid;
104105self.are_widgets_invalid =
106self.are_widgets_invalid || other.are_widgets_invalid;
107 }
108}