Skip to main content

cosmic/widget/
id_container.rs

1use iced_core::event::{self, Event};
2use iced_core::widget::{Id, Operation, Tree};
3use iced_core::{
4    Clipboard, Element, Layout, Length, Rectangle, Shell, Vector, Widget, layout, mouse, overlay,
5    renderer,
6};
7pub use iced_widget::container::{Catalog, Style};
8
9pub fn id_container<'a, Message: 'static, Theme, E>(
10    content: E,
11    id: Id,
12) -> IdContainer<'a, Message, Theme, crate::Renderer>
13where
14    E: Into<Element<'a, Message, Theme, crate::Renderer>>,
15    Theme: iced_widget::container::Catalog,
16    <Theme as iced_widget::container::Catalog>::Class<'a>: From<crate::theme::Container<'a>>,
17{
18    IdContainer::new(content, id)
19}
20
21/// An element decorating some content.
22///
23/// It is normally used for alignment purposes.
24#[allow(missing_debug_implementations)]
25pub struct IdContainer<'a, Message, Theme, Renderer>
26where
27    Renderer: iced_core::Renderer,
28{
29    content: Element<'a, Message, Theme, Renderer>,
30    id: Id,
31}
32
33impl<'a, Message, Theme, Renderer> IdContainer<'a, Message, Theme, Renderer>
34where
35    Renderer: iced_core::Renderer,
36{
37    /// Creates an empty [`IdContainer`].
38    pub(crate) fn new<T>(content: T, id: Id) -> Self
39    where
40        T: Into<Element<'a, Message, Theme, Renderer>>,
41    {
42        IdContainer {
43            content: content.into(),
44            id,
45        }
46    }
47}
48
49impl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>
50    for IdContainer<'_, Message, Theme, Renderer>
51where
52    Renderer: iced_core::Renderer,
53{
54    fn children(&self) -> Vec<Tree> {
55        vec![Tree::new(&self.content)]
56    }
57
58    fn diff(&mut self, tree: &mut Tree) {
59        tree.diff_children(std::slice::from_mut(&mut self.content));
60    }
61
62    fn size(&self) -> iced_core::Size<Length> {
63        self.content.as_widget().size()
64    }
65
66    fn layout(
67        &mut self,
68        tree: &mut Tree,
69        renderer: &Renderer,
70        limits: &layout::Limits,
71    ) -> layout::Node {
72        let node = self
73            .content
74            .as_widget_mut()
75            .layout(&mut tree.children[0], renderer, limits);
76        let size = node.size();
77        layout::Node::with_children(size, vec![node])
78    }
79
80    fn operate(
81        &mut self,
82        tree: &mut Tree,
83        layout: Layout<'_>,
84        renderer: &Renderer,
85        operation: &mut dyn Operation,
86    ) {
87        operation.container(Some(&self.id), layout.bounds());
88        operation.traverse(&mut |operation| {
89            self.content.as_widget_mut().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 update(
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    ) {
113        self.content.as_widget_mut().update(
114            &mut tree.children[0],
115            event,
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<'b>,
173        renderer: &Renderer,
174        viewport: &Rectangle,
175        translation: Vector,
176    ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {
177        self.content.as_widget_mut().overlay(
178            &mut tree.children[0],
179            layout
180                .children()
181                .next()
182                .unwrap()
183                .with_virtual_offset(layout.virtual_offset()),
184            renderer,
185            viewport,
186            translation,
187        )
188    }
189
190    fn drag_destinations(
191        &self,
192        state: &Tree,
193        layout: Layout<'_>,
194        renderer: &Renderer,
195        dnd_rectangles: &mut iced_core::clipboard::DndDestinationRectangles,
196    ) {
197        let content_layout = layout.children().next().unwrap();
198        self.content.as_widget().drag_destinations(
199            &state.children[0],
200            content_layout.with_virtual_offset(layout.virtual_offset()),
201            renderer,
202            dnd_rectangles,
203        );
204    }
205
206    fn id(&self) -> Option<crate::widget::Id> {
207        Some(self.id.clone())
208    }
209
210    fn set_id(&mut self, id: crate::widget::Id) {
211        self.id = id;
212    }
213
214    #[cfg(feature = "a11y")]
215    /// get the a11y nodes for the widget
216    fn a11y_nodes(
217        &self,
218        layout: Layout<'_>,
219        state: &Tree,
220        p: mouse::Cursor,
221    ) -> iced_accessibility::A11yTree {
222        let c_layout = layout.children().next().unwrap();
223        let c_state = &state.children[0];
224        self.content.as_widget().a11y_nodes(
225            c_layout.with_virtual_offset(layout.virtual_offset()),
226            c_state,
227            p,
228        )
229    }
230}
231
232impl<'a, Message, Theme, Renderer> From<IdContainer<'a, Message, Theme, Renderer>>
233    for Element<'a, Message, Theme, Renderer>
234where
235    Message: 'a,
236    Renderer: 'a + iced_core::Renderer,
237    Theme: 'a,
238{
239    fn from(c: IdContainer<'a, Message, Theme, Renderer>) -> Element<'a, Message, Theme, Renderer> {
240        Element::new(c)
241    }
242}