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