1use iced_core::event::{self, Event};
4use iced_core::layout;
5use iced_core::mouse;
6use iced_core::overlay;
7use iced_core::renderer;
8use iced_core::widget::{Id, Operation, Tree};
9use iced_core::{Clipboard, Element, Layout, Length, Rectangle, Shell, Vector, Widget};
10pub use iced_widget::container::{Catalog, Style};
11
12pub fn autosize<'a, Message: 'static, Theme, E>(
13 content: E,
14 id: Id,
15) -> Autosize<'a, Message, Theme, crate::Renderer>
16where
17 E: Into<Element<'a, Message, Theme, crate::Renderer>>,
18 Theme: iced_widget::container::Catalog,
19 <Theme as iced_widget::container::Catalog>::Class<'a>: From<crate::theme::Container<'a>>,
20{
21 Autosize::new(content, id)
22}
23
24#[allow(missing_debug_implementations)]
28pub struct Autosize<'a, Message, Theme, Renderer>
29where
30 Renderer: iced_core::Renderer,
31{
32 content: Element<'a, Message, Theme, Renderer>,
33 id: Id,
34 limits: layout::Limits,
35 auto_width: bool,
36 auto_height: bool,
37}
38
39impl<'a, Message, Theme, Renderer> Autosize<'a, Message, Theme, Renderer>
40where
41 Renderer: iced_core::Renderer,
42{
43 pub(crate) fn new<T>(content: T, id: Id) -> Self
45 where
46 T: Into<Element<'a, Message, Theme, Renderer>>,
47 {
48 Autosize {
49 content: content.into(),
50 id,
51 limits: layout::Limits::NONE,
52 auto_width: true,
53 auto_height: true,
54 }
55 }
56
57 #[inline]
58 pub fn limits(mut self, limits: layout::Limits) -> Self {
59 self.limits = limits;
60 self
61 }
62
63 #[inline]
64 pub fn auto_width(mut self, auto_width: bool) -> Self {
65 self.auto_width = auto_width;
66 self
67 }
68
69 #[inline]
70 pub fn auto_height(mut self, auto_height: bool) -> Self {
71 self.auto_height = auto_height;
72 self
73 }
74
75 #[inline]
76 pub fn max_width(mut self, v: f32) -> Self {
77 self.limits = self.limits.max_width(v);
78 self
79 }
80
81 #[inline]
82 pub fn max_height(mut self, v: f32) -> Self {
83 self.limits = self.limits.max_height(v);
84 self
85 }
86
87 #[inline]
88 pub fn min_width(mut self, v: f32) -> Self {
89 self.limits = self.limits.min_width(v);
90 self
91 }
92
93 #[inline]
94 pub fn min_height(mut self, v: f32) -> Self {
95 self.limits = self.limits.min_height(v);
96 self
97 }
98}
99
100impl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>
101 for Autosize<'_, Message, Theme, Renderer>
102where
103 Renderer: iced_core::Renderer,
104{
105 fn children(&self) -> Vec<Tree> {
106 vec![Tree::new(&self.content)]
107 }
108
109 fn diff(&mut self, tree: &mut Tree) {
110 tree.diff_children(std::slice::from_mut(&mut self.content));
111 }
112
113 fn size(&self) -> iced_core::Size<Length> {
114 self.content.as_widget().size()
115 }
116
117 fn layout(
118 &mut self,
119 tree: &mut Tree,
120 renderer: &Renderer,
121 limits: &layout::Limits,
122 ) -> layout::Node {
123 let mut my_limits = self.limits;
124 let min = limits.min();
125 let max = limits.max();
126 if !self.auto_width {
127 my_limits = limits.min_width(min.width).max_width(max.width);
128 }
129 if !self.auto_height {
130 my_limits = limits.min_height(min.height).max_height(max.height);
131 }
132 let node = self
133 .content
134 .as_widget_mut()
135 .layout(&mut tree.children[0], renderer, &my_limits);
136 let size = node.size();
137 layout::Node::with_children(size, vec![node])
138 }
139
140 fn operate(
141 &mut self,
142 tree: &mut Tree,
143 layout: Layout<'_>,
144 renderer: &Renderer,
145 operation: &mut dyn Operation,
146 ) {
147 operation.container(Some(&self.id), layout.bounds());
148 operation.traverse(&mut |operation| {
149 self.content.as_widget_mut().operate(
150 &mut tree.children[0],
151 layout
152 .children()
153 .next()
154 .unwrap()
155 .with_virtual_offset(layout.virtual_offset()),
156 renderer,
157 operation,
158 );
159 });
160 }
161
162 fn update(
163 &mut self,
164 tree: &mut Tree,
165 event: &Event,
166 layout: Layout<'_>,
167 cursor_position: mouse::Cursor,
168 renderer: &Renderer,
169 clipboard: &mut dyn Clipboard,
170 shell: &mut Shell<'_, Message>,
171 viewport: &Rectangle,
172 ) {
173 #[cfg(all(feature = "wayland", target_os = "linux"))]
174 if matches!(
175 event,
176 Event::PlatformSpecific(event::PlatformSpecific::Wayland(
177 event::wayland::Event::RequestResize
178 ))
179 ) {
180 let bounds = layout.bounds().size();
181 clipboard.request_logical_window_size(bounds.width.max(1.), bounds.height.max(1.));
182 }
183 self.content.as_widget_mut().update(
184 &mut tree.children[0],
185 event,
186 layout
187 .children()
188 .next()
189 .unwrap()
190 .with_virtual_offset(layout.virtual_offset()),
191 cursor_position,
192 renderer,
193 clipboard,
194 shell,
195 viewport,
196 );
197 }
198
199 fn mouse_interaction(
200 &self,
201 tree: &Tree,
202 layout: Layout<'_>,
203 cursor_position: mouse::Cursor,
204 viewport: &Rectangle,
205 renderer: &Renderer,
206 ) -> mouse::Interaction {
207 let content_layout = layout.children().next().unwrap();
208 self.content.as_widget().mouse_interaction(
209 &tree.children[0],
210 content_layout.with_virtual_offset(layout.virtual_offset()),
211 cursor_position,
212 viewport,
213 renderer,
214 )
215 }
216
217 fn draw(
218 &self,
219 tree: &Tree,
220 renderer: &mut Renderer,
221 theme: &Theme,
222 renderer_style: &renderer::Style,
223 layout: Layout<'_>,
224 cursor_position: mouse::Cursor,
225 viewport: &Rectangle,
226 ) {
227 let content_layout = layout.children().next().unwrap();
228 self.content.as_widget().draw(
229 &tree.children[0],
230 renderer,
231 theme,
232 renderer_style,
233 content_layout.with_virtual_offset(layout.virtual_offset()),
234 cursor_position,
235 viewport,
236 );
237 }
238
239 fn overlay<'b>(
240 &'b mut self,
241 tree: &'b mut Tree,
242 layout: Layout<'b>,
243 renderer: &Renderer,
244 viewport: &Rectangle,
245 translation: Vector,
246 ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {
247 self.content.as_widget_mut().overlay(
248 &mut tree.children[0],
249 layout
250 .children()
251 .next()
252 .unwrap()
253 .with_virtual_offset(layout.virtual_offset()),
254 renderer,
255 viewport,
256 translation,
257 )
258 }
259
260 fn drag_destinations(
261 &self,
262 state: &Tree,
263 layout: Layout<'_>,
264 renderer: &Renderer,
265 dnd_rectangles: &mut iced_core::clipboard::DndDestinationRectangles,
266 ) {
267 let content_layout = layout.children().next().unwrap();
268 self.content.as_widget().drag_destinations(
269 &state.children[0],
270 content_layout.with_virtual_offset(layout.virtual_offset()),
271 renderer,
272 dnd_rectangles,
273 );
274 }
275
276 fn id(&self) -> Option<crate::widget::Id> {
277 Some(self.id.clone())
278 }
279
280 fn set_id(&mut self, id: crate::widget::Id) {
281 self.id = id;
282 }
283
284 #[cfg(feature = "a11y")]
285 fn a11y_nodes(
287 &self,
288 layout: Layout<'_>,
289 state: &Tree,
290 p: mouse::Cursor,
291 ) -> iced_accessibility::A11yTree {
292 let c_layout = layout.children().next().unwrap();
293 let c_state = &state.children[0];
294 self.content.as_widget().a11y_nodes(
295 c_layout.with_virtual_offset(layout.virtual_offset()),
296 c_state,
297 p,
298 )
299 }
300}
301
302impl<'a, Message, Theme, Renderer> From<Autosize<'a, Message, Theme, Renderer>>
303 for Element<'a, Message, Theme, Renderer>
304where
305 Message: 'a,
306 Renderer: 'a + iced_core::Renderer,
307 Theme: 'a,
308{
309 fn from(c: Autosize<'a, Message, Theme, Renderer>) -> Element<'a, Message, Theme, Renderer> {
310 Element::new(c)
311 }
312}