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