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, 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.children[0].diff(&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        &self,
69        tree: &mut Tree,
70        renderer: &Renderer,
71        limits: &layout::Limits,
72    ) -> layout::Node {
73        let node = self
74            .content
75            .as_widget()
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        &self,
83        tree: &mut Tree,
84        layout: Layout<'_>,
85        renderer: &Renderer,
86        operation: &mut dyn iced_core::widget::Operation<()>,
87    ) {
88        operation.container(Some(&self.id), layout.bounds(), &mut |operation| {
89            self.content.as_widget().operate(
90                &mut tree.children[0],
91                layout
92                    .children()
93                    .next()
94                    .unwrap()
95                    .with_virtual_offset(layout.virtual_offset()),
96                renderer,
97                operation,
98            );
99        });
100    }
101
102    fn on_event(
103        &mut self,
104        tree: &mut Tree,
105        event: Event,
106        layout: Layout<'_>,
107        cursor_position: mouse::Cursor,
108        renderer: &Renderer,
109        clipboard: &mut dyn Clipboard,
110        shell: &mut Shell<'_, Message>,
111        viewport: &Rectangle,
112    ) -> event::Status {
113        self.content.as_widget_mut().on_event(
114            &mut tree.children[0],
115            event.clone(),
116            layout
117                .children()
118                .next()
119                .unwrap()
120                .with_virtual_offset(layout.virtual_offset()),
121            cursor_position,
122            renderer,
123            clipboard,
124            shell,
125            viewport,
126        )
127    }
128
129    fn mouse_interaction(
130        &self,
131        tree: &Tree,
132        layout: Layout<'_>,
133        cursor_position: mouse::Cursor,
134        viewport: &Rectangle,
135        renderer: &Renderer,
136    ) -> mouse::Interaction {
137        let content_layout = layout.children().next().unwrap();
138        self.content.as_widget().mouse_interaction(
139            &tree.children[0],
140            content_layout.with_virtual_offset(layout.virtual_offset()),
141            cursor_position,
142            viewport,
143            renderer,
144        )
145    }
146
147    fn draw(
148        &self,
149        tree: &Tree,
150        renderer: &mut Renderer,
151        theme: &Theme,
152        renderer_style: &renderer::Style,
153        layout: Layout<'_>,
154        cursor_position: mouse::Cursor,
155        viewport: &Rectangle,
156    ) {
157        let content_layout = layout.children().next().unwrap();
158        self.content.as_widget().draw(
159            &tree.children[0],
160            renderer,
161            theme,
162            renderer_style,
163            content_layout.with_virtual_offset(layout.virtual_offset()),
164            cursor_position,
165            viewport,
166        );
167    }
168
169    fn overlay<'b>(
170        &'b mut self,
171        tree: &'b mut Tree,
172        layout: Layout<'_>,
173        renderer: &Renderer,
174        translation: Vector,
175    ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {
176        self.content.as_widget_mut().overlay(
177            &mut tree.children[0],
178            layout
179                .children()
180                .next()
181                .unwrap()
182                .with_virtual_offset(layout.virtual_offset()),
183            renderer,
184            translation,
185        )
186    }
187
188    fn drag_destinations(
189        &self,
190        state: &Tree,
191        layout: Layout<'_>,
192        renderer: &Renderer,
193        dnd_rectangles: &mut iced_core::clipboard::DndDestinationRectangles,
194    ) {
195        let content_layout = layout.children().next().unwrap();
196        self.content.as_widget().drag_destinations(
197            &state.children[0],
198            content_layout.with_virtual_offset(layout.virtual_offset()),
199            renderer,
200            dnd_rectangles,
201        );
202    }
203
204    fn id(&self) -> Option<crate::widget::Id> {
205        Some(self.id.clone())
206    }
207
208    fn set_id(&mut self, id: crate::widget::Id) {
209        self.id = id;
210    }
211
212    #[cfg(feature = "a11y")]
213    /// get the a11y nodes for the widget
214    fn a11y_nodes(
215        &self,
216        layout: Layout<'_>,
217        state: &Tree,
218        p: mouse::Cursor,
219    ) -> iced_accessibility::A11yTree {
220        let c_layout = layout.children().next().unwrap();
221        let c_state = &state.children[0];
222        self.content.as_widget().a11y_nodes(
223            c_layout.with_virtual_offset(layout.virtual_offset()),
224            c_state,
225            p,
226        )
227    }
228}
229
230impl<'a, Message, Theme, Renderer> From<IdContainer<'a, Message, Theme, Renderer>>
231    for Element<'a, Message, Theme, Renderer>
232where
233    Message: 'a,
234    Renderer: 'a + iced_core::Renderer,
235    Theme: 'a,
236{
237    fn from(c: IdContainer<'a, Message, Theme, Renderer>) -> Element<'a, Message, Theme, Renderer> {
238        Element::new(c)
239    }
240}