iced_widget/
responsive.rs

1use crate::core::layout::{self, Layout};
2use crate::core::mouse;
3use crate::core::overlay;
4use crate::core::renderer;
5use crate::core::widget;
6use crate::core::widget::Tree;
7use crate::core::{
8    self, Clipboard, Element, Event, Length, Rectangle, Shell, Size, Vector,
9    Widget,
10};
11use crate::space;
12
13/// A widget that is aware of its dimensions.
14///
15/// A [`Responsive`] widget will always try to fill all the available space of
16/// its parent.
17pub struct Responsive<
18    'a,
19    Message,
20    Theme = crate::Theme,
21    Renderer = crate::Renderer,
22> {
23    view: Box<dyn Fn(Size) -> Element<'a, Message, Theme, Renderer> + 'a>,
24    width: Length,
25    height: Length,
26    content: Element<'a, Message, Theme, Renderer>,
27}
28
29impl<'a, Message, Theme, Renderer> Responsive<'a, Message, Theme, Renderer>
30where
31    Renderer: core::Renderer,
32{
33    /// Creates a new [`Responsive`] widget with a closure that produces its
34    /// contents.
35    ///
36    /// The `view` closure will receive the maximum available space for
37    /// the [`Responsive`] during layout. You can use this [`Size`] to
38    /// conditionally build the contents.
39    pub fn new(
40        view: impl Fn(Size) -> Element<'a, Message, Theme, Renderer> + 'a,
41    ) -> Self {
42        Self {
43            view: Box::new(view),
44            width: Length::Fill,
45            height: Length::Fill,
46            content: Element::new(space()),
47        }
48    }
49
50    /// Sets the width of the [`Responsive`].
51    pub fn width(mut self, width: impl Into<Length>) -> Self {
52        self.width = width.into();
53        self
54    }
55
56    /// Sets the height of the [`Responsive`].
57    pub fn height(mut self, height: impl Into<Length>) -> Self {
58        self.height = height.into();
59        self
60    }
61}
62
63impl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>
64    for Responsive<'_, Message, Theme, Renderer>
65where
66    Renderer: core::Renderer,
67{
68    fn diff(&self, _tree: &mut Tree) {
69        // Diff is deferred to layout
70    }
71
72    fn size(&self) -> Size<Length> {
73        Size {
74            width: self.width,
75            height: self.height,
76        }
77    }
78
79    fn layout(
80        &mut self,
81        tree: &mut Tree,
82        renderer: &Renderer,
83        limits: &layout::Limits,
84    ) -> layout::Node {
85        let limits = limits.width(self.width).height(self.height);
86        let size = limits.max();
87
88        self.content = (self.view)(size);
89        tree.diff_children(std::slice::from_ref(&self.content));
90
91        let node = self.content.as_widget_mut().layout(
92            &mut tree.children[0],
93            renderer,
94            &limits.loose(),
95        );
96
97        let size = limits.resolve(self.width, self.height, node.size());
98
99        layout::Node::with_children(size, vec![node])
100    }
101
102    fn update(
103        &mut self,
104        tree: &mut Tree,
105        event: &Event,
106        layout: Layout<'_>,
107        cursor: mouse::Cursor,
108        renderer: &Renderer,
109        clipboard: &mut dyn Clipboard,
110        shell: &mut Shell<'_, Message>,
111        viewport: &Rectangle,
112    ) {
113        self.content.as_widget_mut().update(
114            &mut tree.children[0],
115            event,
116            layout.children().next().unwrap(),
117            cursor,
118            renderer,
119            clipboard,
120            shell,
121            viewport,
122        );
123    }
124
125    fn draw(
126        &self,
127        tree: &Tree,
128        renderer: &mut Renderer,
129        theme: &Theme,
130        style: &renderer::Style,
131        layout: Layout<'_>,
132        cursor: mouse::Cursor,
133        viewport: &Rectangle,
134    ) {
135        self.content.as_widget().draw(
136            &tree.children[0],
137            renderer,
138            theme,
139            style,
140            layout.children().next().unwrap(),
141            cursor,
142            viewport,
143        );
144    }
145
146    fn mouse_interaction(
147        &self,
148        tree: &Tree,
149        layout: Layout<'_>,
150        cursor: mouse::Cursor,
151        viewport: &Rectangle,
152        renderer: &Renderer,
153    ) -> mouse::Interaction {
154        self.content.as_widget().mouse_interaction(
155            &tree.children[0],
156            layout.children().next().unwrap(),
157            cursor,
158            viewport,
159            renderer,
160        )
161    }
162
163    fn operate(
164        &mut self,
165        tree: &mut Tree,
166        layout: Layout<'_>,
167        renderer: &Renderer,
168        operation: &mut dyn widget::Operation,
169    ) {
170        self.content.as_widget_mut().operate(
171            &mut tree.children[0],
172            layout.children().next().unwrap(),
173            renderer,
174            operation,
175        );
176    }
177
178    fn overlay<'a>(
179        &'a mut self,
180        tree: &'a mut Tree,
181        layout: Layout<'a>,
182        renderer: &Renderer,
183        viewport: &Rectangle,
184        translation: Vector,
185    ) -> Option<overlay::Element<'a, Message, Theme, Renderer>> {
186        self.content.as_widget_mut().overlay(
187            &mut tree.children[0],
188            layout.children().next().unwrap(),
189            renderer,
190            viewport,
191            translation,
192        )
193    }
194}
195
196impl<'a, Message, Theme, Renderer>
197    From<Responsive<'a, Message, Theme, Renderer>>
198    for Element<'a, Message, Theme, Renderer>
199where
200    Message: 'a,
201    Theme: 'a,
202    Renderer: core::Renderer + 'a,
203{
204    fn from(responsive: Responsive<'a, Message, Theme, Renderer>) -> Self {
205        Self::new(responsive)
206    }
207}