1mod subscription;
2
3use iced::Vector;
4use iced::futures::channel::mpsc::UnboundedSender;
5use iced::widget::Container;
6pub use subscription::*;
7
8use iced_core::event::{self, Event};
9use iced_core::layout;
10use iced_core::mouse;
11use iced_core::overlay;
12use iced_core::renderer;
13use iced_core::widget::Tree;
14use iced_core::{Alignment, Clipboard, Element, Layout, Length, Padding, Rectangle, Shell, Widget};
15use std::{fmt::Debug, hash::Hash};
16
17pub use iced_widget::container::{Catalog, Style};
18
19pub fn rectangle_tracking_container<'a, Message, I, T>(
20 content: T,
21 id: I,
22 tx: UnboundedSender<(I, Rectangle)>,
23) -> RectangleTrackingContainer<'a, Message, crate::Renderer, I>
24where
25 I: Hash + Copy + Send + Sync + Debug + 'a,
26 T: Into<Element<'a, Message, crate::Theme, crate::Renderer>>,
27{
28 RectangleTrackingContainer::new(content, id, tx)
29}
30
31pub fn subscription<
32 I: 'static + Hash + Copy + Send + Sync + Debug,
33 R: 'static + Hash + Copy + Send + Sync + Debug + Eq,
34>(
35 id: I,
36) -> iced::Subscription<(I, RectangleUpdate<R>)> {
37 subscription::rectangle_tracker_subscription(id)
38}
39
40#[derive(Clone, Debug)]
41pub struct RectangleTracker<I> {
42 tx: UnboundedSender<(I, Rectangle)>,
43}
44
45impl<I> RectangleTracker<I>
46where
47 I: Hash + Copy + Send + Sync + Debug,
48{
49 pub fn container<'a, Message: 'static, T>(
50 &self,
51 id: I,
52 content: T,
53 ) -> RectangleTrackingContainer<'a, Message, crate::Renderer, I>
54 where
55 I: 'a,
56 T: Into<Element<'a, Message, crate::Theme, crate::Renderer>>,
57 {
58 RectangleTrackingContainer::new(content, id, self.tx.clone())
59 }
60}
61
62#[allow(missing_debug_implementations)]
66pub struct RectangleTrackingContainer<'a, Message, Renderer, I>
67where
68 Renderer: iced_core::Renderer,
69{
70 tx: UnboundedSender<(I, Rectangle)>,
71 id: I,
72 container: Container<'a, Message, crate::Theme, Renderer>,
73 ignore_bounds: bool,
74}
75
76impl<'a, Message, Renderer, I> RectangleTrackingContainer<'a, Message, Renderer, I>
77where
78 Renderer: iced_core::Renderer,
79 I: 'a + Hash + Copy + Send + Sync + Debug,
80{
81 pub(crate) fn new<T>(content: T, id: I, tx: UnboundedSender<(I, Rectangle)>) -> Self
83 where
84 T: Into<Element<'a, Message, crate::Theme, Renderer>>,
85 {
86 RectangleTrackingContainer {
87 id,
88 tx,
89 container: Container::new(content),
90 ignore_bounds: false,
91 }
92 }
93
94 pub fn diff(&mut self, tree: &mut Tree) {
95 self.container.diff(tree);
96 }
97
98 #[must_use]
100 pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self {
101 self.container = self.container.padding(padding);
102 self
103 }
104
105 #[must_use]
107 pub fn width(mut self, width: Length) -> Self {
108 self.container = self.container.width(width);
109 self
110 }
111
112 #[must_use]
114 pub fn height(mut self, height: Length) -> Self {
115 self.container = self.container.height(height);
116 self
117 }
118
119 #[must_use]
121 pub fn max_width(mut self, max_width: f32) -> Self {
122 self.container = self.container.max_width(max_width);
123 self
124 }
125
126 #[must_use]
128 pub fn max_height(mut self, max_height: f32) -> Self {
129 self.container = self.container.max_height(max_height);
130 self
131 }
132
133 #[must_use]
135 pub fn align_x(mut self, alignment: Alignment) -> Self {
136 self.container = self.container.align_x(alignment);
137 self
138 }
139
140 #[must_use]
142 pub fn align_y(mut self, alignment: Alignment) -> Self {
143 self.container = self.container.align_y(alignment);
144 self
145 }
146
147 #[must_use]
149 pub fn center_x(mut self, width: Length) -> Self {
150 self.container = self.container.center_x(width);
151 self
152 }
153
154 #[must_use]
156 pub fn center_y(mut self, height: Length) -> Self {
157 self.container = self.container.center_y(height);
158 self
159 }
160
161 #[must_use]
163 pub fn center(mut self, length: Length) -> Self {
164 self.container = self.container.center(length);
165 self
166 }
167
168 #[must_use]
170 pub fn style(mut self, style: impl Into<<crate::Theme as Catalog>::Class<'a>>) -> Self {
171 self.container = self.container.class(style);
172 self
173 }
174
175 #[must_use]
178 pub fn ignore_bounds(mut self, ignore_bounds: bool) -> Self {
179 self.ignore_bounds = ignore_bounds;
180 self
181 }
182}
183
184impl<'a, Message, Renderer, I> Widget<Message, crate::Theme, Renderer>
185 for RectangleTrackingContainer<'a, Message, Renderer, I>
186where
187 Renderer: iced_core::Renderer,
188 I: 'a + Hash + Copy + Send + Sync + Debug,
189{
190 fn children(&self) -> Vec<Tree> {
191 self.container.children()
192 }
193
194 fn state(&self) -> iced_core::widget::tree::State {
195 self.container.state()
196 }
197
198 fn diff(&mut self, tree: &mut Tree) {
199 self.container.diff(tree);
200 }
201
202 fn size(&self) -> iced_core::Size<Length> {
203 self.container.size()
204 }
205
206 fn layout(
207 &self,
208 tree: &mut Tree,
209 renderer: &Renderer,
210 limits: &layout::Limits,
211 ) -> layout::Node {
212 self.container.layout(
213 tree,
214 renderer,
215 if self.ignore_bounds {
216 &layout::Limits::NONE
217 } else {
218 limits
219 },
220 )
221 }
222
223 fn operate(
224 &self,
225 tree: &mut Tree,
226 layout: Layout<'_>,
227 renderer: &Renderer,
228 operation: &mut dyn iced_core::widget::Operation<()>,
229 ) {
230 self.container.operate(tree, layout, renderer, operation);
231 }
232
233 fn on_event(
234 &mut self,
235 tree: &mut Tree,
236 event: Event,
237 layout: Layout<'_>,
238 cursor_position: mouse::Cursor,
239 renderer: &Renderer,
240 clipboard: &mut dyn Clipboard,
241 shell: &mut Shell<'_, Message>,
242 viewport: &iced_core::Rectangle,
243 ) -> event::Status {
244 self.container.on_event(
245 tree,
246 event,
247 layout,
248 cursor_position,
249 renderer,
250 clipboard,
251 shell,
252 viewport,
253 )
254 }
255
256 fn mouse_interaction(
257 &self,
258 tree: &Tree,
259 layout: Layout<'_>,
260 cursor_position: mouse::Cursor,
261 viewport: &Rectangle,
262 renderer: &Renderer,
263 ) -> mouse::Interaction {
264 self.container
265 .mouse_interaction(tree, layout, cursor_position, viewport, renderer)
266 }
267
268 fn draw(
269 &self,
270 tree: &Tree,
271 renderer: &mut Renderer,
272 theme: &crate::Theme,
273 renderer_style: &renderer::Style,
274 layout: Layout<'_>,
275 cursor_position: mouse::Cursor,
276 viewport: &Rectangle,
277 ) {
278 let _ = self.tx.unbounded_send((self.id, layout.bounds()));
279 self.container.draw(
280 tree,
281 renderer,
282 theme,
283 renderer_style,
284 layout,
285 cursor_position,
286 viewport,
287 );
288 }
289
290 fn overlay<'b>(
291 &'b mut self,
292 tree: &'b mut Tree,
293 layout: Layout<'_>,
294 renderer: &Renderer,
295 translation: Vector,
296 ) -> Option<overlay::Element<'b, Message, crate::Theme, Renderer>> {
297 self.container.overlay(tree, layout, renderer, translation)
298 }
299
300 fn drag_destinations(
301 &self,
302 state: &Tree,
303 layout: Layout<'_>,
304 renderer: &Renderer,
305 dnd_rectangles: &mut iced_core::clipboard::DndDestinationRectangles,
306 ) {
307 self.container
308 .drag_destinations(state, layout, renderer, dnd_rectangles);
309 }
310
311 #[cfg(feature = "a11y")]
312 fn a11y_nodes(
314 &self,
315 layout: Layout<'_>,
316 state: &Tree,
317 p: mouse::Cursor,
318 ) -> iced_accessibility::A11yTree {
319 self.container.a11y_nodes(layout, state, p)
320 }
321}
322
323impl<'a, Message, Renderer, I> From<RectangleTrackingContainer<'a, Message, Renderer, I>>
324 for Element<'a, Message, crate::Theme, Renderer>
325where
326 Message: 'a,
327 Renderer: 'a + iced_core::Renderer,
328 I: 'a + Hash + Copy + Send + Sync + Debug,
329{
330 fn from(
331 column: RectangleTrackingContainer<'a, Message, Renderer, I>,
332 ) -> Element<'a, Message, crate::Theme, Renderer> {
333 Element::new(column)
334 }
335}