iced_core/
shell.rs

1use crate::window;
2
3/// 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}
16
17impl<'a, Message> Shell<'a, Message> {
18    /// Creates a new [`Shell`] with the provided buffer of messages.
19    pub fn new(messages: &'a mut Vec<Message>) -> Self {
20        Self {
21            messages,
22            redraw_request: None,
23            is_layout_invalid: false,
24            are_widgets_invalid: false,
25        }
26    }
27
28    /// Returns true if the [`Shell`] contains no published messages
29    pub fn is_empty(&self) -> bool {
30        self.messages.is_empty()
31    }
32
33    /// Publish the given `Message` for an application to process it.
34    pub fn publish(&mut self, message: Message) {
35        self.messages.push(message);
36    }
37
38    /// Requests a new frame to be drawn.
39    pub fn request_redraw(&mut self, request: window::RedrawRequest) {
40        match self.redraw_request {
41            None => {
42                self.redraw_request = Some(request);
43            }
44            Some(current) if request < current => {
45                self.redraw_request = Some(request);
46            }
47            _ => {}
48        }
49    }
50
51    /// Returns the request a redraw should happen, if any.
52    pub fn redraw_request(&self) -> Option<window::RedrawRequest> {
53        self.redraw_request
54    }
55
56    /// Returns whether the current layout is invalid or not.
57    pub fn is_layout_invalid(&self) -> bool {
58        self.is_layout_invalid
59    }
60
61    /// Invalidates the current application layout.
62    ///
63    /// The shell will relayout the application widgets.
64    pub fn invalidate_layout(&mut self) {
65        self.is_layout_invalid = true;
66    }
67
68    /// Triggers the given function if the layout is invalid, cleaning it in the
69    /// process.
70    pub fn revalidate_layout(&mut self, f: impl FnOnce()) {
71        if self.is_layout_invalid {
72            self.is_layout_invalid = false;
73
74            f();
75        }
76    }
77
78    /// Returns whether the widgets of the current application have been
79    /// invalidated.
80    pub fn are_widgets_invalid(&self) -> bool {
81        self.are_widgets_invalid
82    }
83
84    /// Invalidates the current application widgets.
85    ///
86    /// The shell will rebuild and relayout the widget tree.
87    pub fn invalidate_widgets(&mut self) {
88        self.are_widgets_invalid = true;
89    }
90
91    /// 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.
95    pub fn merge<B>(&mut self, other: Shell<'_, B>, f: impl Fn(B) -> Message) {
96        self.messages.extend(other.messages.drain(..).map(f));
97
98        if let Some(at) = other.redraw_request {
99            self.request_redraw(at);
100        }
101
102        self.is_layout_invalid =
103            self.is_layout_invalid || other.is_layout_invalid;
104
105        self.are_widgets_invalid =
106            self.are_widgets_invalid || other.are_widgets_invalid;
107    }
108}