cosmic/widget/
id_container.rs

1use iced_core::event::{self, Event};
2use iced_core::layout;
3use iced_core::mouse;
4use iced_core::overlay;
5use iced_core::renderer;
6use iced_core::widget::{Id, Operation, Tree};
7use iced_core::{Clipboard, Element, Layout, Length, Rectangle, Shell, Vector, Widget};
8pub use iced_widget::container::{Catalog, Style};
9
10pub fn id_container<'a, Message: 'static, Theme, E>(
11    content: E,
12    id: Id,
13) -> IdContainer<'a, Message, Theme, crate::Renderer>
14where
15    E: Into<Element<'a, Message, Theme, crate::Renderer>>,
16    Theme: iced_widget::container::Catalog,
17    <Theme as iced_widget::container::Catalog>::Class<'a>: From<crate::theme::Container<'a>>,
18{
19    IdContainer::new(content, id)
20}
21
22/// An element decorating some content.
23///
24/// It is normally used for alignment purposes.
25#[allow(missing_debug_implementations)]
26pub struct IdContainer<'a, Message, Theme, Renderer>
27where
28    Renderer: iced_core::Renderer,
29{
30    content: Element<'a, Message, Theme, Renderer>,
31    id: Id,
32}
33
34impl<'a, Message, Theme, Renderer> IdContainer<'a, Message, Theme, Renderer>
35where
36    Renderer: iced_core::Renderer,
37{
38    /// Creates an empty [`IdContainer`].
39    pub(crate) fn new<T>(content: T, id: Id) -> Self
40    where
41        T: Into<Element<'a, Message, Theme, Renderer>>,
42    {
43        IdContainer {
44            content: content.into(),
45            id,
46        }
47    }
48}
49
50impl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>
51    for IdContainer<'_, Message, Theme, Renderer>
52where
53    Renderer: iced_core::Renderer,
54{
55    fn children(&self) -> Vec<Tree> {
56        vec![Tree::new(&self.content)]
57    }
58
59    fn diff(&mut self, tree: &mut Tree) {
60        tree.diff_children(std::slice::from_mut(&mut self.content));
61    }
62
63    fn size(&self) -> iced_core::Size<Length> {
64        self.content.as_widget().size()
65    }
66
67    fn layout(
68        &mut self,
69        tree: &mut Tree,
70        renderer: &Renderer,
71        limits: &layout::Limits,
72    ) -> layout::Node {
73        let node = self
74            .content
75            .as_widget_mut()
76            .layout(&mut tree.children[0], renderer, limits);
77        let size = node.size();
78        layout::Node::with_children(size, vec![node])
79    }
80
81    fn operate(
82        &mut self,
83        tree: &mut Tree,
84        layout: Layout<'_>,
85        renderer: &Renderer,
86        operation: &mut dyn Operation,
87    ) {
88        operation.container(Some(&self.id), layout.bounds());
89        operation.traverse(&mut |operation| {
90            self.content.as_widget_mut().operate(
91                &mut tree.children[0],
92                layout
93                    .children()
94                    .next()
95                    .unwrap()
96                    .with_virtual_offset(layout.virtual_offset()),
97                renderer,
98                operation,
99            );
100        });
101    }
102
103    fn update(
104        &mut self,
105        tree: &mut Tree,
106        event: &Event,
107        layout: Layout<'_>,
108        cursor_position: mouse::Cursor,
109        renderer: &Renderer,
110        clipboard: &mut dyn Clipboard,
111        shell: &mut Shell<'_, Message>,
112        viewport: &Rectangle,
113    ) {
114        self.content.as_widget_mut().update(
115            &mut tree.children[0],
116            event,
117            layout
118                .children()
119                .next()
120                .unwrap()
121                .with_virtual_offset(layout.virtual_offset()),
122            cursor_position,
123            renderer,
124            clipboard,
125            shell,
126            viewport,
127        );
128    }
129
130    fn mouse_interaction(
131        &self,
132        tree: &Tree,
133        layout: Layout<'_>,
134        cursor_position: mouse::Cursor,
135        viewport: &Rectangle,
136        renderer: &Renderer,
137    ) -> mouse::Interaction {
138        let content_layout = layout.children().next().unwrap();
139        self.content.as_widget().mouse_interaction(
140            &tree.children[0],
141            content_layout.with_virtual_offset(layout.virtual_offset()),
142            cursor_position,
143            viewport,
144            renderer,
145        )
146    }
147
148    fn draw(
149        &self,
150        tree: &Tree,
151        renderer: &mut Renderer,
152        theme: &Theme,
153        renderer_style: &renderer::Style,
154        layout: Layout<'_>,
155        cursor_position: mouse::Cursor,
156        viewport: &Rectangle,
157    ) {
158        let content_layout = layout.children().next().unwrap();
159        self.content.as_widget().draw(
160            &tree.children[0],
161            renderer,
162            theme,
163            renderer_style,
164            content_layout.with_virtual_offset(layout.virtual_offset()),
165            cursor_position,
166            viewport,
167        );
168    }
169
170    fn overlay<'b>(
171        &'b mut self,
172        tree: &'b mut Tree,
173        layout: Layout<'b>,
174        renderer: &Renderer,
175        viewport: &Rectangle,
176        translation: Vector,
177    ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {
178        self.content.as_widget_mut().overlay(
179            &mut tree.children[0],
180            layout
181                .children()
182                .next()
183                .unwrap()
184                .with_virtual_offset(layout.virtual_offset()),
185            renderer,
186            viewport,
187            translation,
188        )
189    }
190
191    fn drag_destinations(
192        &self,
193        state: &Tree,
194        layout: Layout<'_>,
195        renderer: &Renderer,
196        dnd_rectangles: &mut iced_core::clipboard::DndDestinationRectangles,
197    ) {
198        let content_layout = layout.children().next().unwrap();
199        self.content.as_widget().drag_destinations(
200            &state.children[0],
201            content_layout.with_virtual_offset(layout.virtual_offset()),
202            renderer,
203            dnd_rectangles,
204        );
205    }
206
207    fn id(&self) -> Option<crate::widget::Id> {
208        Some(self.id.clone())
209    }
210
211    fn set_id(&mut self, id: crate::widget::Id) {
212        self.id = id;
213    }
214
215    #[cfg(feature = "a11y")]
216    /// get the a11y nodes for the widget
217    fn a11y_nodes(
218        &self,
219        layout: Layout<'_>,
220        state: &Tree,
221        p: mouse::Cursor,
222    ) -> iced_accessibility::A11yTree {
223        let c_layout = layout.children().next().unwrap();
224        let c_state = &state.children[0];
225        self.content.as_widget().a11y_nodes(
226            c_layout.with_virtual_offset(layout.virtual_offset()),
227            c_state,
228            p,
229        )
230    }
231}
232
233impl<'a, Message, Theme, Renderer> From<IdContainer<'a, Message, Theme, Renderer>>
234    for Element<'a, Message, Theme, Renderer>
235where
236    Message: 'a,
237    Renderer: 'a + iced_core::Renderer,
238    Theme: 'a,
239{
240    fn from(c: IdContainer<'a, Message, Theme, Renderer>) -> Element<'a, Message, Theme, Renderer> {
241        Element::new(c)
242    }
243}