cosmic/widget/
wrapper.rs

1use std::{
2    borrow::Borrow,
3    cell::RefCell,
4    rc::Rc,
5    thread::{self, ThreadId},
6};
7
8use crate::Element;
9use iced::{Length, Rectangle, Size, event};
10use iced_core::{Widget, id::Id, widget, widget::tree};
11
12#[derive(Debug)]
13pub struct RcWrapper<T> {
14    pub(crate) data: Rc<RefCell<T>>,
15    pub(crate) thread_id: ThreadId,
16}
17
18impl<T: Default> Default for RcWrapper<T> {
19    fn default() -> Self {
20        Self::new(T::default())
21    }
22}
23
24impl<T> Clone for RcWrapper<T> {
25    fn clone(&self) -> Self {
26        Self {
27            data: self.data.clone(),
28            thread_id: self.thread_id,
29        }
30    }
31}
32
33unsafe impl<M: 'static> Send for RcWrapper<M> {}
34unsafe impl<M: 'static> Sync for RcWrapper<M> {}
35
36impl<T> RcWrapper<T> {
37    pub fn new(element: T) -> Self {
38        Self {
39            data: Rc::new(RefCell::new(element)),
40            thread_id: thread::current().id(),
41        }
42    }
43
44    /// # Panics
45    ///
46    /// Will panic if used outside of original thread.
47    pub fn with_data<O>(&self, f: impl FnOnce(&T) -> O) -> O {
48        assert_eq!(self.thread_id, thread::current().id());
49        let my_ref: &T = &RefCell::borrow(self.data.as_ref());
50        f(my_ref)
51    }
52
53    /// # Panics
54    ///
55    /// Will panic if used outside of original thread.
56    pub fn with_data_mut<O>(&self, f: impl FnOnce(&mut T) -> O) -> O {
57        assert_eq!(self.thread_id, thread::current().id());
58        let my_refmut: &mut T = &mut RefCell::borrow_mut(self.data.as_ref());
59        f(my_refmut)
60    }
61}
62
63#[derive(Clone)]
64pub struct RcElementWrapper<M> {
65    pub(crate) element: RcWrapper<Element<'static, M>>,
66}
67
68impl<M> RcElementWrapper<M> {
69    #[must_use]
70    pub fn new(element: Element<'static, M>) -> Self {
71        RcElementWrapper {
72            element: RcWrapper::new(element),
73        }
74    }
75}
76
77impl<M: 'static> Borrow<dyn Widget<M, crate::Theme, crate::Renderer>> for RcElementWrapper<M> {
78    fn borrow(&self) -> &(dyn Widget<M, crate::Theme, crate::Renderer> + 'static) {
79        self
80    }
81}
82
83impl<M> Widget<M, crate::Theme, crate::Renderer> for RcElementWrapper<M> {
84    fn size(&self) -> Size<Length> {
85        self.element.with_data(|e| e.as_widget().size())
86    }
87
88    fn size_hint(&self) -> Size<Length> {
89        self.element.with_data(move |e| e.as_widget().size_hint())
90    }
91
92    fn layout(
93        &mut self,
94        tree: &mut tree::Tree,
95        renderer: &crate::Renderer,
96        limits: &iced_core::layout::Limits,
97    ) -> iced_core::layout::Node {
98        self.element
99            .with_data_mut(|e| e.as_widget_mut().layout(tree, renderer, limits))
100    }
101
102    fn draw(
103        &self,
104        tree: &tree::Tree,
105        renderer: &mut crate::Renderer,
106        theme: &crate::Theme,
107        style: &iced_core::renderer::Style,
108        layout: iced_core::Layout<'_>,
109        cursor: iced_core::mouse::Cursor,
110        viewport: &Rectangle,
111    ) {
112        self.element.with_data(move |e| {
113            e.as_widget()
114                .draw(tree, renderer, theme, style, layout, cursor, viewport);
115        });
116    }
117
118    fn tag(&self) -> tree::Tag {
119        self.element.with_data(|e| e.as_widget().tag())
120    }
121
122    fn state(&self) -> tree::State {
123        self.element.with_data(|e| e.as_widget().state())
124    }
125
126    fn children(&self) -> Vec<tree::Tree> {
127        self.element.with_data(|e| e.as_widget().children())
128    }
129
130    fn diff(&mut self, tree: &mut tree::Tree) {
131        self.element.with_data_mut(|e| e.as_widget_mut().diff(tree));
132    }
133
134    fn operate(
135        &mut self,
136        state: &mut tree::Tree,
137        layout: iced_core::Layout<'_>,
138        renderer: &crate::Renderer,
139        operation: &mut dyn widget::Operation,
140    ) {
141        self.element.with_data_mut(|e| {
142            e.as_widget_mut()
143                .operate(state, layout, renderer, operation);
144        });
145    }
146
147    fn update(
148        &mut self,
149        state: &mut tree::Tree,
150        event: &crate::iced::Event,
151        layout: iced_core::Layout<'_>,
152        cursor: iced_core::mouse::Cursor,
153        renderer: &crate::Renderer,
154        clipboard: &mut dyn iced_core::Clipboard,
155        shell: &mut iced_core::Shell<'_, M>,
156        viewport: &Rectangle,
157    ) {
158        self.element.with_data_mut(|e| {
159            e.as_widget_mut().update(
160                state, event, layout, cursor, renderer, clipboard, shell, viewport,
161            )
162        })
163    }
164
165    fn mouse_interaction(
166        &self,
167        state: &tree::Tree,
168        layout: iced_core::Layout<'_>,
169        cursor: iced_core::mouse::Cursor,
170        viewport: &Rectangle,
171        renderer: &crate::Renderer,
172    ) -> iced_core::mouse::Interaction {
173        self.element.with_data(|e| {
174            e.as_widget()
175                .mouse_interaction(state, layout, cursor, viewport, renderer)
176        })
177    }
178
179    fn overlay<'a>(
180        &'a mut self,
181        state: &'a mut tree::Tree,
182        layout: iced_core::Layout<'a>,
183        renderer: &crate::Renderer,
184        viewport: &Rectangle,
185        translation: iced_core::Vector,
186    ) -> Option<iced_core::overlay::Element<'a, M, crate::Theme, crate::Renderer>> {
187        assert_eq!(self.element.thread_id, thread::current().id());
188        Rc::get_mut(&mut self.element.data).and_then(|e| {
189            e.get_mut()
190                .as_widget_mut()
191                .overlay(state, layout, renderer, viewport, translation)
192        })
193    }
194
195    fn id(&self) -> Option<Id> {
196        self.element.with_data_mut(|e| e.as_widget_mut().id())
197    }
198
199    fn set_id(&mut self, id: Id) {
200        self.element.with_data_mut(|e| e.as_widget_mut().set_id(id));
201    }
202
203    fn drag_destinations(
204        &self,
205        state: &tree::Tree,
206        layout: iced_core::Layout<'_>,
207        renderer: &crate::Renderer,
208        dnd_rectangles: &mut iced_core::clipboard::DndDestinationRectangles,
209    ) {
210        self.element.with_data_mut(|e| {
211            e.as_widget_mut()
212                .drag_destinations(state, layout, renderer, dnd_rectangles);
213        });
214    }
215}
216
217impl<Message: 'static> From<RcElementWrapper<Message>> for Element<'static, Message> {
218    fn from(wrapper: RcElementWrapper<Message>) -> Self {
219        Element::new(wrapper)
220    }
221}
222
223impl<Message: 'static> From<Element<'static, Message>> for RcElementWrapper<Message> {
224    fn from(e: Element<'static, Message>) -> Self {
225        RcElementWrapper::new(e)
226    }
227}