refactor: use RcWrapper
This commit is contained in:
parent
9ee6233884
commit
3de3e3efa8
2 changed files with 94 additions and 70 deletions
|
|
@ -9,7 +9,7 @@ use std::sync::{Arc, Mutex};
|
||||||
pub use appearance::{Appearance, StyleSheet};
|
pub use appearance::{Appearance, StyleSheet};
|
||||||
use iced::advanced::widget;
|
use iced::advanced::widget;
|
||||||
|
|
||||||
use crate::widget::{icon, Container};
|
use crate::widget::{icon, Container, RcElementWrapper, RcWrapper};
|
||||||
use iced_core::event::{self, Event};
|
use iced_core::event::{self, Event};
|
||||||
use iced_core::layout::{self, Layout};
|
use iced_core::layout::{self, Layout};
|
||||||
use iced_core::text::{self, Text};
|
use iced_core::text::{self, Text};
|
||||||
|
|
@ -127,19 +127,14 @@ where
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct State {
|
pub struct State {
|
||||||
pub(crate) tree: Arc<Mutex<Tree>>,
|
pub(crate) tree: RcWrapper<Tree>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO use the Rc wrapper instead
|
|
||||||
// XXX The tree is only used on one thread, but this is needed to make a message
|
|
||||||
unsafe impl Send for State {}
|
|
||||||
unsafe impl Sync for State {}
|
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
/// Creates a new [`State`] for a [`Menu`].
|
/// Creates a new [`State`] for a [`Menu`].
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
tree: Arc::new(Mutex::new(Tree::empty())),
|
tree: RcWrapper::new(Tree::empty()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -151,7 +146,7 @@ impl Default for State {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Overlay<'a, Message> {
|
struct Overlay<'a, Message> {
|
||||||
state: Arc<Mutex<Tree>>,
|
state: RcWrapper<Tree>,
|
||||||
container: Container<'a, Message, crate::Theme, crate::Renderer>,
|
container: Container<'a, Message, crate::Theme, crate::Renderer>,
|
||||||
width: f32,
|
width: f32,
|
||||||
target_height: f32,
|
target_height: f32,
|
||||||
|
|
@ -199,9 +194,10 @@ impl<'a, Message: 'a> Overlay<'a, Message> {
|
||||||
))
|
))
|
||||||
.class(crate::style::Container::Dropdown);
|
.class(crate::style::Container::Dropdown);
|
||||||
|
|
||||||
let mut tree_guard = state.tree.lock().unwrap();
|
state
|
||||||
tree_guard.diff(&mut container as &mut dyn Widget<_, _, _>);
|
.tree
|
||||||
drop(tree_guard);
|
.with_data_mut(|tree| tree.diff(&mut container as &mut dyn Widget<_, _, _>));
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
state: state.tree.clone(),
|
state: state.tree.clone(),
|
||||||
container,
|
container,
|
||||||
|
|
@ -213,8 +209,6 @@ impl<'a, Message: 'a> Overlay<'a, Message> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _layout(&self, renderer: &crate::Renderer, bounds: Size) -> layout::Node {
|
fn _layout(&self, renderer: &crate::Renderer, bounds: Size) -> layout::Node {
|
||||||
let mut guard = self.state.lock().unwrap();
|
|
||||||
|
|
||||||
let space_below = bounds.height - (self.position.y + self.target_height);
|
let space_below = bounds.height - (self.position.y + self.target_height);
|
||||||
let space_above = self.position.y;
|
let space_above = self.position.y;
|
||||||
|
|
||||||
|
|
@ -231,7 +225,9 @@ impl<'a, Message: 'a> Overlay<'a, Message> {
|
||||||
)
|
)
|
||||||
.width(self.width);
|
.width(self.width);
|
||||||
|
|
||||||
let node = self.container.layout(&mut guard, renderer, &limits);
|
let node = self
|
||||||
|
.state
|
||||||
|
.with_data_mut(|tree| self.container.layout(tree, renderer, &limits));
|
||||||
|
|
||||||
node.clone().move_to(if space_below > space_above {
|
node.clone().move_to(if space_below > space_above {
|
||||||
self.position + Vector::new(0.0, self.target_height)
|
self.position + Vector::new(0.0, self.target_height)
|
||||||
|
|
@ -250,12 +246,12 @@ impl<'a, Message: 'a> Overlay<'a, Message> {
|
||||||
shell: &mut Shell<'_, Message>,
|
shell: &mut Shell<'_, Message>,
|
||||||
) -> event::Status {
|
) -> event::Status {
|
||||||
let bounds = layout.bounds();
|
let bounds = layout.bounds();
|
||||||
let mut guard = self.state.lock().unwrap();
|
|
||||||
|
|
||||||
let state = &mut *guard;
|
self.state.with_data_mut(|tree| {
|
||||||
self.container.on_event(
|
self.container.on_event(
|
||||||
state, event, layout, cursor, renderer, clipboard, shell, &bounds,
|
tree, event, layout, cursor, renderer, clipboard, shell, &bounds,
|
||||||
)
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _mouse_interaction(
|
fn _mouse_interaction(
|
||||||
|
|
@ -265,10 +261,10 @@ impl<'a, Message: 'a> Overlay<'a, Message> {
|
||||||
viewport: &Rectangle,
|
viewport: &Rectangle,
|
||||||
renderer: &crate::Renderer,
|
renderer: &crate::Renderer,
|
||||||
) -> mouse::Interaction {
|
) -> mouse::Interaction {
|
||||||
let guard = self.state.lock().unwrap();
|
self.state.with_data(|tree| {
|
||||||
|
|
||||||
self.container
|
self.container
|
||||||
.mouse_interaction(&guard, layout, cursor, viewport, renderer)
|
.mouse_interaction(tree, layout, cursor, viewport, renderer)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _draw(
|
fn _draw(
|
||||||
|
|
@ -279,8 +275,6 @@ impl<'a, Message: 'a> Overlay<'a, Message> {
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
cursor: mouse::Cursor,
|
cursor: mouse::Cursor,
|
||||||
) {
|
) {
|
||||||
let state = self.state.lock().unwrap();
|
|
||||||
|
|
||||||
let appearance = theme.appearance(&self.style);
|
let appearance = theme.appearance(&self.style);
|
||||||
let bounds = layout.bounds();
|
let bounds = layout.bounds();
|
||||||
|
|
||||||
|
|
@ -297,8 +291,10 @@ impl<'a, Message: 'a> Overlay<'a, Message> {
|
||||||
appearance.background,
|
appearance.background,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
self.state.with_data(|tree| {
|
||||||
self.container
|
self.container
|
||||||
.draw(&*state, renderer, theme, style, layout, cursor, &bounds);
|
.draw(tree, renderer, theme, style, layout, cursor, &bounds)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -306,8 +302,6 @@ impl<'a, Message: 'a> iced_core::Overlay<Message, crate::Theme, crate::Renderer>
|
||||||
for Overlay<'a, Message>
|
for Overlay<'a, Message>
|
||||||
{
|
{
|
||||||
fn layout(&mut self, renderer: &crate::Renderer, bounds: Size) -> layout::Node {
|
fn layout(&mut self, renderer: &crate::Renderer, bounds: Size) -> layout::Node {
|
||||||
let mut guard = self.state.lock().unwrap();
|
|
||||||
|
|
||||||
self._layout(renderer, bounds)
|
self._layout(renderer, bounds)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -341,8 +335,6 @@ impl<'a, Message: 'a> iced_core::Overlay<Message, crate::Theme, crate::Renderer>
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
cursor: mouse::Cursor,
|
cursor: mouse::Cursor,
|
||||||
) {
|
) {
|
||||||
let guard = self.state.lock().unwrap();
|
|
||||||
|
|
||||||
self._draw(renderer, theme, style, layout, cursor);
|
self._draw(renderer, theme, style, layout, cursor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -360,11 +352,10 @@ impl<'a, Message: 'a> crate::widget::Widget<Message, crate::Theme, crate::Render
|
||||||
renderer: &crate::Renderer,
|
renderer: &crate::Renderer,
|
||||||
limits: &iced::Limits,
|
limits: &iced::Limits,
|
||||||
) -> layout::Node {
|
) -> layout::Node {
|
||||||
let mut guard = self.state.lock().unwrap();
|
|
||||||
|
|
||||||
let limits = limits.width(self.width);
|
let limits = limits.width(self.width);
|
||||||
|
|
||||||
self.container.layout(&mut guard, renderer, &limits)
|
self.state
|
||||||
|
.with_data_mut(|tree| self.container.layout(tree, renderer, &limits))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mouse_interaction(
|
fn mouse_interaction(
|
||||||
|
|
|
||||||
|
|
@ -8,48 +8,80 @@ use crate::Element;
|
||||||
use iced::{event, Length, Rectangle, Size};
|
use iced::{event, Length, Rectangle, Size};
|
||||||
use iced_core::{id::Id, widget, widget::tree, Widget};
|
use iced_core::{id::Id, widget, widget::tree, Widget};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Debug)]
|
||||||
pub struct RcElementWrapper<M> {
|
pub struct RcWrapper<T> {
|
||||||
pub(crate) element: Rc<RefCell<Element<'static, M>>>,
|
pub(crate) data: Rc<RefCell<T>>,
|
||||||
pub(crate) thread_id: ThreadId,
|
pub(crate) thread_id: ThreadId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M> RcElementWrapper<M> {
|
impl<T> Clone for RcWrapper<T> {
|
||||||
pub fn new(element: Element<'static, M>) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
element: Rc::new(RefCell::new(element)),
|
data: self.data.clone(),
|
||||||
|
thread_id: self.thread_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<M: 'static> Send for RcWrapper<M> {}
|
||||||
|
unsafe impl<M: 'static> Sync for RcWrapper<M> {}
|
||||||
|
|
||||||
|
impl<T> RcWrapper<T> {
|
||||||
|
pub fn new(element: T) -> Self {
|
||||||
|
Self {
|
||||||
|
data: Rc::new(RefCell::new(element)),
|
||||||
thread_id: thread::current().id(),
|
thread_id: thread::current().id(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_element<T>(&self, f: impl FnOnce(&Element<'static, M>) -> T) -> T {
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Will panic if used outside of original thread.
|
||||||
|
pub fn with_data<O>(&self, f: impl FnOnce(&T) -> O) -> O {
|
||||||
assert_eq!(self.thread_id, thread::current().id());
|
assert_eq!(self.thread_id, thread::current().id());
|
||||||
let my_ref: &Element<'static, M> = &RefCell::borrow(self.element.as_ref());
|
let my_ref: &T = &RefCell::borrow(self.data.as_ref());
|
||||||
f(my_ref)
|
f(my_ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_element_mut<T>(&self, f: impl FnOnce(&mut Element<'static, M>) -> T) -> T {
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Will panic if used outside of original thread.
|
||||||
|
pub fn with_data_mut<O>(&self, f: impl FnOnce(&mut T) -> O) -> O {
|
||||||
assert_eq!(self.thread_id, thread::current().id());
|
assert_eq!(self.thread_id, thread::current().id());
|
||||||
let my_refmut: &mut Element<'static, M> = &mut RefCell::borrow_mut(self.element.as_ref());
|
let my_refmut: &mut T = &mut RefCell::borrow_mut(self.data.as_ref());
|
||||||
f(my_refmut)
|
f(my_refmut)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn as_ptr(&self) -> *mut Element<'static, M> {
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Will panic if used outside of original thread.
|
||||||
|
pub(crate) unsafe fn as_ptr(&self) -> *mut T {
|
||||||
assert_eq!(self.thread_id, thread::current().id());
|
assert_eq!(self.thread_id, thread::current().id());
|
||||||
RefCell::as_ptr(self.element.as_ref())
|
RefCell::as_ptr(self.data.as_ref())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<M: 'static> Send for RcElementWrapper<M> {}
|
#[derive(Clone)]
|
||||||
unsafe impl<M: 'static> Sync for RcElementWrapper<M> {}
|
pub struct RcElementWrapper<M> {
|
||||||
|
pub(crate) element: RcWrapper<Element<'static, M>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<M> RcElementWrapper<M> {
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(element: Element<'static, M>) -> Self {
|
||||||
|
RcElementWrapper {
|
||||||
|
element: RcWrapper::new(element),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<M> Widget<M, crate::Theme, crate::Renderer> for RcElementWrapper<M> {
|
impl<M> Widget<M, crate::Theme, crate::Renderer> for RcElementWrapper<M> {
|
||||||
fn size(&self) -> Size<Length> {
|
fn size(&self) -> Size<Length> {
|
||||||
self.with_element(|e| e.as_widget().size())
|
self.element.with_data(|e| e.as_widget().size())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size_hint(&self) -> Size<Length> {
|
fn size_hint(&self) -> Size<Length> {
|
||||||
self.element.borrow_mut().as_widget().size_hint()
|
self.element.with_data(move |e| e.as_widget().size_hint())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn layout(
|
fn layout(
|
||||||
|
|
@ -58,7 +90,8 @@ impl<M> Widget<M, crate::Theme, crate::Renderer> for RcElementWrapper<M> {
|
||||||
renderer: &crate::Renderer,
|
renderer: &crate::Renderer,
|
||||||
limits: &crate::iced_core::layout::Limits,
|
limits: &crate::iced_core::layout::Limits,
|
||||||
) -> crate::iced_core::layout::Node {
|
) -> crate::iced_core::layout::Node {
|
||||||
self.with_element_mut(|e| e.as_widget_mut().layout(tree, renderer, limits))
|
self.element
|
||||||
|
.with_data_mut(|e| e.as_widget_mut().layout(tree, renderer, limits))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(
|
fn draw(
|
||||||
|
|
@ -71,26 +104,26 @@ impl<M> Widget<M, crate::Theme, crate::Renderer> for RcElementWrapper<M> {
|
||||||
cursor: crate::iced_core::mouse::Cursor,
|
cursor: crate::iced_core::mouse::Cursor,
|
||||||
viewport: &Rectangle,
|
viewport: &Rectangle,
|
||||||
) {
|
) {
|
||||||
self.with_element(move |e| {
|
self.element.with_data(move |e| {
|
||||||
e.as_widget()
|
e.as_widget()
|
||||||
.draw(tree, renderer, theme, style, layout, cursor, viewport)
|
.draw(tree, renderer, theme, style, layout, cursor, viewport);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tag(&self) -> tree::Tag {
|
fn tag(&self) -> tree::Tag {
|
||||||
self.with_element(|e| e.as_widget().tag())
|
self.element.with_data(|e| e.as_widget().tag())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn state(&self) -> tree::State {
|
fn state(&self) -> tree::State {
|
||||||
self.with_element(|e| e.as_widget().state())
|
self.element.with_data(|e| e.as_widget().state())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn children(&self) -> Vec<tree::Tree> {
|
fn children(&self) -> Vec<tree::Tree> {
|
||||||
self.with_element(|e| e.as_widget().children())
|
self.element.with_data(|e| e.as_widget().children())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn diff(&mut self, tree: &mut tree::Tree) {
|
fn diff(&mut self, tree: &mut tree::Tree) {
|
||||||
self.with_element_mut(|e| e.as_widget_mut().diff(tree))
|
self.element.with_data_mut(|e| e.as_widget_mut().diff(tree));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn operate(
|
fn operate(
|
||||||
|
|
@ -100,9 +133,9 @@ impl<M> Widget<M, crate::Theme, crate::Renderer> for RcElementWrapper<M> {
|
||||||
renderer: &crate::Renderer,
|
renderer: &crate::Renderer,
|
||||||
operation: &mut dyn widget::Operation,
|
operation: &mut dyn widget::Operation,
|
||||||
) {
|
) {
|
||||||
self.with_element(|e| {
|
self.element.with_data(|e| {
|
||||||
e.as_widget().operate(state, layout, renderer, operation);
|
e.as_widget().operate(state, layout, renderer, operation);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_event(
|
fn on_event(
|
||||||
|
|
@ -116,7 +149,7 @@ impl<M> Widget<M, crate::Theme, crate::Renderer> for RcElementWrapper<M> {
|
||||||
shell: &mut crate::iced_core::Shell<'_, M>,
|
shell: &mut crate::iced_core::Shell<'_, M>,
|
||||||
viewport: &Rectangle,
|
viewport: &Rectangle,
|
||||||
) -> event::Status {
|
) -> event::Status {
|
||||||
self.with_element_mut(|e| {
|
self.element.with_data_mut(|e| {
|
||||||
e.as_widget_mut().on_event(
|
e.as_widget_mut().on_event(
|
||||||
state, event, layout, cursor, renderer, clipboard, shell, viewport,
|
state, event, layout, cursor, renderer, clipboard, shell, viewport,
|
||||||
)
|
)
|
||||||
|
|
@ -131,7 +164,7 @@ impl<M> Widget<M, crate::Theme, crate::Renderer> for RcElementWrapper<M> {
|
||||||
viewport: &Rectangle,
|
viewport: &Rectangle,
|
||||||
renderer: &crate::Renderer,
|
renderer: &crate::Renderer,
|
||||||
) -> crate::iced_core::mouse::Interaction {
|
) -> crate::iced_core::mouse::Interaction {
|
||||||
self.with_element(|e| {
|
self.element.with_data(|e| {
|
||||||
e.as_widget()
|
e.as_widget()
|
||||||
.mouse_interaction(state, layout, cursor, viewport, renderer)
|
.mouse_interaction(state, layout, cursor, viewport, renderer)
|
||||||
})
|
})
|
||||||
|
|
@ -144,8 +177,8 @@ impl<M> Widget<M, crate::Theme, crate::Renderer> for RcElementWrapper<M> {
|
||||||
renderer: &crate::Renderer,
|
renderer: &crate::Renderer,
|
||||||
translation: crate::iced_core::Vector,
|
translation: crate::iced_core::Vector,
|
||||||
) -> Option<crate::iced_core::overlay::Element<'a, M, crate::Theme, crate::Renderer>> {
|
) -> Option<crate::iced_core::overlay::Element<'a, M, crate::Theme, crate::Renderer>> {
|
||||||
assert_eq!(self.thread_id, thread::current().id());
|
assert_eq!(self.element.thread_id, thread::current().id());
|
||||||
Rc::get_mut(&mut self.element).and_then(|e| {
|
Rc::get_mut(&mut self.element.data).and_then(|e| {
|
||||||
e.get_mut()
|
e.get_mut()
|
||||||
.as_widget_mut()
|
.as_widget_mut()
|
||||||
.overlay(state, layout, renderer, translation)
|
.overlay(state, layout, renderer, translation)
|
||||||
|
|
@ -153,11 +186,11 @@ impl<M> Widget<M, crate::Theme, crate::Renderer> for RcElementWrapper<M> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn id(&self) -> Option<Id> {
|
fn id(&self) -> Option<Id> {
|
||||||
self.with_element_mut(|e| e.as_widget_mut().id())
|
self.element.with_data_mut(|e| e.as_widget_mut().id())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_id(&mut self, id: Id) {
|
fn set_id(&mut self, id: Id) {
|
||||||
self.with_element_mut(|e| e.as_widget_mut().set_id(id))
|
self.element.with_data_mut(|e| e.as_widget_mut().set_id(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn drag_destinations(
|
fn drag_destinations(
|
||||||
|
|
@ -167,10 +200,10 @@ impl<M> Widget<M, crate::Theme, crate::Renderer> for RcElementWrapper<M> {
|
||||||
renderer: &crate::Renderer,
|
renderer: &crate::Renderer,
|
||||||
dnd_rectangles: &mut crate::iced_core::clipboard::DndDestinationRectangles,
|
dnd_rectangles: &mut crate::iced_core::clipboard::DndDestinationRectangles,
|
||||||
) {
|
) {
|
||||||
self.with_element_mut(|e| {
|
self.element.with_data_mut(|e| {
|
||||||
e.as_widget_mut()
|
e.as_widget_mut()
|
||||||
.drag_destinations(state, layout, renderer, dnd_rectangles)
|
.drag_destinations(state, layout, renderer, dnd_rectangles);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue