Merge pull request #1644 from nicksenger/fix/lazy-widget
Fix `overlay` implementation for `Lazy` widget
This commit is contained in:
commit
ca337b880f
4 changed files with 211 additions and 218 deletions
|
|
@ -1,10 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "cached"
|
|
||||||
version = "0.1.0"
|
|
||||||
authors = ["Nick Senger <dev@nsenger.com>"]
|
|
||||||
edition = "2021"
|
|
||||||
publish = false
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
iced = { path = "../..", features = ["debug"] }
|
|
||||||
iced_lazy = { path = "../../lazy" }
|
|
||||||
|
|
@ -1,139 +0,0 @@
|
||||||
use iced::theme;
|
|
||||||
use iced::widget::{
|
|
||||||
button, column, horizontal_space, row, scrollable, text, text_input,
|
|
||||||
};
|
|
||||||
use iced::{Element, Length, Sandbox, Settings};
|
|
||||||
use iced_lazy::lazy;
|
|
||||||
|
|
||||||
use std::collections::HashSet;
|
|
||||||
|
|
||||||
pub fn main() -> iced::Result {
|
|
||||||
App::run(Settings::default())
|
|
||||||
}
|
|
||||||
|
|
||||||
struct App {
|
|
||||||
options: HashSet<String>,
|
|
||||||
input: String,
|
|
||||||
order: Order,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for App {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
options: ["Foo", "Bar", "Baz", "Qux", "Corge", "Waldo", "Fred"]
|
|
||||||
.into_iter()
|
|
||||||
.map(ToString::to_string)
|
|
||||||
.collect(),
|
|
||||||
input: Default::default(),
|
|
||||||
order: Order::Ascending,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
enum Message {
|
|
||||||
InputChanged(String),
|
|
||||||
ToggleOrder,
|
|
||||||
DeleteOption(String),
|
|
||||||
AddOption(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Sandbox for App {
|
|
||||||
type Message = Message;
|
|
||||||
|
|
||||||
fn new() -> Self {
|
|
||||||
Self::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn title(&self) -> String {
|
|
||||||
String::from("Cached - Iced")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self, message: Message) {
|
|
||||||
match message {
|
|
||||||
Message::InputChanged(input) => {
|
|
||||||
self.input = input;
|
|
||||||
}
|
|
||||||
Message::ToggleOrder => {
|
|
||||||
self.order = match self.order {
|
|
||||||
Order::Ascending => Order::Descending,
|
|
||||||
Order::Descending => Order::Ascending,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Message::AddOption(option) => {
|
|
||||||
self.options.insert(option);
|
|
||||||
self.input.clear();
|
|
||||||
}
|
|
||||||
Message::DeleteOption(option) => {
|
|
||||||
self.options.remove(&option);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Element<Message> {
|
|
||||||
let options = lazy((&self.order, self.options.len()), || {
|
|
||||||
let mut options: Vec<_> = self.options.iter().collect();
|
|
||||||
|
|
||||||
options.sort_by(|a, b| match self.order {
|
|
||||||
Order::Ascending => a.to_lowercase().cmp(&b.to_lowercase()),
|
|
||||||
Order::Descending => b.to_lowercase().cmp(&a.to_lowercase()),
|
|
||||||
});
|
|
||||||
|
|
||||||
column(
|
|
||||||
options
|
|
||||||
.into_iter()
|
|
||||||
.map(|option| {
|
|
||||||
row![
|
|
||||||
text(option),
|
|
||||||
horizontal_space(Length::Fill),
|
|
||||||
button("Delete")
|
|
||||||
.on_press(Message::DeleteOption(
|
|
||||||
option.to_string(),
|
|
||||||
),)
|
|
||||||
.style(theme::Button::Destructive)
|
|
||||||
]
|
|
||||||
.into()
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
)
|
|
||||||
.spacing(10)
|
|
||||||
});
|
|
||||||
|
|
||||||
column![
|
|
||||||
scrollable(options).height(Length::Fill),
|
|
||||||
row![
|
|
||||||
text_input(
|
|
||||||
"Add a new option",
|
|
||||||
&self.input,
|
|
||||||
Message::InputChanged,
|
|
||||||
)
|
|
||||||
.on_submit(Message::AddOption(self.input.clone())),
|
|
||||||
button(text(format!("Toggle Order ({})", self.order)))
|
|
||||||
.on_press(Message::ToggleOrder)
|
|
||||||
]
|
|
||||||
.spacing(10)
|
|
||||||
]
|
|
||||||
.spacing(20)
|
|
||||||
.padding(20)
|
|
||||||
.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Hash)]
|
|
||||||
enum Order {
|
|
||||||
Ascending,
|
|
||||||
Descending,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Display for Order {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"{}",
|
|
||||||
match self {
|
|
||||||
Self::Ascending => "Ascending",
|
|
||||||
Self::Descending => "Descending",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +1,21 @@
|
||||||
use iced::theme;
|
use iced::theme;
|
||||||
use iced::widget::{
|
use iced::widget::{
|
||||||
button, column, horizontal_space, row, scrollable, text, text_input,
|
button, column, horizontal_space, pick_list, row, scrollable, text,
|
||||||
|
text_input,
|
||||||
};
|
};
|
||||||
use iced::{Element, Length, Sandbox, Settings};
|
use iced::{Element, Length, Sandbox, Settings};
|
||||||
use iced_lazy::lazy;
|
use iced_lazy::lazy;
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
use std::hash::Hash;
|
||||||
|
|
||||||
pub fn main() -> iced::Result {
|
pub fn main() -> iced::Result {
|
||||||
App::run(Settings::default())
|
App::run(Settings::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
struct App {
|
struct App {
|
||||||
options: HashSet<String>,
|
version: u8,
|
||||||
|
items: HashSet<Item>,
|
||||||
input: String,
|
input: String,
|
||||||
order: Order,
|
order: Order,
|
||||||
}
|
}
|
||||||
|
|
@ -20,9 +23,10 @@ struct App {
|
||||||
impl Default for App {
|
impl Default for App {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
options: ["Foo", "Bar", "Baz", "Qux", "Corge", "Waldo", "Fred"]
|
version: 0,
|
||||||
|
items: ["Foo", "Bar", "Baz", "Qux", "Corge", "Waldo", "Fred"]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(ToString::to_string)
|
.map(From::from)
|
||||||
.collect(),
|
.collect(),
|
||||||
input: Default::default(),
|
input: Default::default(),
|
||||||
order: Order::Ascending,
|
order: Order::Ascending,
|
||||||
|
|
@ -30,12 +34,92 @@ impl Default for App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
|
||||||
|
enum Color {
|
||||||
|
#[default]
|
||||||
|
Black,
|
||||||
|
Red,
|
||||||
|
Orange,
|
||||||
|
Yellow,
|
||||||
|
Green,
|
||||||
|
Blue,
|
||||||
|
Purple,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Color {
|
||||||
|
const ALL: &[Color] = &[
|
||||||
|
Color::Black,
|
||||||
|
Color::Red,
|
||||||
|
Color::Orange,
|
||||||
|
Color::Yellow,
|
||||||
|
Color::Green,
|
||||||
|
Color::Blue,
|
||||||
|
Color::Purple,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for Color {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.write_str(match self {
|
||||||
|
Self::Black => "Black",
|
||||||
|
Self::Red => "Red",
|
||||||
|
Self::Orange => "Orange",
|
||||||
|
Self::Yellow => "Yellow",
|
||||||
|
Self::Green => "Green",
|
||||||
|
Self::Blue => "Blue",
|
||||||
|
Self::Purple => "Purple",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Color> for iced::Color {
|
||||||
|
fn from(value: Color) -> Self {
|
||||||
|
match value {
|
||||||
|
Color::Black => iced::Color::from_rgb8(0, 0, 0),
|
||||||
|
Color::Red => iced::Color::from_rgb8(220, 50, 47),
|
||||||
|
Color::Orange => iced::Color::from_rgb8(203, 75, 22),
|
||||||
|
Color::Yellow => iced::Color::from_rgb8(181, 137, 0),
|
||||||
|
Color::Green => iced::Color::from_rgb8(133, 153, 0),
|
||||||
|
Color::Blue => iced::Color::from_rgb8(38, 139, 210),
|
||||||
|
Color::Purple => iced::Color::from_rgb8(108, 113, 196),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq)]
|
||||||
|
struct Item {
|
||||||
|
name: String,
|
||||||
|
color: Color,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hash for Item {
|
||||||
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
|
self.name.hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Item {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.name.eq(&other.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for Item {
|
||||||
|
fn from(s: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
name: s.to_owned(),
|
||||||
|
color: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
enum Message {
|
enum Message {
|
||||||
InputChanged(String),
|
InputChanged(String),
|
||||||
ToggleOrder,
|
ToggleOrder,
|
||||||
DeleteOption(String),
|
DeleteItem(Item),
|
||||||
AddOption(String),
|
AddItem(String),
|
||||||
|
ItemColorChanged(Item, Color),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sandbox for App {
|
impl Sandbox for App {
|
||||||
|
|
@ -46,7 +130,7 @@ impl Sandbox for App {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn title(&self) -> String {
|
fn title(&self) -> String {
|
||||||
String::from("Cached - Iced")
|
String::from("Lazy - Iced")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, message: Message) {
|
fn update(&mut self, message: Message) {
|
||||||
|
|
@ -55,43 +139,71 @@ impl Sandbox for App {
|
||||||
self.input = input;
|
self.input = input;
|
||||||
}
|
}
|
||||||
Message::ToggleOrder => {
|
Message::ToggleOrder => {
|
||||||
|
self.version = self.version.wrapping_add(1);
|
||||||
self.order = match self.order {
|
self.order = match self.order {
|
||||||
Order::Ascending => Order::Descending,
|
Order::Ascending => Order::Descending,
|
||||||
Order::Descending => Order::Ascending,
|
Order::Descending => Order::Ascending,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::AddOption(option) => {
|
Message::AddItem(name) => {
|
||||||
self.options.insert(option);
|
self.version = self.version.wrapping_add(1);
|
||||||
|
self.items.insert(name.as_str().into());
|
||||||
self.input.clear();
|
self.input.clear();
|
||||||
}
|
}
|
||||||
Message::DeleteOption(option) => {
|
Message::DeleteItem(item) => {
|
||||||
self.options.remove(&option);
|
self.version = self.version.wrapping_add(1);
|
||||||
|
self.items.remove(&item);
|
||||||
|
}
|
||||||
|
Message::ItemColorChanged(item, color) => {
|
||||||
|
self.version = self.version.wrapping_add(1);
|
||||||
|
if self.items.remove(&item) {
|
||||||
|
self.items.insert(Item {
|
||||||
|
name: item.name,
|
||||||
|
color,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Element<Message> {
|
fn view(&self) -> Element<Message> {
|
||||||
let options = lazy((&self.order, self.options.len()), || {
|
let options = lazy(self.version, || {
|
||||||
let mut options: Vec<_> = self.options.iter().collect();
|
let mut items: Vec<_> = self.items.iter().cloned().collect();
|
||||||
|
|
||||||
options.sort_by(|a, b| match self.order {
|
items.sort_by(|a, b| match self.order {
|
||||||
Order::Ascending => a.to_lowercase().cmp(&b.to_lowercase()),
|
Order::Ascending => {
|
||||||
Order::Descending => b.to_lowercase().cmp(&a.to_lowercase()),
|
a.name.to_lowercase().cmp(&b.name.to_lowercase())
|
||||||
|
}
|
||||||
|
Order::Descending => {
|
||||||
|
b.name.to_lowercase().cmp(&a.name.to_lowercase())
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
column(
|
column(
|
||||||
options
|
items
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|option| {
|
.map(|item| {
|
||||||
|
let button = button("Delete")
|
||||||
|
.on_press(Message::DeleteItem(item.clone()))
|
||||||
|
.style(theme::Button::Destructive);
|
||||||
|
|
||||||
row![
|
row![
|
||||||
text(option),
|
text(&item.name)
|
||||||
|
.style(theme::Text::Color(item.color.into())),
|
||||||
horizontal_space(Length::Fill),
|
horizontal_space(Length::Fill),
|
||||||
button("Delete")
|
pick_list(
|
||||||
.on_press(Message::DeleteOption(
|
Color::ALL,
|
||||||
option.to_string(),
|
Some(item.color),
|
||||||
),)
|
move |color| {
|
||||||
.style(theme::Button::Destructive)
|
Message::ItemColorChanged(
|
||||||
|
item.clone(),
|
||||||
|
color,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
),
|
||||||
|
button
|
||||||
]
|
]
|
||||||
|
.spacing(20)
|
||||||
.into()
|
.into()
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
|
|
@ -107,7 +219,7 @@ impl Sandbox for App {
|
||||||
&self.input,
|
&self.input,
|
||||||
Message::InputChanged,
|
Message::InputChanged,
|
||||||
)
|
)
|
||||||
.on_submit(Message::AddOption(self.input.clone())),
|
.on_submit(Message::AddItem(self.input.clone())),
|
||||||
button(text(format!("Toggle Order ({})", self.order)))
|
button(text(format!("Toggle Order ({})", self.order)))
|
||||||
.on_press(Message::ToggleOrder)
|
.on_press(Message::ToggleOrder)
|
||||||
]
|
]
|
||||||
|
|
|
||||||
118
lazy/src/lazy.rs
118
lazy/src/lazy.rs
|
|
@ -9,16 +9,17 @@ use iced_native::Element;
|
||||||
use iced_native::{Clipboard, Hasher, Length, Point, Rectangle, Shell, Size};
|
use iced_native::{Clipboard, Hasher, Length, Point, Rectangle, Shell, Size};
|
||||||
|
|
||||||
use ouroboros::self_referencing;
|
use ouroboros::self_referencing;
|
||||||
use std::cell::{Ref, RefCell, RefMut};
|
use std::cell::RefCell;
|
||||||
use std::hash::{Hash, Hasher as H};
|
use std::hash::{Hash, Hasher as H};
|
||||||
use std::marker::PhantomData;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct Lazy<'a, Message, Renderer, Dependency, View> {
|
pub struct Lazy<'a, Message, Renderer, Dependency, View> {
|
||||||
dependency: Dependency,
|
dependency: Dependency,
|
||||||
view: Box<dyn Fn() -> View + 'a>,
|
view: Box<dyn Fn() -> View + 'a>,
|
||||||
element: RefCell<Option<Rc<RefCell<Element<'static, Message, Renderer>>>>>,
|
element: RefCell<
|
||||||
|
Option<Rc<RefCell<Option<Element<'static, Message, Renderer>>>>>,
|
||||||
|
>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Message, Renderer, Dependency, View>
|
impl<'a, Message, Renderer, Dependency, View>
|
||||||
|
|
@ -37,21 +38,35 @@ where
|
||||||
|
|
||||||
fn with_element<T>(
|
fn with_element<T>(
|
||||||
&self,
|
&self,
|
||||||
f: impl FnOnce(Ref<Element<Message, Renderer>>) -> T,
|
f: impl FnOnce(&Element<Message, Renderer>) -> T,
|
||||||
) -> T {
|
) -> T {
|
||||||
f(self.element.borrow().as_ref().unwrap().borrow())
|
f(self
|
||||||
|
.element
|
||||||
|
.borrow()
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.borrow()
|
||||||
|
.as_ref()
|
||||||
|
.unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_element_mut<T>(
|
fn with_element_mut<T>(
|
||||||
&self,
|
&self,
|
||||||
f: impl FnOnce(RefMut<Element<Message, Renderer>>) -> T,
|
f: impl FnOnce(&mut Element<Message, Renderer>) -> T,
|
||||||
) -> T {
|
) -> T {
|
||||||
f(self.element.borrow().as_ref().unwrap().borrow_mut())
|
f(self
|
||||||
|
.element
|
||||||
|
.borrow()
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.borrow_mut()
|
||||||
|
.as_mut()
|
||||||
|
.unwrap())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Internal<Message, Renderer> {
|
struct Internal<Message, Renderer> {
|
||||||
element: Rc<RefCell<Element<'static, Message, Renderer>>>,
|
element: Rc<RefCell<Option<Element<'static, Message, Renderer>>>>,
|
||||||
hash: u64,
|
hash: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -73,7 +88,7 @@ where
|
||||||
self.dependency.hash(&mut hasher);
|
self.dependency.hash(&mut hasher);
|
||||||
let hash = hasher.finish();
|
let hash = hasher.finish();
|
||||||
|
|
||||||
let element = Rc::new(RefCell::new((self.view)().into()));
|
let element = Rc::new(RefCell::new(Some((self.view)().into())));
|
||||||
|
|
||||||
(*self.element.borrow_mut()) = Some(element.clone());
|
(*self.element.borrow_mut()) = Some(element.clone());
|
||||||
|
|
||||||
|
|
@ -81,9 +96,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn children(&self) -> Vec<Tree> {
|
fn children(&self) -> Vec<Tree> {
|
||||||
vec![Tree::new(
|
self.with_element(|element| vec![Tree::new(element.as_widget())])
|
||||||
self.element.borrow().as_ref().unwrap().borrow().as_widget(),
|
|
||||||
)]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn diff(&self, tree: &mut Tree) {
|
fn diff(&self, tree: &mut Tree) {
|
||||||
|
|
@ -97,12 +110,12 @@ where
|
||||||
current.hash = new_hash;
|
current.hash = new_hash;
|
||||||
|
|
||||||
let element = (self.view)().into();
|
let element = (self.view)().into();
|
||||||
current.element = Rc::new(RefCell::new(element));
|
current.element = Rc::new(RefCell::new(Some(element)));
|
||||||
|
|
||||||
(*self.element.borrow_mut()) = Some(current.element.clone());
|
(*self.element.borrow_mut()) = Some(current.element.clone());
|
||||||
tree.diff_children(std::slice::from_ref(
|
self.with_element(|element| {
|
||||||
&self.element.borrow().as_ref().unwrap().borrow().as_widget(),
|
tree.diff_children(std::slice::from_ref(&element.as_widget()))
|
||||||
));
|
});
|
||||||
} else {
|
} else {
|
||||||
(*self.element.borrow_mut()) = Some(current.element.clone());
|
(*self.element.borrow_mut()) = Some(current.element.clone());
|
||||||
}
|
}
|
||||||
|
|
@ -153,7 +166,7 @@ where
|
||||||
clipboard: &mut dyn Clipboard,
|
clipboard: &mut dyn Clipboard,
|
||||||
shell: &mut Shell<'_, Message>,
|
shell: &mut Shell<'_, Message>,
|
||||||
) -> event::Status {
|
) -> event::Status {
|
||||||
self.with_element_mut(|mut element| {
|
self.with_element_mut(|element| {
|
||||||
element.as_widget_mut().on_event(
|
element.as_widget_mut().on_event(
|
||||||
&mut tree.children[0],
|
&mut tree.children[0],
|
||||||
event,
|
event,
|
||||||
|
|
@ -214,23 +227,27 @@ where
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
) -> Option<overlay::Element<'_, Message, Renderer>> {
|
) -> Option<overlay::Element<'_, Message, Renderer>> {
|
||||||
let overlay = OverlayBuilder {
|
let overlay = Overlay(Some(
|
||||||
cached: self,
|
InnerBuilder {
|
||||||
tree: &mut tree.children[0],
|
cell: self.element.borrow().as_ref().unwrap().clone(),
|
||||||
types: PhantomData,
|
element: self
|
||||||
overlay_builder: |cached, tree| {
|
.element
|
||||||
Rc::get_mut(cached.element.get_mut().as_mut().unwrap())
|
.borrow()
|
||||||
|
.as_ref()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.get_mut()
|
.borrow_mut()
|
||||||
.as_widget_mut()
|
.take()
|
||||||
.overlay(tree, layout, renderer)
|
.unwrap(),
|
||||||
},
|
tree: &mut tree.children[0],
|
||||||
}
|
overlay_builder: |element, tree| {
|
||||||
.build();
|
element.as_widget_mut().overlay(tree, layout, renderer)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
.build(),
|
||||||
|
));
|
||||||
|
|
||||||
let has_overlay = overlay.with_overlay(|overlay| {
|
let has_overlay = overlay
|
||||||
overlay.as_ref().map(overlay::Element::position)
|
.with_overlay_maybe(|overlay| overlay::Element::position(overlay));
|
||||||
});
|
|
||||||
|
|
||||||
has_overlay
|
has_overlay
|
||||||
.map(|position| overlay::Element::new(position, Box::new(overlay)))
|
.map(|position| overlay::Element::new(position, Box::new(overlay)))
|
||||||
|
|
@ -238,37 +255,50 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[self_referencing]
|
#[self_referencing]
|
||||||
struct Overlay<'a, 'b, Message, Renderer, Dependency, View> {
|
struct Inner<'a, Message, Renderer>
|
||||||
cached: &'a mut Lazy<'b, Message, Renderer, Dependency, View>,
|
where
|
||||||
|
Message: 'a,
|
||||||
|
Renderer: 'a,
|
||||||
|
{
|
||||||
|
cell: Rc<RefCell<Option<Element<'static, Message, Renderer>>>>,
|
||||||
|
element: Element<'static, Message, Renderer>,
|
||||||
tree: &'a mut Tree,
|
tree: &'a mut Tree,
|
||||||
types: PhantomData<(Message, Dependency, View)>,
|
|
||||||
|
|
||||||
#[borrows(mut cached, mut tree)]
|
#[borrows(mut element, mut tree)]
|
||||||
#[covariant]
|
#[covariant]
|
||||||
overlay: Option<overlay::Element<'this, Message, Renderer>>,
|
overlay: Option<overlay::Element<'this, Message, Renderer>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, Message, Renderer, Dependency, View>
|
struct Overlay<'a, Message, Renderer>(Option<Inner<'a, Message, Renderer>>);
|
||||||
Overlay<'a, 'b, Message, Renderer, Dependency, View>
|
|
||||||
{
|
impl<'a, Message, Renderer> Drop for Overlay<'a, Message, Renderer> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let heads = self.0.take().unwrap().into_heads();
|
||||||
|
(*heads.cell.borrow_mut()) = Some(heads.element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Message, Renderer> Overlay<'a, Message, Renderer> {
|
||||||
fn with_overlay_maybe<T>(
|
fn with_overlay_maybe<T>(
|
||||||
&self,
|
&self,
|
||||||
f: impl FnOnce(&overlay::Element<'_, Message, Renderer>) -> T,
|
f: impl FnOnce(&overlay::Element<'_, Message, Renderer>) -> T,
|
||||||
) -> Option<T> {
|
) -> Option<T> {
|
||||||
self.borrow_overlay().as_ref().map(f)
|
self.0.as_ref().unwrap().borrow_overlay().as_ref().map(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_overlay_mut_maybe<T>(
|
fn with_overlay_mut_maybe<T>(
|
||||||
&mut self,
|
&mut self,
|
||||||
f: impl FnOnce(&mut overlay::Element<'_, Message, Renderer>) -> T,
|
f: impl FnOnce(&mut overlay::Element<'_, Message, Renderer>) -> T,
|
||||||
) -> Option<T> {
|
) -> Option<T> {
|
||||||
self.with_overlay_mut(|overlay| overlay.as_mut().map(f))
|
self.0
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.with_overlay_mut(|overlay| overlay.as_mut().map(f))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, Message, Renderer, Dependency, View>
|
impl<'a, Message, Renderer> overlay::Overlay<Message, Renderer>
|
||||||
overlay::Overlay<Message, Renderer>
|
for Overlay<'a, Message, Renderer>
|
||||||
for Overlay<'a, 'b, Message, Renderer, Dependency, View>
|
|
||||||
where
|
where
|
||||||
Renderer: iced_native::Renderer,
|
Renderer: iced_native::Renderer,
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue