From 5a5670eda5990fbf0d3c1ce8cfc0b7edae87b914 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Mon, 17 Feb 2025 16:40:11 -0500 Subject: [PATCH] refactor: remove menu tree changes --- src/app/core.rs | 12 +- src/widget/context_menu.rs | 43 +++---- src/widget/dropdown/menu/mod.rs | 1 + src/widget/menu/menu_bar.rs | 6 +- src/widget/menu/menu_inner.rs | 56 ++++----- src/widget/menu/menu_tree.rs | 111 ++++++++--------- src/widget/nav_bar.rs | 2 +- src/widget/segmented_button/widget.rs | 21 ++-- src/widget/wrapper.rs | 166 +++++++++++++++----------- 9 files changed, 221 insertions(+), 197 deletions(-) diff --git a/src/app/core.rs b/src/app/core.rs index 0c9d338a..36feb0f0 100644 --- a/src/app/core.rs +++ b/src/app/core.rs @@ -390,7 +390,7 @@ impl Core { pub fn responsive_menu_bar<'a, Message: Clone + From + 'static>( &self, id: crate::widget::Id, - roots: Vec>, + roots: Vec>, ) -> crate::Element<'a, Message> { let menu_bar_size = self.menu_bars.get(&id); if !menu_bar_size.is_some_and(|(limits, size)| { @@ -405,10 +405,12 @@ impl Core { } else { crate::Element::from( responsive_container::responsive_container( - menu::bar(vec![menu::Tree::<'a, _, _>::with_children( - button::icon(icon::from_name("open-menu-symbolic")) - .padding([4, 12]) - .class(crate::theme::Button::MenuRoot), + menu::bar(vec![menu::Tree::<_>::with_children( + Element::from( + button::icon(icon::from_name("open-menu-symbolic")) + .padding([4, 12]) + .class(crate::theme::Button::MenuRoot), + ), roots, )]), id, diff --git a/src/widget/context_menu.rs b/src/widget/context_menu.rs index cf174385..338775b9 100644 --- a/src/widget/context_menu.rs +++ b/src/widget/context_menu.rs @@ -6,30 +6,24 @@ use crate::widget::menu::{ self, CloseCondition, ItemHeight, ItemWidth, MenuBarState, PathHighlight, }; -use crate::widget::ArcElementWrapper; use derive_setters::Setters; use iced::touch::Finger; use iced::{Event, Vector}; use iced_core::widget::{tree, Tree, Widget}; use iced_core::{event, mouse, touch, Length, Point, Size}; use std::collections::HashSet; -use std::sync::{Arc, Mutex}; - -use super::dropdown; /// A context menu is a menu in a graphical user interface that appears upon user interaction, such as a right-click mouse operation. -pub fn context_menu( - content: impl Into> + 'static, +pub fn context_menu<'a, Message: 'a>( + content: impl Into> + 'a, // on_context: Message, - context_menu: Option>>, -) -> ContextMenu<'static, Message> { + context_menu: Option>>, +) -> ContextMenu<'a, Message> { let mut this = ContextMenu { content: content.into(), context_menu: context_menu.map(|menus| { vec![menu::Tree::with_children( - ArcElementWrapper(Arc::new(Mutex::new(crate::Element::from( - crate::widget::row::<'static, Message>(), - )))), + crate::widget::row::<'static, Message>(), menus, )] }), @@ -49,10 +43,10 @@ pub struct ContextMenu<'a, Message> { #[setters(skip)] content: crate::Element<'a, Message>, #[setters(skip)] - context_menu: Option>>, + context_menu: Option>>, } -impl<'a, Message: Clone + 'static> Widget +impl<'a, Message: Clone> Widget for ContextMenu<'a, Message> { fn tag(&self) -> tree::Tag { @@ -64,7 +58,6 @@ impl<'a, Message: Clone + 'static> Widget Widget Widget Option> { let state = tree.state.downcast_ref::(); - let menu_state = state.menu_state.clone(); + let Some(context_menu) = self.context_menu.as_mut() else { return None; }; @@ -239,8 +229,8 @@ impl<'a, Message: Clone + 'static> Widget Widget Widget From> - for crate::Element<'static, Message> -{ - fn from(widget: ContextMenu<'static, Message>) -> Self { +impl<'a, Message: Clone + 'a> From> for crate::Element<'a, Message> { + fn from(widget: ContextMenu<'a, Message>) -> Self { Self::new(widget) } } @@ -297,5 +285,4 @@ fn touch_lifted(event: &Event) -> bool { pub struct LocalState { context_cursor: Point, fingers_pressed: HashSet, - menu_state: dropdown::menu::State, } diff --git a/src/widget/dropdown/menu/mod.rs b/src/widget/dropdown/menu/mod.rs index b6c5c8c0..507a0d40 100644 --- a/src/widget/dropdown/menu/mod.rs +++ b/src/widget/dropdown/menu/mod.rs @@ -130,6 +130,7 @@ pub struct State { pub(crate) tree: Arc>, } +// 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 {} diff --git a/src/widget/menu/menu_bar.rs b/src/widget/menu/menu_bar.rs index 79c77005..a1be7c82 100644 --- a/src/widget/menu/menu_bar.rs +++ b/src/widget/menu/menu_bar.rs @@ -84,7 +84,7 @@ where .map(|root| { let mut tree = Tree::empty(); let flat = root - .flatten() + .flattern() .iter() .map(|mt| Tree::new(mt.item.as_widget())) .collect(); @@ -110,7 +110,7 @@ pub(crate) fn menu_roots_diff<'a, Message, Renderer>( .zip(menu_roots.iter()) .for_each(|(t, root)| { let mut flat = root - .flatten() + .flattern() .iter() .map(|mt| { let widget = mt.item.as_widget(); @@ -129,7 +129,7 @@ pub(crate) fn menu_roots_diff<'a, Message, Renderer>( let extended = menu_roots[tree.children.len()..].iter().map(|root| { let mut tree = Tree::empty(); let flat = root - .flatten() + .flattern() .iter() .map(|mt| Tree::new(mt.item.as_widget())) .collect(); diff --git a/src/widget/menu/menu_inner.rs b/src/widget/menu/menu_inner.rs index 616ae441..b64fba2c 100644 --- a/src/widget/menu/menu_inner.rs +++ b/src/widget/menu/menu_inner.rs @@ -1,13 +1,8 @@ // From iced_aw, license MIT //! Menu tree overlay -use std::{ - borrow::Cow, - sync::{Arc, Mutex}, -}; - use super::{menu_bar::MenuBarState, menu_tree::MenuTree}; -use crate::{style::menu_bar::StyleSheet, widget::dropdown}; +use crate::style::menu_bar::StyleSheet; use iced_core::{Border, Shadow}; use iced_widget::core::{ @@ -245,7 +240,7 @@ struct MenuBounds { impl MenuBounds { #[allow(clippy::too_many_arguments)] fn new( - menu_tree: &MenuTree, + menu_tree: &MenuTree<'_, Message, Renderer>, renderer: &Renderer, item_width: ItemWidth, item_height: ItemHeight, @@ -305,7 +300,7 @@ impl MenuState { overlay_offset: Vector, slice: MenuSlice, renderer: &Renderer, - menu_tree: &MenuTree, + menu_tree: &MenuTree<'_, Message, Renderer>, tree: &mut [Tree], ) -> Node where @@ -359,7 +354,7 @@ impl MenuState { overlay_offset: Vector, index: usize, renderer: &Renderer, - menu_tree: &MenuTree, + menu_tree: &MenuTree<'_, Message, Renderer>, tree: &mut Tree, ) -> Node where @@ -432,9 +427,12 @@ impl MenuState { } } -pub(crate) struct Menu<'b, Message: std::clone::Clone> { - pub(crate) tree: dropdown::menu::State, - pub(crate) menu_roots: Cow<'b, Vec>>, +pub(crate) struct Menu<'a, 'b, Message, Renderer> +where + Renderer: renderer::Renderer, +{ + pub(crate) tree: &'b mut Tree, + pub(crate) menu_roots: &'b mut Vec>, pub(crate) bounds_expand: u16, /// Allows menu overlay items to overlap the parent pub(crate) menu_overlays_parent: bool, @@ -446,10 +444,10 @@ pub(crate) struct Menu<'b, Message: std::clone::Clone> { pub(crate) cross_offset: i32, pub(crate) root_bounds_list: Vec, pub(crate) path_highlight: Option, - pub(crate) style: Cow<'b, ::Style>, + pub(crate) style: &'b ::Style, pub(crate) position: Point, } -impl<'b, Message: Clone + 'static, Renderer> Menu<'b, Message> +impl<'a, 'b, Message, Renderer> Menu<'a, 'b, Message, Renderer> where Renderer: renderer::Renderer, { @@ -753,7 +751,7 @@ fn pad_rectangle(rect: Rectangle, padding: Padding) -> Rectangle { } pub(super) fn init_root_menu( - menu: &mut Menu<'_, Message>, + menu: &mut Menu<'_, '_, Message, Renderer>, renderer: &Renderer, shell: &mut Shell<'_, Message>, overlay_cursor: Point, @@ -831,7 +829,7 @@ pub(super) fn init_root_menu( #[allow(clippy::too_many_arguments)] fn process_menu_events<'b, Message, Renderer>( tree: &'b mut Tree, - menu_roots: &'b mut [MenuTree], + menu_roots: &'b mut [MenuTree<'_, Message, Renderer>], event: event::Event, view_cursor: Cursor, renderer: &Renderer, @@ -889,7 +887,7 @@ where #[allow(unused_results)] fn process_overlay_events( - menu: &mut Menu<'_, Message>, + menu: &mut Menu<'_, '_, Message, Renderer>, renderer: &Renderer, viewport_size: Size, overlay_offset: Vector, @@ -899,7 +897,6 @@ fn process_overlay_events( ) -> event::Status where Renderer: renderer::Renderer, - Message: std::clone::Clone, { use event::Status::{Captured, Ignored}; /* @@ -1080,13 +1077,16 @@ where Captured } -fn process_scroll_events( - menu: &mut Menu<'_, Message>, +fn process_scroll_events( + menu: &mut Menu<'_, '_, Message, Renderer>, delta: mouse::ScrollDelta, overlay_cursor: Point, viewport_size: Size, overlay_offset: Vector, -) -> event::Status { +) -> event::Status +where + Renderer: renderer::Renderer, +{ use event::Status::{Captured, Ignored}; use mouse::ScrollDelta; @@ -1155,13 +1155,16 @@ fn process_scroll_events( #[allow(clippy::pedantic)] /// Returns (children_size, child_positions, child_sizes) -fn get_children_layout( - menu_tree: &MenuTree, - renderer: &crate::Renderer, +fn get_children_layout( + menu_tree: &MenuTree<'_, Message, Renderer>, + renderer: &Renderer, item_width: ItemWidth, item_height: ItemHeight, tree: &mut [Tree], -) -> (Size, Vec, Vec) { +) -> (Size, Vec, Vec) +where + Renderer: renderer::Renderer, +{ let width = match item_width { ItemWidth::Uniform(u) => f32::from(u), ItemWidth::Static(s) => f32::from(menu_tree.width.unwrap_or(s)), @@ -1181,8 +1184,7 @@ fn get_children_layout( .children .iter() .map(|mt| { - let guard = mt.item.0.lock().unwrap(); - let w = guard.as_widget(); + let w = mt.item.as_widget(); match w.size().height { Length::Fixed(f) => Size::new(width, f), Length::Shrink => { diff --git a/src/widget/menu/menu_tree.rs b/src/widget/menu/menu_tree.rs index 96c6a4aa..01ca3076 100644 --- a/src/widget/menu/menu_tree.rs +++ b/src/widget/menu/menu_tree.rs @@ -5,14 +5,13 @@ use std::borrow::Cow; use std::collections::HashMap; use std::rc::Rc; -use std::sync::{Arc, Mutex}; use iced_widget::core::{renderer, Element}; use crate::iced_core::{Alignment, Length}; +use crate::widget::icon; use crate::widget::menu::action::MenuAction; use crate::widget::menu::key_bind::KeyBind; -use crate::widget::{icon, ArcElementWrapper}; use crate::{theme, widget}; /// Nested menu is essentially a tree of items, a menu is a collection of items @@ -24,27 +23,27 @@ use crate::{theme, widget}; /// but there's no need to explicitly distinguish them here, if a menu tree /// has children, it's a menu, otherwise it's an item #[allow(missing_debug_implementations)] -#[derive(Clone)] - -pub struct MenuTree { +pub struct MenuTree<'a, Message, Renderer = crate::Renderer> { /// The menu tree will be flatten into a vector to build a linear widget tree, /// the `index` field is the index of the item in that vector pub(crate) index: usize, - // TODO needs to be wrapped in Arc, + pub(crate) item: Element<'a, Message, crate::Theme, Renderer>, /// The children of the menu tree - pub(crate) children: Vec>, + pub(crate) children: Vec>, /// The width of the menu tree pub(crate) width: Option, /// The height of the menu tree pub(crate) height: Option, } -impl MenuTree { +impl<'a, Message, Renderer> MenuTree<'a, Message, Renderer> +where + Renderer: renderer::Renderer, +{ /// Create a new menu tree from a widget - pub fn new(item: impl Into>) -> Self { + pub fn new(item: impl Into>) -> Self { Self { index: 0, item: item.into(), @@ -56,8 +55,8 @@ impl MenuTree { /// Create a menu tree from a widget and a vector of sub trees pub fn with_children( - item: impl Into>, - children: Vec>>, + item: impl Into>, + children: Vec>>, ) -> Self { Self { index: 0, @@ -93,7 +92,7 @@ impl MenuTree { /// Set the index of each item pub(crate) fn set_index(&mut self) { /// inner counting function. - fn rec(mt: &mut MenuTree, count: &mut usize) { + fn rec(mt: &mut MenuTree<'_, Message, Renderer>, count: &mut usize) { // keep items under the same menu line up mt.children.iter_mut().for_each(|c| { c.index = *count; @@ -110,32 +109,36 @@ impl MenuTree { } /// Flatten the menu tree - pub(crate) fn flatten(&self) -> Vec { + pub(crate) fn flattern(&'a self) -> Vec<&Self> { /// Inner flattening function - fn rec( - mt: &MenuTree, - flat: &mut Vec>, + fn rec<'a, Message, Renderer>( + mt: &'a MenuTree<'a, Message, Renderer>, + flat: &mut Vec<&MenuTree<'a, Message, Renderer>>, ) { - mt.children.clone().into_iter().for_each(|c| { + mt.children.iter().for_each(|c| { flat.push(c); }); mt.children.iter().for_each(|c| { - rec(&c, flat); + rec(c, flat); }); } let mut flat = Vec::new(); - flat.push(self.clone()); + flat.push(self); rec(self, &mut flat); flat } } -impl From> for MenuTree { - fn from(value: crate::Element<'static, Message>) -> Self { - Self::new(ArcElementWrapper(Arc::new(Mutex::new(value)))) +impl<'a, Message, Renderer> From> + for MenuTree<'a, Message, Renderer> +where + Renderer: renderer::Renderer, +{ + fn from(value: Element<'a, Message, crate::Theme, Renderer>) -> Self { + Self::new(value) } } @@ -154,7 +157,6 @@ pub fn menu_button<'a, Message: 'a>( .class(theme::Button::MenuItem) } -#[derive(Clone)] /// Represents a menu item that performs an action when selected or a separator between menu items. /// /// - `Action` - Represents a menu item that performs an action when selected. @@ -211,13 +213,18 @@ where /// # Returns /// - A vector of `MenuTree`. pub fn menu_items< + 'a, A: MenuAction, L: Into> + 'static, - Message: 'static + std::clone::Clone, + Message: 'a, + Renderer: renderer::Renderer + 'a, >( key_binds: &HashMap, children: Vec>, -) -> Vec> { +) -> Vec> +where + Element<'a, Message, crate::Theme, Renderer>: From>, +{ fn find_key(action: &A, key_binds: &HashMap) -> String { for (key_bind, key_action) in key_binds { if action == key_action { @@ -252,7 +259,7 @@ pub fn menu_items< let menu_button = menu_button(items).on_press(action.message()); - trees.push(MenuTree::::from(Element::from(menu_button))); + trees.push(MenuTree::::new(menu_button)); } MenuItem::ButtonDisabled(label, icon, action) => { let key = find_key(&action, key_binds); @@ -270,7 +277,7 @@ pub fn menu_items< let menu_button = menu_button(items); - trees.push(MenuTree::::from(Element::from(menu_button))); + trees.push(MenuTree::::new(menu_button)); } MenuItem::CheckBox(label, icon, value, action) => { let key = find_key(&action, key_binds); @@ -300,40 +307,36 @@ pub fn menu_items< items.insert(2, widget::icon::icon(icon).size(14).into()); } - trees.push(MenuTree::from(Element::from( - menu_button(items).on_press(action.message()), - ))); + trees.push(MenuTree::new(menu_button(items).on_press(action.message()))); } MenuItem::Folder(label, children) => { - trees.push(MenuTree::::with_children( - ArcElementWrapper(Arc::new(Mutex::new(crate::Element::from( - menu_button::<'static, _>(vec![ - widget::text(label).into(), - widget::horizontal_space().into(), - widget::icon::from_name("pan-end-symbolic") - .size(16) - .icon() - .into(), - ]) - .class( - // Menu folders have no on_press so they take on the disabled style by default - if children.is_empty() { - // This will make the folder use the disabled style if it has no children - theme::Button::MenuItem - } else { - // This will make the folder use the enabled style if it has children - theme::Button::MenuFolder - }, - ), - )))), + trees.push(MenuTree::::with_children( + menu_button(vec![ + widget::text(label).into(), + widget::horizontal_space().into(), + widget::icon::from_name("pan-end-symbolic") + .size(16) + .icon() + .into(), + ]) + .class( + // Menu folders have no on_press so they take on the disabled style by default + if children.is_empty() { + // This will make the folder use the disabled style if it has no children + theme::Button::MenuItem + } else { + // This will make the folder use the enabled style if it has children + theme::Button::MenuFolder + }, + ), menu_items(key_binds, children), )); } MenuItem::Divider => { if i != size - 1 { - trees.push(MenuTree::::from(Element::from( + trees.push(MenuTree::::new( widget::divider::horizontal::light(), - ))); + )); } } } diff --git a/src/widget/nav_bar.rs b/src/widget/nav_bar.rs index e6bb7037..5a32b4a3 100644 --- a/src/widget/nav_bar.rs +++ b/src/widget/nav_bar.rs @@ -67,7 +67,7 @@ impl<'a, Message: Clone + 'static> NavBar<'a, Message> { self } - pub fn context_menu(mut self, context_menu: Option>>) -> Self { + pub fn context_menu(mut self, context_menu: Option>>) -> Self { self.segmented_button = self.segmented_button.context_menu(context_menu); self } diff --git a/src/widget/segmented_button/widget.rs b/src/widget/segmented_button/widget.rs index 209c5b8e..e40465d0 100644 --- a/src/widget/segmented_button/widget.rs +++ b/src/widget/segmented_button/widget.rs @@ -9,7 +9,7 @@ use crate::widget::menu::{ self, menu_roots_children, menu_roots_diff, CloseCondition, ItemHeight, ItemWidth, MenuBarState, PathHighlight, }; -use crate::widget::{dropdown, icon, Icon}; +use crate::widget::{icon, Icon}; use crate::{Element, Renderer}; use derive_setters::Setters; use iced::clipboard::dnd::{self, DndAction, DndDestinationRectangle, DndEvent, OfferEvent}; @@ -127,7 +127,7 @@ where pub(super) style: Style, /// The context menu to display when a context is activated #[setters(skip)] - pub(super) context_menu: Option>>, + pub(super) context_menu: Option>>, /// Emits the ID of the item that was activated. #[setters(skip)] pub(super) on_activate: Option Message + 'static>>, @@ -197,13 +197,13 @@ where } } - pub fn context_menu(mut self, context_menu: Option>>) -> Self + pub fn context_menu(mut self, context_menu: Option>>) -> Self where - Message: Clone + 'static, + Message: 'static, { self.context_menu = context_menu.map(|menus| { vec![menu::Tree::with_children( - crate::Element::from(crate::widget::row::<'static, Message>()), + crate::widget::row::<'static, Message>(), menus, )] }); @@ -593,7 +593,6 @@ where dnd_state: Default::default(), fingers_pressed: Default::default(), pressed_item: None, - menu_state: Default::default(), }) } @@ -1553,7 +1552,7 @@ where translation: Vector, ) -> Option> { let state = tree.state.downcast_ref::(); - let menu_state = state.menu_state.clone(); + let Some(entity) = state.show_context else { return None; }; @@ -1581,8 +1580,8 @@ where Some( crate::widget::menu::Menu { - tree: menu_state, - menu_roots: Cow::Borrowed(context_menu), + tree: &mut tree.children[0], + menu_roots: context_menu, bounds_expand: 16, menu_overlays_parent: true, close_condition: CloseCondition { @@ -1597,7 +1596,7 @@ where cross_offset: 0, root_bounds_list: vec![bounds], path_highlight: Some(PathHighlight::MenuActive), - style: Cow::Owned(crate::theme::menu_bar::MenuBarStyle::Default), + style: &crate::theme::menu_bar::MenuBarStyle::Default, position: Point::new(translation.x, translation.y), } .overlay(), @@ -1684,8 +1683,6 @@ pub struct LocalState { fingers_pressed: HashSet, /// The currently pressed item pressed_item: Option, - /// Menu state - pub(crate) menu_state: dropdown::menu::State, } #[derive(Debug, Default, PartialEq)] diff --git a/src/widget/wrapper.rs b/src/widget/wrapper.rs index cb1fe673..ca63dded 100644 --- a/src/widget/wrapper.rs +++ b/src/widget/wrapper.rs @@ -1,19 +1,55 @@ -use std::sync::{Arc, Mutex}; +use std::{ + cell::RefCell, + rc::Rc, + thread::{self, ThreadId}, +}; use crate::Element; use iced::{event, Length, Rectangle, Size}; use iced_core::{id::Id, widget, widget::tree, Widget}; #[derive(Clone)] -pub struct ArcElementWrapper(pub Arc>>); +pub struct RcElementWrapper { + pub(crate) element: Rc>>, + pub(crate) thread_id: ThreadId, +} -impl Widget for ArcElementWrapper { +impl RcElementWrapper { + pub fn new(element: Element<'static, M>) -> Self { + Self { + element: Rc::new(RefCell::new(element)), + thread_id: thread::current().id(), + } + } + + pub fn with_element(&self, f: impl FnOnce(&Element<'static, M>) -> T) -> T { + assert_eq!(self.thread_id, thread::current().id()); + let my_ref: &Element<'static, M> = &RefCell::borrow(self.element.as_ref()); + f(my_ref) + } + + pub fn with_element_mut(&self, f: impl FnOnce(&mut Element<'static, M>) -> T) -> T { + assert_eq!(self.thread_id, thread::current().id()); + let my_refmut: &mut Element<'static, M> = &mut RefCell::borrow_mut(self.element.as_ref()); + f(my_refmut) + } + + pub(crate) unsafe fn as_ptr(&self) -> *mut Element<'static, M> { + assert_eq!(self.thread_id, thread::current().id()); + RefCell::as_ptr(self.element.as_ref()) + } +} + +unsafe impl Send for RcElementWrapper {} +unsafe impl Sync for RcElementWrapper {} + +impl Widget for RcElementWrapper { fn size(&self) -> Size { - self.0.lock().unwrap().as_widget().size() + self.with_element(|e| e.as_widget().size()) } fn size_hint(&self) -> Size { - self.0.lock().unwrap().as_widget().size_hint() + self.element.borrow_mut().as_widget().size_hint() } fn layout( @@ -22,11 +58,7 @@ impl Widget for ArcElementWrapper { renderer: &crate::Renderer, limits: &crate::iced_core::layout::Limits, ) -> crate::iced_core::layout::Node { - self.0 - .lock() - .unwrap() - .as_widget_mut() - .layout(tree, renderer, limits) + self.with_element_mut(|e| e.as_widget_mut().layout(tree, renderer, limits)) } fn draw( @@ -39,27 +71,26 @@ impl Widget for ArcElementWrapper { cursor: crate::iced_core::mouse::Cursor, viewport: &Rectangle, ) { - self.0 - .lock() - .unwrap() - .as_widget() - .draw(tree, renderer, theme, style, layout, cursor, viewport) + self.with_element(move |e| { + e.as_widget() + .draw(tree, renderer, theme, style, layout, cursor, viewport) + }) } fn tag(&self) -> tree::Tag { - self.0.lock().unwrap().as_widget().tag() + self.with_element(|e| e.as_widget().tag()) } fn state(&self) -> tree::State { - self.0.lock().unwrap().as_widget().state() + self.with_element(|e| e.as_widget().state()) } fn children(&self) -> Vec { - self.0.lock().unwrap().as_widget().children() + self.with_element(|e| e.as_widget().children()) } fn diff(&mut self, tree: &mut tree::Tree) { - self.0.lock().unwrap().as_widget_mut().diff(tree) + self.with_element_mut(|e| e.as_widget_mut().diff(tree)) } fn operate( @@ -69,87 +100,88 @@ impl Widget for ArcElementWrapper { renderer: &crate::Renderer, operation: &mut dyn widget::Operation, ) { - self.0 - .lock() - .unwrap() - .as_widget() - .operate(state, layout, renderer, operation) + self.with_element(|e| { + e.as_widget().operate(state, layout, renderer, operation); + }) } fn on_event( &mut self, - _state: &mut tree::Tree, - _event: crate::iced::Event, - _layout: crate::iced_core::Layout<'_>, - _cursor: crate::iced_core::mouse::Cursor, - _renderer: &crate::Renderer, - _clipboard: &mut dyn crate::iced_core::Clipboard, - _shell: &mut crate::iced_core::Shell<'_, M>, - _viewport: &Rectangle, + state: &mut tree::Tree, + event: crate::iced::Event, + layout: crate::iced_core::Layout<'_>, + cursor: crate::iced_core::mouse::Cursor, + renderer: &crate::Renderer, + clipboard: &mut dyn crate::iced_core::Clipboard, + shell: &mut crate::iced_core::Shell<'_, M>, + viewport: &Rectangle, ) -> event::Status { - self.0.lock().unwrap().as_widget_mut().on_event( - _state, _event, _layout, _cursor, _renderer, _clipboard, _shell, _viewport, - ) + self.with_element_mut(|e| { + e.as_widget_mut().on_event( + state, event, layout, cursor, renderer, clipboard, shell, viewport, + ) + }) } fn mouse_interaction( &self, - _state: &tree::Tree, - _layout: crate::iced_core::Layout<'_>, - _cursor: crate::iced_core::mouse::Cursor, - _viewport: &Rectangle, - _renderer: &crate::Renderer, + state: &tree::Tree, + layout: crate::iced_core::Layout<'_>, + cursor: crate::iced_core::mouse::Cursor, + viewport: &Rectangle, + renderer: &crate::Renderer, ) -> crate::iced_core::mouse::Interaction { - self.0 - .lock() - .unwrap() - .as_widget() - .mouse_interaction(_state, _layout, _cursor, _viewport, _renderer) + self.with_element(|e| { + e.as_widget() + .mouse_interaction(state, layout, cursor, viewport, renderer) + }) } fn overlay<'a>( &'a mut self, - _state: &'a mut tree::Tree, - _layout: crate::iced_core::Layout<'_>, - _renderer: &crate::Renderer, - _translation: crate::iced_core::Vector, + state: &'a mut tree::Tree, + layout: crate::iced_core::Layout<'_>, + renderer: &crate::Renderer, + translation: crate::iced_core::Vector, ) -> Option> { - // TODO - None + assert_eq!(self.thread_id, thread::current().id()); + Rc::get_mut(&mut self.element).and_then(|e| { + e.get_mut() + .as_widget_mut() + .overlay(state, layout, renderer, translation) + }) } fn id(&self) -> Option { - self.0.lock().unwrap().as_widget().id() + self.with_element_mut(|e| e.as_widget_mut().id()) } - fn set_id(&mut self, _id: Id) { - self.0.lock().unwrap().as_widget_mut().set_id(_id) + fn set_id(&mut self, id: Id) { + self.with_element_mut(|e| e.as_widget_mut().set_id(id)) } fn drag_destinations( &self, - _state: &tree::Tree, - _layout: crate::iced_core::Layout<'_>, + state: &tree::Tree, + layout: crate::iced_core::Layout<'_>, renderer: &crate::Renderer, - _dnd_rectangles: &mut crate::iced_core::clipboard::DndDestinationRectangles, + dnd_rectangles: &mut crate::iced_core::clipboard::DndDestinationRectangles, ) { - self.0.lock().unwrap().as_widget().drag_destinations( - _state, - _layout, - renderer, - _dnd_rectangles, - ) + self.with_element_mut(|e| { + e.as_widget_mut() + .drag_destinations(state, layout, renderer, dnd_rectangles) + }) } } -impl From> for Element<'static, Message> { - fn from(wrapper: ArcElementWrapper) -> Self { +impl From> for Element<'static, Message> { + fn from(wrapper: RcElementWrapper) -> Self { Element::new(wrapper) } } -impl From> for ArcElementWrapper { +impl From> for RcElementWrapper { fn from(e: Element<'static, Message>) -> Self { - ArcElementWrapper(Arc::new(Mutex::new(e))) + RcElementWrapper::new(e) } }