/// A connection to the state of a shell. /// /// A [`Widget`] can leverage a [`Shell`] to trigger changes in an application, /// like publishing messages or invalidating the current layout. /// /// [`Widget`]: crate::Widget #[derive(Debug)] pub struct Shell<'a, Message> { messages: &'a mut Vec, is_layout_invalid: bool, are_widgets_invalid: bool, } impl<'a, Message> Shell<'a, Message> { /// Creates a new [`Shell`] with the provided buffer of messages. pub fn new(messages: &'a mut Vec) -> Self { Self { messages, is_layout_invalid: false, are_widgets_invalid: false, } } /// Triggers the given function if the layout is invalid, cleaning it in the /// process. pub fn revalidate_layout(&mut self, f: impl FnOnce()) { if self.is_layout_invalid { self.is_layout_invalid = false; f() } } /// Publish the given `Message` for an application to process it. pub fn publish(&mut self, message: Message) { self.messages.push(message); } /// Invalidates the current application layout. /// /// The shell will relayout the application widgets. pub fn invalidate_layout(&mut self) { self.is_layout_invalid = true; } /// Invalidates the current application widgets. /// /// The shell will rebuild and relayout the widget tree. pub fn invalidate_widgets(&mut self) { self.are_widgets_invalid = true; } /// Merges the current [`Shell`] with another one by applying the given /// function to the messages of the latter. /// /// This method is useful for composition. pub fn merge(&mut self, other: Shell<'_, B>, f: impl Fn(B) -> Message) { self.messages.extend(other.messages.drain(..).map(f)); self.is_layout_invalid = self.is_layout_invalid || other.is_layout_invalid; self.are_widgets_invalid = self.are_widgets_invalid || other.are_widgets_invalid; } /// Returns whether the widgets of the current application have been /// invalidated. pub fn are_widgets_invalid(&self) -> bool { self.are_widgets_invalid } }