fix(popover): implement overlay and remove use of refcell

This commit is contained in:
Jeremy Soller 2024-09-10 11:43:08 -06:00
parent b66f8986d1
commit 05da0a83b2

View file

@ -13,7 +13,6 @@ use iced_core::widget::{tree, Operation, OperationOutputWrapper, Tree};
use iced_core::{ use iced_core::{
Clipboard, Element, Layout, Length, Point, Rectangle, Shell, Size, Vector, Widget, Clipboard, Element, Layout, Length, Point, Rectangle, Shell, Size, Vector, Widget,
}; };
use std::cell::RefCell;
pub use iced_style::container::{Appearance, StyleSheet}; pub use iced_style::container::{Appearance, StyleSheet};
@ -35,8 +34,7 @@ pub enum Position {
pub struct Popover<'a, Message, Renderer> { pub struct Popover<'a, Message, Renderer> {
content: Element<'a, Message, crate::Theme, Renderer>, content: Element<'a, Message, crate::Theme, Renderer>,
modal: bool, modal: bool,
// XXX Avoid refcell; improve iced overlay API? popup: Option<Element<'a, Message, crate::Theme, Renderer>>,
popup: Option<RefCell<Element<'a, Message, crate::Theme, Renderer>>>,
position: Position, position: Position,
on_close: Option<Message>, on_close: Option<Message>,
} }
@ -65,7 +63,7 @@ impl<'a, Message, Renderer> Popover<'a, Message, Renderer> {
} }
pub fn popup(mut self, popup: impl Into<Element<'a, Message, crate::Theme, Renderer>>) -> Self { pub fn popup(mut self, popup: impl Into<Element<'a, Message, crate::Theme, Renderer>>) -> Self {
self.popup = Some(RefCell::new(popup.into())); self.popup = Some(popup.into());
self self
} }
@ -92,7 +90,7 @@ where
fn children(&self) -> Vec<Tree> { fn children(&self) -> Vec<Tree> {
if let Some(popup) = &self.popup { if let Some(popup) = &self.popup {
vec![Tree::new(&self.content), Tree::new(&*popup.borrow())] vec![Tree::new(&self.content), Tree::new(popup)]
} else { } else {
vec![Tree::new(&self.content)] vec![Tree::new(&self.content)]
} }
@ -100,7 +98,7 @@ where
fn diff(&mut self, tree: &mut Tree) { fn diff(&mut self, tree: &mut Tree) {
if let Some(popup) = &mut self.popup { if let Some(popup) = &mut self.popup {
tree.diff_children(&mut [&mut self.content, &mut popup.borrow_mut()]); tree.diff_children(&mut [&mut self.content, popup]);
} else { } else {
tree.diff_children(&mut [&mut self.content]); tree.diff_children(&mut [&mut self.content]);
} }
@ -221,7 +219,7 @@ where
return None; return None;
} }
if let Some(popup) = &self.popup { if let Some(popup) = &mut self.popup {
let bounds = layout.bounds(); let bounds = layout.bounds();
// Calculate overlay position from relative position // Calculate overlay position from relative position
@ -242,7 +240,6 @@ where
overlay_position.x = overlay_position.x.round(); overlay_position.x = overlay_position.x.round();
overlay_position.y = overlay_position.y.round(); overlay_position.y = overlay_position.y.round();
// XXX needed to use RefCell to get &mut for popup element
Some(overlay::Element::new( Some(overlay::Element::new(
overlay_position, overlay_position,
Box::new(Overlay { Box::new(Overlay {
@ -287,7 +284,7 @@ where
pub struct Overlay<'a, 'b, Message, Renderer> { pub struct Overlay<'a, 'b, Message, Renderer> {
tree: &'a mut Tree, tree: &'a mut Tree,
content: &'a RefCell<Element<'b, Message, crate::Theme, Renderer>>, content: &'a mut Element<'b, Message, crate::Theme, Renderer>,
position: Position, position: Position,
} }
@ -307,7 +304,6 @@ where
let limits = layout::Limits::new(Size::UNIT, bounds); let limits = layout::Limits::new(Size::UNIT, bounds);
let node = self let node = self
.content .content
.borrow()
.as_widget() .as_widget()
.layout(self.tree, renderer, &limits); .layout(self.tree, renderer, &limits);
match self.position { match self.position {
@ -347,7 +343,6 @@ where
operation: &mut dyn Operation<OperationOutputWrapper<Message>>, operation: &mut dyn Operation<OperationOutputWrapper<Message>>,
) { ) {
self.content self.content
.borrow()
.as_widget() .as_widget()
.operate(self.tree, layout, renderer, operation); .operate(self.tree, layout, renderer, operation);
} }
@ -361,7 +356,7 @@ where
clipboard: &mut dyn Clipboard, clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Message>, shell: &mut Shell<'_, Message>,
) -> event::Status { ) -> event::Status {
self.content.borrow_mut().as_widget_mut().on_event( self.content.as_widget_mut().on_event(
self.tree, self.tree,
event, event,
layout, layout,
@ -380,7 +375,7 @@ where
viewport: &Rectangle, viewport: &Rectangle,
renderer: &Renderer, renderer: &Renderer,
) -> mouse::Interaction { ) -> mouse::Interaction {
self.content.borrow().as_widget().mouse_interaction( self.content.as_widget().mouse_interaction(
self.tree, self.tree,
layout, layout,
cursor_position, cursor_position,
@ -398,7 +393,7 @@ where
cursor_position: mouse::Cursor, cursor_position: mouse::Cursor,
) { ) {
let bounds = layout.bounds(); let bounds = layout.bounds();
self.content.borrow().as_widget().draw( self.content.as_widget().draw(
self.tree, self.tree,
renderer, renderer,
theme, theme,
@ -408,6 +403,16 @@ where
&bounds, &bounds,
); );
} }
fn overlay<'c>(
&'c mut self,
layout: Layout<'_>,
renderer: &Renderer,
) -> Option<overlay::Element<'c, Message, crate::Theme, Renderer>> {
self.content
.as_widget_mut()
.overlay(&mut self.tree, layout, renderer)
}
} }
/// The local state of a [`Popover`]. /// The local state of a [`Popover`].