1use iced::Size;
4use iced::widget::Container;
5use iced_core::event::Event;
6use iced_core::widget::Tree;
7use iced_core::{
8 Alignment, Clipboard, Element, Layout, Length, Padding, Rectangle, Shell, Vector, Widget,
9 layout, mouse, overlay, renderer,
10};
11
12pub use iced_widget::container::{Catalog, Style};
13
14pub fn aspect_ratio_container<'a, Message: 'static, T>(
15 content: T,
16 ratio: f32,
17) -> AspectRatio<'a, Message, crate::Renderer>
18where
19 T: Into<Element<'a, Message, crate::Theme, crate::Renderer>>,
20{
21 AspectRatio::new(content, ratio)
22}
23
24#[allow(missing_debug_implementations)]
26pub struct AspectRatio<'a, Message, Renderer>
27where
28 Renderer: iced_core::Renderer,
29{
30 ratio: f32,
31 container: Container<'a, Message, crate::Theme, Renderer>,
32}
33
34impl<Message, Renderer> AspectRatio<'_, Message, Renderer>
35where
36 Renderer: iced_core::Renderer,
37{
38 fn constrain_limits(&self, size: Size) -> Size {
39 let Size {
40 mut width,
41 mut height,
42 } = size;
43 if size.width / size.height > self.ratio {
44 width = self.ratio * height;
45 } else {
46 height = width / self.ratio;
47 }
48 Size { width, height }
49 }
50}
51
52impl<'a, Message, Renderer> AspectRatio<'a, Message, Renderer>
53where
54 Renderer: iced_core::Renderer,
55{
56 pub(crate) fn new<T>(content: T, ratio: f32) -> Self
58 where
59 T: Into<Element<'a, Message, crate::Theme, Renderer>>,
60 {
61 AspectRatio {
62 ratio,
63 container: Container::new(content),
64 }
65 }
66
67 #[must_use]
69 pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self {
70 self.container = self.container.padding(padding);
71 self
72 }
73
74 #[must_use]
76 #[inline]
77 pub fn width(mut self, width: Length) -> Self {
78 self.container = self.container.width(width);
79 self
80 }
81
82 #[must_use]
84 #[inline]
85 pub fn height(mut self, height: Length) -> Self {
86 self.container = self.container.height(height);
87 self
88 }
89
90 #[must_use]
92 #[inline]
93 pub fn max_width(mut self, max_width: f32) -> Self {
94 self.container = self.container.max_width(max_width);
95 self
96 }
97
98 #[must_use]
100 #[inline]
101 pub fn max_height(mut self, max_height: f32) -> Self {
102 self.container = self.container.max_height(max_height);
103 self
104 }
105
106 #[must_use]
108 #[inline]
109 pub fn align_x(mut self, alignment: Alignment) -> Self {
110 self.container = self.container.align_x(alignment);
111 self
112 }
113
114 #[must_use]
116 #[inline]
117 pub fn align_y(mut self, alignment: Alignment) -> Self {
118 self.container = self.container.align_y(alignment);
119 self
120 }
121
122 #[must_use]
124 #[inline]
125 pub fn center_x(mut self, width: Length) -> Self {
126 self.container = self.container.center_x(width);
127 self
128 }
129
130 #[must_use]
132 #[inline]
133 pub fn center_y(mut self, height: Length) -> Self {
134 self.container = self.container.center_y(height);
135 self
136 }
137
138 #[must_use]
140 #[inline]
141 pub fn center(mut self, length: Length) -> Self {
142 self.container = self.container.center(length);
143 self
144 }
145
146 #[must_use]
148 pub fn class(mut self, style: impl Into<crate::style::Container<'a>>) -> Self {
149 self.container = self.container.class(style);
150 self
151 }
152}
153
154impl<Message, Renderer> Widget<Message, crate::Theme, Renderer>
155 for AspectRatio<'_, Message, Renderer>
156where
157 Renderer: iced_core::Renderer,
158{
159 fn children(&self) -> Vec<Tree> {
160 self.container.children()
161 }
162
163 fn diff(&mut self, tree: &mut Tree) {
164 self.container.diff(tree);
165 }
166
167 fn size(&self) -> Size<Length> {
168 self.container.size()
169 }
170
171 fn layout(
172 &mut self,
173 tree: &mut Tree,
174 renderer: &Renderer,
175 limits: &layout::Limits,
176 ) -> layout::Node {
177 let custom_limits = layout::Limits::new(
178 self.constrain_limits(limits.min()),
179 self.constrain_limits(limits.max()),
180 );
181 self.container
182 .layout(&mut tree.children[0], renderer, &custom_limits)
183 }
184
185 fn operate(
186 &mut self,
187 tree: &mut Tree,
188 layout: Layout<'_>,
189 renderer: &Renderer,
190 operation: &mut dyn iced_core::widget::Operation<()>,
191 ) {
192 self.container.operate(tree, layout, renderer, operation);
193 }
194
195 fn update(
196 &mut self,
197 tree: &mut Tree,
198 event: &Event,
199 layout: Layout<'_>,
200 cursor_position: mouse::Cursor,
201 renderer: &Renderer,
202 clipboard: &mut dyn Clipboard,
203 shell: &mut Shell<'_, Message>,
204 viewport: &Rectangle,
205 ) {
206 self.container.update(
207 tree,
208 event,
209 layout,
210 cursor_position,
211 renderer,
212 clipboard,
213 shell,
214 viewport,
215 )
216 }
217
218 fn mouse_interaction(
219 &self,
220 tree: &Tree,
221 layout: Layout<'_>,
222 cursor_position: mouse::Cursor,
223 viewport: &Rectangle,
224 renderer: &Renderer,
225 ) -> mouse::Interaction {
226 self.container
227 .mouse_interaction(tree, layout, cursor_position, viewport, renderer)
228 }
229
230 fn draw(
231 &self,
232 tree: &Tree,
233 renderer: &mut Renderer,
234 theme: &crate::Theme,
235 renderer_style: &renderer::Style,
236 layout: Layout<'_>,
237 cursor_position: mouse::Cursor,
238 viewport: &Rectangle,
239 ) {
240 self.container.draw(
241 tree,
242 renderer,
243 theme,
244 renderer_style,
245 layout,
246 cursor_position,
247 viewport,
248 );
249 }
250
251 fn overlay<'b>(
252 &'b mut self,
253 tree: &'b mut Tree,
254 layout: Layout<'b>,
255 renderer: &Renderer,
256 viewport: &Rectangle,
257 translation: Vector,
258 ) -> Option<overlay::Element<'b, Message, crate::Theme, Renderer>> {
259 self.container
260 .overlay(tree, layout, renderer, viewport, translation)
261 }
262
263 #[cfg(feature = "a11y")]
264 fn a11y_nodes(
266 &self,
267 layout: Layout<'_>,
268 state: &Tree,
269 p: mouse::Cursor,
270 ) -> iced_accessibility::A11yTree {
271 self.container.a11y_nodes(layout, state, p)
272 }
273}
274
275impl<'a, Message, Renderer> From<AspectRatio<'a, Message, Renderer>>
276 for Element<'a, Message, crate::Theme, Renderer>
277where
278 Message: 'a,
279 Renderer: 'a + iced_core::Renderer,
280{
281 fn from(
282 column: AspectRatio<'a, Message, Renderer>,
283 ) -> Element<'a, Message, crate::Theme, Renderer> {
284 Element::new(column)
285 }
286}