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