1use iced_core::{Length, Rectangle, Widget};
4
5#[allow(unused_imports)]
6pub use iced_core::{
7 Renderer,
8 layout::{Limits, Node},
9 widget::Tree,
10};
11
12type LayoutFn<'a, Message, Theme, Renderer> = Box<
13 dyn Fn(
14 &mut Vec<iced_core::Element<'a, Message, Theme, Renderer>>,
15 &mut Vec<Tree>,
16 &Renderer,
17 &Limits,
18 ) -> Node,
19>;
20
21pub struct CustomLayout<'a, Message, Theme, Renderer> {
23 elements: Vec<iced_core::Element<'a, Message, Theme, Renderer>>,
24 width: Length,
25 height: Length,
26 layout: LayoutFn<'a, Message, Theme, Renderer>,
27}
28
29impl<'b, Message, Theme, Renderer: iced_core::Renderer> CustomLayout<'b, Message, Theme, Renderer> {
30 pub fn new(
32 elements: Vec<iced_core::Element<'b, Message, Theme, Renderer>>,
33 layout: impl Fn(
34 &mut Vec<iced_core::Element<'b, Message, Theme, Renderer>>,
35 &mut Vec<Tree>,
36 &Renderer,
37 &Limits,
38 ) -> Node
39 + 'static,
40 ) -> Self {
41 Self {
42 elements,
43 width: Length::Shrink,
44 height: Length::Shrink,
45 layout: Box::new(layout),
46 }
47 }
48
49 #[must_use]
51 pub fn width(mut self, length: impl Into<Length>) -> Self {
52 self.width = length.into();
53 self
54 }
55
56 #[must_use]
58 pub fn height(mut self, length: impl Into<Length>) -> Self {
59 self.height = length.into();
60 self
61 }
62}
63
64impl<Message, Theme, Renderer: iced_core::Renderer> Widget<Message, Theme, Renderer>
65 for CustomLayout<'_, Message, Theme, Renderer>
66{
67 fn size(&self) -> iced_core::Size<Length> {
68 iced_core::Size::new(self.width, self.height)
69 }
70
71 fn layout(&mut self, tree: &mut Tree, renderer: &Renderer, limits: &Limits) -> Node {
72 (self.layout)(&mut self.elements, &mut tree.children, renderer, limits)
73 }
74
75 fn draw(
76 &self,
77 tree: &Tree,
78 renderer: &mut Renderer,
79 theme: &Theme,
80 style: &iced_core::renderer::Style,
81 layout: iced_core::Layout<'_>,
82 cursor: iced_core::mouse::Cursor,
83 viewport: &iced_core::Rectangle,
84 ) {
85 tree.children
86 .iter()
87 .zip(layout.children())
88 .zip(self.elements.iter())
89 .for_each(|((state, layout), element)| {
90 element
91 .as_widget()
92 .draw(state, renderer, theme, style, layout, cursor, viewport);
93 });
94 }
95
96 fn children(&self) -> Vec<Tree> {
97 self.elements.iter().map(|x| Tree::new(x)).collect()
98 }
99
100 fn diff(&self, tree: &mut Tree) {
101 tree.diff_children(&self.elements);
102 }
103
104 fn operate(
105 &mut self,
106 state: &mut Tree,
107 layout: iced_core::Layout<'_>,
108 renderer: &Renderer,
109 operation: &mut dyn iced_core::widget::Operation,
110 ) {
111 state
112 .children
113 .iter_mut()
114 .zip(layout.children())
115 .zip(self.elements.iter_mut())
116 .for_each(|((state, layout), element)| {
117 operation.container(None, layout.bounds());
118 operation.traverse(&mut |operation| {
119 element
120 .as_widget_mut()
121 .operate(state, layout, renderer, operation);
122 });
123 });
124 }
125
126 fn update(
127 &mut self,
128 state: &mut Tree,
129 event: &iced_core::Event,
130 layout: iced_core::Layout<'_>,
131 cursor: iced_core::mouse::Cursor,
132 renderer: &Renderer,
133 clipboard: &mut dyn iced_core::Clipboard,
134 shell: &mut iced_core::Shell<'_, Message>,
135 viewport: &iced_core::Rectangle,
136 ) {
137 for ((state, layout), element) in state
138 .children
139 .iter_mut()
140 .zip(layout.children())
141 .zip(self.elements.iter_mut())
142 {
143 element.as_widget_mut().update(
144 state, event, layout, cursor, renderer, clipboard, shell, viewport,
145 );
146 }
147 }
148
149 fn size_hint(&self) -> iced_core::Size<Length> {
150 self.size()
151 }
152
153 fn overlay<'a>(
154 &'a mut self,
155 state: &'a mut Tree,
156 layout: iced_core::Layout<'a>,
157 renderer: &Renderer,
158 viewport: &Rectangle,
159 translation: iced_core::Vector,
160 ) -> Option<iced_core::overlay::Element<'a, Message, Theme, Renderer>> {
161 iced_core::overlay::from_children(
162 &mut self.elements,
163 state,
164 layout,
165 renderer,
166 viewport,
167 translation,
168 )
169 }
170
171 fn mouse_interaction(
172 &self,
173 state: &Tree,
174 layout: iced_core::Layout<'_>,
175 cursor: iced_core::mouse::Cursor,
176 viewport: &iced_core::Rectangle,
177 renderer: &Renderer,
178 ) -> iced_core::mouse::Interaction {
179 self.elements
180 .iter()
181 .zip(&state.children)
182 .zip(layout.children())
183 .map(|((child, state), layout)| {
184 child
185 .as_widget()
186 .mouse_interaction(state, layout, cursor, viewport, renderer)
187 })
188 .max()
189 .unwrap_or_default()
190 }
191}
192
193impl<'b, Message: 'b, Theme: 'b, Renderer: iced_core::Renderer + 'b>
194 From<CustomLayout<'b, Message, Theme, Renderer>>
195 for iced_core::Element<'b, Message, Theme, Renderer>
196{
197 fn from(value: CustomLayout<'b, Message, Theme, Renderer>) -> Self {
198 iced_core::Element::new(value)
199 }
200}