Skip to main content

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