diff options
author | 2023-03-04 05:37:11 +0100 | |
---|---|---|
committer | 2023-03-04 05:37:11 +0100 | |
commit | 3a0d34c0240f4421737a6a08761f99d6f8140d02 (patch) | |
tree | c9a4a6b8e9c1db1b8fcd05bc98e3f131d5ef4bd5 /lazy | |
parent | c54409d1711e1f615c7ea4b02c082954e340632a (diff) | |
download | iced-3a0d34c0240f4421737a6a08761f99d6f8140d02.tar.gz iced-3a0d34c0240f4421737a6a08761f99d6f8140d02.tar.bz2 iced-3a0d34c0240f4421737a6a08761f99d6f8140d02.zip |
Create `iced_widget` subcrate and re-organize the whole codebase
Diffstat (limited to 'lazy')
-rw-r--r-- | lazy/Cargo.toml | 18 | ||||
-rw-r--r-- | lazy/src/cache.rs | 13 | ||||
-rw-r--r-- | lazy/src/component.rs | 575 | ||||
-rw-r--r-- | lazy/src/lazy.rs | 396 | ||||
-rw-r--r-- | lazy/src/lib.rs | 66 | ||||
-rw-r--r-- | lazy/src/responsive.rs | 425 |
6 files changed, 0 insertions, 1493 deletions
diff --git a/lazy/Cargo.toml b/lazy/Cargo.toml deleted file mode 100644 index c739b312..00000000 --- a/lazy/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "iced_lazy" -version = "0.5.0" -authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"] -edition = "2021" -description = "Lazy widgets for Iced" -license = "MIT" -repository = "https://github.com/iced-rs/iced" -documentation = "https://docs.rs/iced_lazy" -keywords = ["gui", "ui", "graphics", "interface", "widgets"] -categories = ["gui"] - -[dependencies] -ouroboros = "0.13" - -[dependencies.iced_native] -version = "0.9" -path = "../native" diff --git a/lazy/src/cache.rs b/lazy/src/cache.rs deleted file mode 100644 index 5b4a39f6..00000000 --- a/lazy/src/cache.rs +++ /dev/null @@ -1,13 +0,0 @@ -use iced_native::overlay; -use iced_native::Element; - -use ouroboros::self_referencing; - -#[self_referencing(pub_extras)] -pub struct Cache<'a, Message: 'a, Renderer: 'a> { - pub element: Element<'a, Message, Renderer>, - - #[borrows(mut element)] - #[covariant] - overlay: Option<overlay::Element<'this, Message, Renderer>>, -} diff --git a/lazy/src/component.rs b/lazy/src/component.rs deleted file mode 100644 index b23da9f7..00000000 --- a/lazy/src/component.rs +++ /dev/null @@ -1,575 +0,0 @@ -//! Build and reuse custom widgets using The Elm Architecture. -use iced_native::event; -use iced_native::layout::{self, Layout}; -use iced_native::mouse; -use iced_native::overlay; -use iced_native::renderer; -use iced_native::widget; -use iced_native::widget::tree::{self, Tree}; -use iced_native::{ - Clipboard, Element, Length, Point, Rectangle, Shell, Size, Widget, -}; - -use ouroboros::self_referencing; -use std::cell::RefCell; -use std::marker::PhantomData; - -/// A reusable, custom widget that uses The Elm Architecture. -/// -/// A [`Component`] allows you to implement custom widgets as if they were -/// `iced` applications with encapsulated state. -/// -/// In other words, a [`Component`] allows you to turn `iced` applications into -/// custom widgets and embed them without cumbersome wiring. -/// -/// A [`Component`] produces widgets that may fire an [`Event`](Component::Event) -/// and update the internal state of the [`Component`]. -/// -/// Additionally, a [`Component`] is capable of producing a `Message` to notify -/// the parent application of any relevant interactions. -pub trait Component<Message, Renderer> { - /// The internal state of this [`Component`]. - type State: Default; - - /// The type of event this [`Component`] handles internally. - type Event; - - /// Processes an [`Event`](Component::Event) and updates the [`Component`] state accordingly. - /// - /// It can produce a `Message` for the parent application. - fn update( - &mut self, - state: &mut Self::State, - event: Self::Event, - ) -> Option<Message>; - - /// Produces the widgets of the [`Component`], which may trigger an [`Event`](Component::Event) - /// on user interaction. - fn view(&self, state: &Self::State) -> Element<'_, Self::Event, Renderer>; - - /// Update the [`Component`] state based on the provided [`Operation`](widget::Operation) - /// - /// By default, it does nothing. - fn operate( - &self, - _state: &mut Self::State, - _operation: &mut dyn widget::Operation<Message>, - ) { - } -} - -/// Turns an implementor of [`Component`] into an [`Element`] that can be -/// embedded in any application. -pub fn view<'a, C, Message, Renderer>( - component: C, -) -> Element<'a, Message, Renderer> -where - C: Component<Message, Renderer> + 'a, - C::State: 'static, - Message: 'a, - Renderer: iced_native::Renderer + 'a, -{ - Element::new(Instance { - state: RefCell::new(Some( - StateBuilder { - component: Box::new(component), - message: PhantomData, - state: PhantomData, - element_builder: |_| None, - } - .build(), - )), - }) -} - -struct Instance<'a, Message, Renderer, Event, S> { - state: RefCell<Option<State<'a, Message, Renderer, Event, S>>>, -} - -#[self_referencing] -struct State<'a, Message: 'a, Renderer: 'a, Event: 'a, S: 'a> { - component: - Box<dyn Component<Message, Renderer, Event = Event, State = S> + 'a>, - message: PhantomData<Message>, - state: PhantomData<S>, - - #[borrows(component)] - #[covariant] - element: Option<Element<'this, Event, Renderer>>, -} - -impl<'a, Message, Renderer, Event, S> Instance<'a, Message, Renderer, Event, S> -where - S: Default, -{ - fn rebuild_element(&self, state: &S) { - let heads = self.state.borrow_mut().take().unwrap().into_heads(); - - *self.state.borrow_mut() = Some( - StateBuilder { - component: heads.component, - message: PhantomData, - state: PhantomData, - element_builder: |component| Some(component.view(state)), - } - .build(), - ); - } - - fn rebuild_element_with_operation( - &self, - state: &mut S, - operation: &mut dyn widget::Operation<Message>, - ) { - let heads = self.state.borrow_mut().take().unwrap().into_heads(); - - heads.component.operate(state, operation); - - *self.state.borrow_mut() = Some( - StateBuilder { - component: heads.component, - message: PhantomData, - state: PhantomData, - element_builder: |component| Some(component.view(state)), - } - .build(), - ); - } - - fn with_element<T>( - &self, - f: impl FnOnce(&Element<'_, Event, Renderer>) -> T, - ) -> T { - self.with_element_mut(|element| f(element)) - } - - fn with_element_mut<T>( - &self, - f: impl FnOnce(&mut Element<'_, Event, Renderer>) -> T, - ) -> T { - self.state - .borrow_mut() - .as_mut() - .unwrap() - .with_element_mut(|element| f(element.as_mut().unwrap())) - } -} - -impl<'a, Message, Renderer, Event, S> Widget<Message, Renderer> - for Instance<'a, Message, Renderer, Event, S> -where - S: 'static + Default, - Renderer: iced_native::Renderer, -{ - fn tag(&self) -> tree::Tag { - struct Tag<T>(T); - tree::Tag::of::<Tag<S>>() - } - - fn state(&self) -> tree::State { - tree::State::new(S::default()) - } - - fn children(&self) -> Vec<Tree> { - self.rebuild_element(&S::default()); - self.with_element(|element| vec![Tree::new(element)]) - } - - fn diff(&self, tree: &mut Tree) { - self.rebuild_element(tree.state.downcast_ref()); - self.with_element(|element| { - tree.diff_children(std::slice::from_ref(&element)) - }) - } - - fn width(&self) -> Length { - self.with_element(|element| element.as_widget().width()) - } - - fn height(&self) -> Length { - self.with_element(|element| element.as_widget().height()) - } - - fn layout( - &self, - renderer: &Renderer, - limits: &layout::Limits, - ) -> layout::Node { - self.with_element(|element| { - element.as_widget().layout(renderer, limits) - }) - } - - fn on_event( - &mut self, - tree: &mut Tree, - event: iced_native::Event, - layout: Layout<'_>, - cursor_position: Point, - renderer: &Renderer, - clipboard: &mut dyn Clipboard, - shell: &mut Shell<'_, Message>, - ) -> event::Status { - let mut local_messages = Vec::new(); - let mut local_shell = Shell::new(&mut local_messages); - - let event_status = self.with_element_mut(|element| { - element.as_widget_mut().on_event( - &mut tree.children[0], - event, - layout, - cursor_position, - renderer, - clipboard, - &mut local_shell, - ) - }); - - local_shell.revalidate_layout(|| shell.invalidate_layout()); - - if let Some(redraw_request) = local_shell.redraw_request() { - shell.request_redraw(redraw_request); - } - - if !local_messages.is_empty() { - let mut heads = self.state.take().unwrap().into_heads(); - - for message in local_messages.into_iter().filter_map(|message| { - heads - .component - .update(tree.state.downcast_mut::<S>(), message) - }) { - shell.publish(message); - } - - self.state = RefCell::new(Some( - StateBuilder { - component: heads.component, - message: PhantomData, - state: PhantomData, - element_builder: |state| { - Some(state.view(tree.state.downcast_ref::<S>())) - }, - } - .build(), - )); - - self.with_element(|element| { - tree.diff_children(std::slice::from_ref(&element)) - }); - - shell.invalidate_layout(); - } - - event_status - } - - fn operate( - &self, - tree: &mut Tree, - layout: Layout<'_>, - renderer: &Renderer, - operation: &mut dyn widget::Operation<Message>, - ) { - self.rebuild_element_with_operation( - tree.state.downcast_mut(), - operation, - ); - - struct MapOperation<'a, B> { - operation: &'a mut dyn widget::Operation<B>, - } - - impl<'a, T, B> widget::Operation<T> for MapOperation<'a, B> { - fn container( - &mut self, - id: Option<&widget::Id>, - operate_on_children: &mut dyn FnMut( - &mut dyn widget::Operation<T>, - ), - ) { - self.operation.container(id, &mut |operation| { - operate_on_children(&mut MapOperation { operation }); - }); - } - - fn focusable( - &mut self, - state: &mut dyn widget::operation::Focusable, - id: Option<&widget::Id>, - ) { - self.operation.focusable(state, id); - } - - fn text_input( - &mut self, - state: &mut dyn widget::operation::TextInput, - id: Option<&widget::Id>, - ) { - self.operation.text_input(state, id); - } - } - - self.with_element(|element| { - tree.diff_children(std::slice::from_ref(&element)); - - element.as_widget().operate( - &mut tree.children[0], - layout, - renderer, - &mut MapOperation { operation }, - ); - }); - } - - fn draw( - &self, - tree: &Tree, - renderer: &mut Renderer, - theme: &Renderer::Theme, - style: &renderer::Style, - layout: Layout<'_>, - cursor_position: Point, - viewport: &Rectangle, - ) { - self.with_element(|element| { - element.as_widget().draw( - &tree.children[0], - renderer, - theme, - style, - layout, - cursor_position, - viewport, - ); - }); - } - - fn mouse_interaction( - &self, - tree: &Tree, - layout: Layout<'_>, - cursor_position: Point, - viewport: &Rectangle, - renderer: &Renderer, - ) -> mouse::Interaction { - self.with_element(|element| { - element.as_widget().mouse_interaction( - &tree.children[0], - layout, - cursor_position, - viewport, - renderer, - ) - }) - } - - fn overlay<'b>( - &'b mut self, - tree: &'b mut Tree, - layout: Layout<'_>, - renderer: &Renderer, - ) -> Option<overlay::Element<'b, Message, Renderer>> { - let overlay = OverlayBuilder { - instance: self, - tree, - types: PhantomData, - overlay_builder: |instance, tree| { - instance.state.get_mut().as_mut().unwrap().with_element_mut( - move |element| { - element.as_mut().unwrap().as_widget_mut().overlay( - &mut tree.children[0], - layout, - renderer, - ) - }, - ) - }, - } - .build(); - - let has_overlay = overlay.with_overlay(|overlay| { - overlay.as_ref().map(overlay::Element::position) - }); - - has_overlay.map(|position| { - overlay::Element::new( - position, - Box::new(OverlayInstance { - overlay: Some(overlay), - }), - ) - }) - } -} - -#[self_referencing] -struct Overlay<'a, 'b, Message, Renderer, Event, S> { - instance: &'a mut Instance<'b, Message, Renderer, Event, S>, - tree: &'a mut Tree, - types: PhantomData<(Message, Event, S)>, - - #[borrows(mut instance, mut tree)] - #[covariant] - overlay: Option<overlay::Element<'this, Event, Renderer>>, -} - -struct OverlayInstance<'a, 'b, Message, Renderer, Event, S> { - overlay: Option<Overlay<'a, 'b, Message, Renderer, Event, S>>, -} - -impl<'a, 'b, Message, Renderer, Event, S> - OverlayInstance<'a, 'b, Message, Renderer, Event, S> -{ - fn with_overlay_maybe<T>( - &self, - f: impl FnOnce(&overlay::Element<'_, Event, Renderer>) -> T, - ) -> Option<T> { - self.overlay - .as_ref() - .unwrap() - .borrow_overlay() - .as_ref() - .map(f) - } - - fn with_overlay_mut_maybe<T>( - &mut self, - f: impl FnOnce(&mut overlay::Element<'_, Event, Renderer>) -> T, - ) -> Option<T> { - self.overlay - .as_mut() - .unwrap() - .with_overlay_mut(|overlay| overlay.as_mut().map(f)) - } -} - -impl<'a, 'b, Message, Renderer, Event, S> overlay::Overlay<Message, Renderer> - for OverlayInstance<'a, 'b, Message, Renderer, Event, S> -where - Renderer: iced_native::Renderer, - S: 'static + Default, -{ - fn layout( - &self, - renderer: &Renderer, - bounds: Size, - position: Point, - ) -> layout::Node { - self.with_overlay_maybe(|overlay| { - let translation = position - overlay.position(); - - overlay.layout(renderer, bounds, translation) - }) - .unwrap_or_default() - } - - fn draw( - &self, - renderer: &mut Renderer, - theme: &Renderer::Theme, - style: &renderer::Style, - layout: Layout<'_>, - cursor_position: Point, - ) { - let _ = self.with_overlay_maybe(|overlay| { - overlay.draw(renderer, theme, style, layout, cursor_position); - }); - } - - fn mouse_interaction( - &self, - layout: Layout<'_>, - cursor_position: Point, - viewport: &Rectangle, - renderer: &Renderer, - ) -> mouse::Interaction { - self.with_overlay_maybe(|overlay| { - overlay.mouse_interaction( - layout, - cursor_position, - viewport, - renderer, - ) - }) - .unwrap_or_default() - } - - fn on_event( - &mut self, - event: iced_native::Event, - layout: Layout<'_>, - cursor_position: Point, - renderer: &Renderer, - clipboard: &mut dyn Clipboard, - shell: &mut Shell<'_, Message>, - ) -> iced_native::event::Status { - let mut local_messages = Vec::new(); - let mut local_shell = Shell::new(&mut local_messages); - - let event_status = self - .with_overlay_mut_maybe(|overlay| { - overlay.on_event( - event, - layout, - cursor_position, - renderer, - clipboard, - &mut local_shell, - ) - }) - .unwrap_or(iced_native::event::Status::Ignored); - - local_shell.revalidate_layout(|| shell.invalidate_layout()); - - if !local_messages.is_empty() { - let overlay = self.overlay.take().unwrap().into_heads(); - let mut heads = overlay.instance.state.take().unwrap().into_heads(); - - for message in local_messages.into_iter().filter_map(|message| { - heads - .component - .update(overlay.tree.state.downcast_mut::<S>(), message) - }) { - shell.publish(message); - } - - *overlay.instance.state.borrow_mut() = Some( - StateBuilder { - component: heads.component, - message: PhantomData, - state: PhantomData, - element_builder: |state| { - Some(state.view(overlay.tree.state.downcast_ref::<S>())) - }, - } - .build(), - ); - - overlay.instance.with_element(|element| { - overlay.tree.diff_children(std::slice::from_ref(&element)) - }); - - self.overlay = Some( - OverlayBuilder { - instance: overlay.instance, - tree: overlay.tree, - types: PhantomData, - overlay_builder: |_, _| None, - } - .build(), - ); - - shell.invalidate_layout(); - } - - event_status - } - - fn is_over(&self, layout: Layout<'_>, cursor_position: Point) -> bool { - self.with_overlay_maybe(|overlay| { - overlay.is_over(layout, cursor_position) - }) - .unwrap_or_default() - } -} diff --git a/lazy/src/lazy.rs b/lazy/src/lazy.rs deleted file mode 100644 index 5e909a49..00000000 --- a/lazy/src/lazy.rs +++ /dev/null @@ -1,396 +0,0 @@ -use iced_native::event; -use iced_native::layout::{self, Layout}; -use iced_native::mouse; -use iced_native::overlay; -use iced_native::renderer; -use iced_native::widget::tree::{self, Tree}; -use iced_native::widget::{self, Widget}; -use iced_native::Element; -use iced_native::{Clipboard, Hasher, Length, Point, Rectangle, Shell, Size}; - -use ouroboros::self_referencing; -use std::cell::RefCell; -use std::hash::{Hash, Hasher as H}; -use std::rc::Rc; - -#[allow(missing_debug_implementations)] -pub struct Lazy<'a, Message, Renderer, Dependency, View> { - dependency: Dependency, - view: Box<dyn Fn(&Dependency) -> View + 'a>, - element: RefCell< - Option<Rc<RefCell<Option<Element<'static, Message, Renderer>>>>>, - >, -} - -impl<'a, Message, Renderer, Dependency, View> - Lazy<'a, Message, Renderer, Dependency, View> -where - Dependency: Hash + 'a, - View: Into<Element<'static, Message, Renderer>>, -{ - pub fn new( - dependency: Dependency, - view: impl Fn(&Dependency) -> View + 'a, - ) -> Self { - Self { - dependency, - view: Box::new(view), - element: RefCell::new(None), - } - } - - fn with_element<T>( - &self, - f: impl FnOnce(&Element<Message, Renderer>) -> T, - ) -> T { - f(self - .element - .borrow() - .as_ref() - .unwrap() - .borrow() - .as_ref() - .unwrap()) - } - - fn with_element_mut<T>( - &self, - f: impl FnOnce(&mut Element<Message, Renderer>) -> T, - ) -> T { - f(self - .element - .borrow() - .as_ref() - .unwrap() - .borrow_mut() - .as_mut() - .unwrap()) - } -} - -struct Internal<Message, Renderer> { - element: Rc<RefCell<Option<Element<'static, Message, Renderer>>>>, - hash: u64, -} - -impl<'a, Message, Renderer, Dependency, View> Widget<Message, Renderer> - for Lazy<'a, Message, Renderer, Dependency, View> -where - View: Into<Element<'static, Message, Renderer>> + 'static, - Dependency: Hash + 'a, - Message: 'static, - Renderer: iced_native::Renderer + 'static, -{ - fn tag(&self) -> tree::Tag { - struct Tag<T>(T); - tree::Tag::of::<Tag<View>>() - } - - fn state(&self) -> tree::State { - let mut hasher = Hasher::default(); - self.dependency.hash(&mut hasher); - let hash = hasher.finish(); - - let element = - Rc::new(RefCell::new(Some((self.view)(&self.dependency).into()))); - - (*self.element.borrow_mut()) = Some(element.clone()); - - tree::State::new(Internal { element, hash }) - } - - fn children(&self) -> Vec<Tree> { - self.with_element(|element| vec![Tree::new(element.as_widget())]) - } - - fn diff(&self, tree: &mut Tree) { - let current = tree.state.downcast_mut::<Internal<Message, Renderer>>(); - - let mut hasher = Hasher::default(); - self.dependency.hash(&mut hasher); - let new_hash = hasher.finish(); - - if current.hash != new_hash { - current.hash = new_hash; - - let element = (self.view)(&self.dependency).into(); - current.element = Rc::new(RefCell::new(Some(element))); - - (*self.element.borrow_mut()) = Some(current.element.clone()); - self.with_element(|element| { - tree.diff_children(std::slice::from_ref(&element.as_widget())) - }); - } else { - (*self.element.borrow_mut()) = Some(current.element.clone()); - } - } - - fn width(&self) -> Length { - self.with_element(|element| element.as_widget().width()) - } - - fn height(&self) -> Length { - self.with_element(|element| element.as_widget().height()) - } - - fn layout( - &self, - renderer: &Renderer, - limits: &layout::Limits, - ) -> layout::Node { - self.with_element(|element| { - element.as_widget().layout(renderer, limits) - }) - } - - fn operate( - &self, - tree: &mut Tree, - layout: Layout<'_>, - renderer: &Renderer, - operation: &mut dyn widget::Operation<Message>, - ) { - self.with_element(|element| { - element.as_widget().operate( - &mut tree.children[0], - layout, - renderer, - operation, - ); - }); - } - - fn on_event( - &mut self, - tree: &mut Tree, - event: iced_native::Event, - layout: Layout<'_>, - cursor_position: Point, - renderer: &Renderer, - clipboard: &mut dyn Clipboard, - shell: &mut Shell<'_, Message>, - ) -> event::Status { - self.with_element_mut(|element| { - element.as_widget_mut().on_event( - &mut tree.children[0], - event, - layout, - cursor_position, - renderer, - clipboard, - shell, - ) - }) - } - - fn mouse_interaction( - &self, - tree: &Tree, - layout: Layout<'_>, - cursor_position: Point, - viewport: &Rectangle, - renderer: &Renderer, - ) -> mouse::Interaction { - self.with_element(|element| { - element.as_widget().mouse_interaction( - &tree.children[0], - layout, - cursor_position, - viewport, - renderer, - ) - }) - } - - fn draw( - &self, - tree: &Tree, - renderer: &mut Renderer, - theme: &Renderer::Theme, - style: &renderer::Style, - layout: Layout<'_>, - cursor_position: Point, - viewport: &Rectangle, - ) { - self.with_element(|element| { - element.as_widget().draw( - &tree.children[0], - renderer, - theme, - style, - layout, - cursor_position, - viewport, - ) - }) - } - - fn overlay<'b>( - &'b mut self, - tree: &'b mut Tree, - layout: Layout<'_>, - renderer: &Renderer, - ) -> Option<overlay::Element<'_, Message, Renderer>> { - let overlay = Overlay(Some( - InnerBuilder { - cell: self.element.borrow().as_ref().unwrap().clone(), - element: self - .element - .borrow() - .as_ref() - .unwrap() - .borrow_mut() - .take() - .unwrap(), - tree: &mut tree.children[0], - overlay_builder: |element, tree| { - element.as_widget_mut().overlay(tree, layout, renderer) - }, - } - .build(), - )); - - let has_overlay = overlay - .with_overlay_maybe(|overlay| overlay::Element::position(overlay)); - - has_overlay - .map(|position| overlay::Element::new(position, Box::new(overlay))) - } -} - -#[self_referencing] -struct Inner<'a, Message, Renderer> -where - Message: 'a, - Renderer: 'a, -{ - cell: Rc<RefCell<Option<Element<'static, Message, Renderer>>>>, - element: Element<'static, Message, Renderer>, - tree: &'a mut Tree, - - #[borrows(mut element, mut tree)] - #[covariant] - overlay: Option<overlay::Element<'this, Message, Renderer>>, -} - -struct Overlay<'a, Message, Renderer>(Option<Inner<'a, Message, Renderer>>); - -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>( - &self, - f: impl FnOnce(&overlay::Element<'_, Message, Renderer>) -> T, - ) -> Option<T> { - self.0.as_ref().unwrap().borrow_overlay().as_ref().map(f) - } - - fn with_overlay_mut_maybe<T>( - &mut self, - f: impl FnOnce(&mut overlay::Element<'_, Message, Renderer>) -> T, - ) -> Option<T> { - self.0 - .as_mut() - .unwrap() - .with_overlay_mut(|overlay| overlay.as_mut().map(f)) - } -} - -impl<'a, Message, Renderer> overlay::Overlay<Message, Renderer> - for Overlay<'a, Message, Renderer> -where - Renderer: iced_native::Renderer, -{ - fn layout( - &self, - renderer: &Renderer, - bounds: Size, - position: Point, - ) -> layout::Node { - self.with_overlay_maybe(|overlay| { - let translation = position - overlay.position(); - - overlay.layout(renderer, bounds, translation) - }) - .unwrap_or_default() - } - - fn draw( - &self, - renderer: &mut Renderer, - theme: &Renderer::Theme, - style: &renderer::Style, - layout: Layout<'_>, - cursor_position: Point, - ) { - let _ = self.with_overlay_maybe(|overlay| { - overlay.draw(renderer, theme, style, layout, cursor_position); - }); - } - - fn mouse_interaction( - &self, - layout: Layout<'_>, - cursor_position: Point, - viewport: &Rectangle, - renderer: &Renderer, - ) -> mouse::Interaction { - self.with_overlay_maybe(|overlay| { - overlay.mouse_interaction( - layout, - cursor_position, - viewport, - renderer, - ) - }) - .unwrap_or_default() - } - - fn on_event( - &mut self, - event: iced_native::Event, - layout: Layout<'_>, - cursor_position: Point, - renderer: &Renderer, - clipboard: &mut dyn Clipboard, - shell: &mut Shell<'_, Message>, - ) -> event::Status { - self.with_overlay_mut_maybe(|overlay| { - overlay.on_event( - event, - layout, - cursor_position, - renderer, - clipboard, - shell, - ) - }) - .unwrap_or(iced_native::event::Status::Ignored) - } - - fn is_over(&self, layout: Layout<'_>, cursor_position: Point) -> bool { - self.with_overlay_maybe(|overlay| { - overlay.is_over(layout, cursor_position) - }) - .unwrap_or_default() - } -} - -impl<'a, Message, Renderer, Dependency, View> - From<Lazy<'a, Message, Renderer, Dependency, View>> - for Element<'a, Message, Renderer> -where - View: Into<Element<'static, Message, Renderer>> + 'static, - Renderer: iced_native::Renderer + 'static, - Message: 'static, - Dependency: Hash + 'a, -{ - fn from(lazy: Lazy<'a, Message, Renderer, Dependency, View>) -> Self { - Self::new(lazy) - } -} diff --git a/lazy/src/lib.rs b/lazy/src/lib.rs deleted file mode 100644 index 41a28773..00000000 --- a/lazy/src/lib.rs +++ /dev/null @@ -1,66 +0,0 @@ -#![doc( - html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg" -)] -#![deny( - missing_debug_implementations, - unused_results, - clippy::extra_unused_lifetimes, - clippy::from_over_into, - clippy::needless_borrow, - clippy::new_without_default, - clippy::useless_conversion -)] -#![forbid(unsafe_code)] -#![allow( - clippy::await_holding_refcell_ref, - clippy::inherent_to_string, - clippy::type_complexity -)] -#![cfg_attr(docsrs, feature(doc_cfg))] -mod lazy; - -pub mod component; -pub mod responsive; - -pub use component::Component; -pub use lazy::Lazy; -pub use responsive::Responsive; - -mod cache; - -use iced_native::{Element, Size}; -use std::hash::Hash; - -pub fn lazy<'a, Message, Renderer, Dependency, View>( - dependency: Dependency, - view: impl Fn(&Dependency) -> View + 'a, -) -> Lazy<'a, Message, Renderer, Dependency, View> -where - Dependency: Hash + 'a, - View: Into<Element<'static, Message, Renderer>>, -{ - Lazy::new(dependency, view) -} - -/// Turns an implementor of [`Component`] into an [`Element`] that can be -/// embedded in any application. -pub fn component<'a, C, Message, Renderer>( - component: C, -) -> Element<'a, Message, Renderer> -where - C: Component<Message, Renderer> + 'a, - C::State: 'static, - Message: 'a, - Renderer: iced_native::Renderer + 'a, -{ - component::view(component) -} - -pub fn responsive<'a, Message, Renderer>( - f: impl Fn(Size) -> Element<'a, Message, Renderer> + 'a, -) -> Responsive<'a, Message, Renderer> -where - Renderer: iced_native::Renderer, -{ - Responsive::new(f) -} diff --git a/lazy/src/responsive.rs b/lazy/src/responsive.rs deleted file mode 100644 index 57c07de1..00000000 --- a/lazy/src/responsive.rs +++ /dev/null @@ -1,425 +0,0 @@ -use iced_native::event; -use iced_native::layout::{self, Layout}; -use iced_native::mouse; -use iced_native::overlay; -use iced_native::renderer; -use iced_native::widget::tree::{self, Tree}; -use iced_native::widget::{self, horizontal_space}; -use iced_native::{ - Clipboard, Element, Length, Point, Rectangle, Shell, Size, Widget, -}; - -use ouroboros::self_referencing; -use std::cell::{RefCell, RefMut}; -use std::marker::PhantomData; -use std::ops::Deref; - -/// A widget that is aware of its dimensions. -/// -/// A [`Responsive`] widget will always try to fill all the available space of -/// its parent. -#[allow(missing_debug_implementations)] -pub struct Responsive<'a, Message, Renderer> { - view: Box<dyn Fn(Size) -> Element<'a, Message, Renderer> + 'a>, - content: RefCell<Content<'a, Message, Renderer>>, -} - -impl<'a, Message, Renderer> Responsive<'a, Message, Renderer> -where - Renderer: iced_native::Renderer, -{ - /// Creates a new [`Responsive`] widget with a closure that produces its - /// contents. - /// - /// The `view` closure will be provided with the current [`Size`] of - /// the [`Responsive`] widget and, therefore, can be used to build the - /// contents of the widget in a responsive way. - pub fn new( - view: impl Fn(Size) -> Element<'a, Message, Renderer> + 'a, - ) -> Self { - Self { - view: Box::new(view), - content: RefCell::new(Content { - size: Size::ZERO, - layout: layout::Node::new(Size::ZERO), - element: Element::new(horizontal_space(0)), - }), - } - } -} - -struct Content<'a, Message, Renderer> { - size: Size, - layout: layout::Node, - element: Element<'a, Message, Renderer>, -} - -impl<'a, Message, Renderer> Content<'a, Message, Renderer> -where - Renderer: iced_native::Renderer, -{ - fn update( - &mut self, - tree: &mut Tree, - renderer: &Renderer, - new_size: Size, - view: &dyn Fn(Size) -> Element<'a, Message, Renderer>, - ) { - if self.size == new_size { - return; - } - - self.element = view(new_size); - self.size = new_size; - - tree.diff(&self.element); - - self.layout = self - .element - .as_widget() - .layout(renderer, &layout::Limits::new(Size::ZERO, self.size)); - } - - fn resolve<R, T>( - &mut self, - tree: &mut Tree, - renderer: R, - layout: Layout<'_>, - view: &dyn Fn(Size) -> Element<'a, Message, Renderer>, - f: impl FnOnce( - &mut Tree, - R, - Layout<'_>, - &mut Element<'a, Message, Renderer>, - ) -> T, - ) -> T - where - R: Deref<Target = Renderer>, - { - self.update(tree, renderer.deref(), layout.bounds().size(), view); - - let content_layout = Layout::with_offset( - layout.position() - Point::ORIGIN, - &self.layout, - ); - - f(tree, renderer, content_layout, &mut self.element) - } -} - -struct State { - tree: RefCell<Tree>, -} - -impl<'a, Message, Renderer> Widget<Message, Renderer> - for Responsive<'a, Message, Renderer> -where - Renderer: iced_native::Renderer, -{ - fn tag(&self) -> tree::Tag { - tree::Tag::of::<State>() - } - - fn state(&self) -> tree::State { - tree::State::new(State { - tree: RefCell::new(Tree::empty()), - }) - } - - fn width(&self) -> Length { - Length::Fill - } - - fn height(&self) -> Length { - Length::Fill - } - - fn layout( - &self, - _renderer: &Renderer, - limits: &layout::Limits, - ) -> layout::Node { - layout::Node::new(limits.max()) - } - - fn operate( - &self, - tree: &mut Tree, - layout: Layout<'_>, - renderer: &Renderer, - operation: &mut dyn widget::Operation<Message>, - ) { - let state = tree.state.downcast_mut::<State>(); - let mut content = self.content.borrow_mut(); - - content.resolve( - &mut state.tree.borrow_mut(), - renderer, - layout, - &self.view, - |tree, renderer, layout, element| { - element - .as_widget() - .operate(tree, layout, renderer, operation); - }, - ); - } - - fn on_event( - &mut self, - tree: &mut Tree, - event: iced_native::Event, - layout: Layout<'_>, - cursor_position: Point, - renderer: &Renderer, - clipboard: &mut dyn Clipboard, - shell: &mut Shell<'_, Message>, - ) -> event::Status { - let state = tree.state.downcast_mut::<State>(); - let mut content = self.content.borrow_mut(); - - content.resolve( - &mut state.tree.borrow_mut(), - renderer, - layout, - &self.view, - |tree, renderer, layout, element| { - element.as_widget_mut().on_event( - tree, - event, - layout, - cursor_position, - renderer, - clipboard, - shell, - ) - }, - ) - } - - fn draw( - &self, - tree: &Tree, - renderer: &mut Renderer, - theme: &Renderer::Theme, - style: &renderer::Style, - layout: Layout<'_>, - cursor_position: Point, - viewport: &Rectangle, - ) { - let state = tree.state.downcast_ref::<State>(); - let mut content = self.content.borrow_mut(); - - content.resolve( - &mut state.tree.borrow_mut(), - renderer, - layout, - &self.view, - |tree, renderer, layout, element| { - element.as_widget().draw( - tree, - renderer, - theme, - style, - layout, - cursor_position, - viewport, - ) - }, - ) - } - - fn mouse_interaction( - &self, - tree: &Tree, - layout: Layout<'_>, - cursor_position: Point, - viewport: &Rectangle, - renderer: &Renderer, - ) -> mouse::Interaction { - let state = tree.state.downcast_ref::<State>(); - let mut content = self.content.borrow_mut(); - - content.resolve( - &mut state.tree.borrow_mut(), - renderer, - layout, - &self.view, - |tree, renderer, layout, element| { - element.as_widget().mouse_interaction( - tree, - layout, - cursor_position, - viewport, - renderer, - ) - }, - ) - } - - fn overlay<'b>( - &'b mut self, - tree: &'b mut Tree, - layout: Layout<'_>, - renderer: &Renderer, - ) -> Option<overlay::Element<'b, Message, Renderer>> { - use std::ops::DerefMut; - - let state = tree.state.downcast_ref::<State>(); - - let overlay = OverlayBuilder { - content: self.content.borrow_mut(), - tree: state.tree.borrow_mut(), - types: PhantomData, - overlay_builder: |content: &mut RefMut<Content<_, _>>, tree| { - content.update( - tree, - renderer, - layout.bounds().size(), - &self.view, - ); - - let Content { - element, - layout: content_layout, - .. - } = content.deref_mut(); - - let content_layout = Layout::with_offset( - layout.bounds().position() - Point::ORIGIN, - content_layout, - ); - - element - .as_widget_mut() - .overlay(tree, content_layout, renderer) - }, - } - .build(); - - let has_overlay = overlay.with_overlay(|overlay| { - overlay.as_ref().map(overlay::Element::position) - }); - - has_overlay - .map(|position| overlay::Element::new(position, Box::new(overlay))) - } -} - -impl<'a, Message, Renderer> From<Responsive<'a, Message, Renderer>> - for Element<'a, Message, Renderer> -where - Renderer: iced_native::Renderer + 'a, - Message: 'a, -{ - fn from(responsive: Responsive<'a, Message, Renderer>) -> Self { - Self::new(responsive) - } -} - -#[self_referencing] -struct Overlay<'a, 'b, Message, Renderer> { - content: RefMut<'a, Content<'b, Message, Renderer>>, - tree: RefMut<'a, Tree>, - types: PhantomData<Message>, - - #[borrows(mut content, mut tree)] - #[covariant] - overlay: Option<overlay::Element<'this, Message, Renderer>>, -} - -impl<'a, 'b, Message, Renderer> Overlay<'a, 'b, Message, Renderer> { - fn with_overlay_maybe<T>( - &self, - f: impl FnOnce(&overlay::Element<'_, Message, Renderer>) -> T, - ) -> Option<T> { - self.borrow_overlay().as_ref().map(f) - } - - fn with_overlay_mut_maybe<T>( - &mut self, - f: impl FnOnce(&mut overlay::Element<'_, Message, Renderer>) -> T, - ) -> Option<T> { - self.with_overlay_mut(|overlay| overlay.as_mut().map(f)) - } -} - -impl<'a, 'b, Message, Renderer> overlay::Overlay<Message, Renderer> - for Overlay<'a, 'b, Message, Renderer> -where - Renderer: iced_native::Renderer, -{ - fn layout( - &self, - renderer: &Renderer, - bounds: Size, - position: Point, - ) -> layout::Node { - self.with_overlay_maybe(|overlay| { - let translation = position - overlay.position(); - - overlay.layout(renderer, bounds, translation) - }) - .unwrap_or_default() - } - - fn draw( - &self, - renderer: &mut Renderer, - theme: &Renderer::Theme, - style: &renderer::Style, - layout: Layout<'_>, - cursor_position: Point, - ) { - let _ = self.with_overlay_maybe(|overlay| { - overlay.draw(renderer, theme, style, layout, cursor_position); - }); - } - - fn mouse_interaction( - &self, - layout: Layout<'_>, - cursor_position: Point, - viewport: &Rectangle, - renderer: &Renderer, - ) -> mouse::Interaction { - self.with_overlay_maybe(|overlay| { - overlay.mouse_interaction( - layout, - cursor_position, - viewport, - renderer, - ) - }) - .unwrap_or_default() - } - - fn on_event( - &mut self, - event: iced_native::Event, - layout: Layout<'_>, - cursor_position: Point, - renderer: &Renderer, - clipboard: &mut dyn Clipboard, - shell: &mut Shell<'_, Message>, - ) -> event::Status { - self.with_overlay_mut_maybe(|overlay| { - overlay.on_event( - event, - layout, - cursor_position, - renderer, - clipboard, - shell, - ) - }) - .unwrap_or(iced_native::event::Status::Ignored) - } - - fn is_over(&self, layout: Layout<'_>, cursor_position: Point) -> bool { - self.with_overlay_maybe(|overlay| { - overlay.is_over(layout, cursor_position) - }) - .unwrap_or_default() - } -} |