diff options
Diffstat (limited to 'pure/src/element.rs')
-rw-r--r-- | pure/src/element.rs | 346 |
1 files changed, 0 insertions, 346 deletions
diff --git a/pure/src/element.rs b/pure/src/element.rs deleted file mode 100644 index 35c68716..00000000 --- a/pure/src/element.rs +++ /dev/null @@ -1,346 +0,0 @@ -use crate::overlay; -use crate::widget::tree::{self, Tree}; -use crate::widget::Widget; - -use iced_native::event::{self, Event}; -use iced_native::layout::{self, Layout}; -use iced_native::mouse; -use iced_native::renderer; -use iced_native::{Clipboard, Length, Point, Rectangle, Shell}; - -use std::borrow::Borrow; - -/// A generic [`Widget`]. -/// -/// It is useful to build composable user interfaces that do not leak -/// implementation details in their __view logic__. -/// -/// If you have a [built-in widget], you should be able to use `Into<Element>` -/// to turn it into an [`Element`]. -/// -/// [built-in widget]: crate::widget -pub struct Element<'a, Message, Renderer> { - widget: Box<dyn Widget<Message, Renderer> + 'a>, -} - -impl<'a, Message, Renderer> Element<'a, Message, Renderer> { - /// Creates a new [`Element`] containing the given [`Widget`]. - pub fn new(widget: impl Widget<Message, Renderer> + 'a) -> Self - where - Renderer: iced_native::Renderer, - { - Self { - widget: Box::new(widget), - } - } - - /// Returns a reference to the [`Widget`] of the [`Element`], - pub fn as_widget(&self) -> &dyn Widget<Message, Renderer> { - self.widget.as_ref() - } - - /// Returns a mutable reference to the [`Widget`] of the [`Element`], - pub fn as_widget_mut(&mut self) -> &mut dyn Widget<Message, Renderer> { - self.widget.as_mut() - } - - /// Applies a transformation to the produced message of the [`Element`]. - /// - /// This method is useful when you want to decouple different parts of your - /// UI and make them __composable__. - /// - /// # Example - /// Imagine we want to use [our counter](index.html#usage). But instead of - /// showing a single counter, we want to display many of them. We can reuse - /// the `Counter` type as it is! - /// - /// We use composition to model the __state__ of our new application: - /// - /// ``` - /// # mod counter { - /// # pub struct Counter; - /// # } - /// use counter::Counter; - /// - /// struct ManyCounters { - /// counters: Vec<Counter>, - /// } - /// ``` - /// - /// We can store the state of multiple counters now. However, the - /// __messages__ we implemented before describe the user interactions - /// of a __single__ counter. Right now, we need to also identify which - /// counter is receiving user interactions. Can we use composition again? - /// Yes. - /// - /// ``` - /// # mod counter { - /// # #[derive(Debug, Clone, Copy)] - /// # pub enum Message {} - /// # } - /// #[derive(Debug, Clone, Copy)] - /// pub enum Message { - /// Counter(usize, counter::Message) - /// } - /// ``` - /// - /// We compose the previous __messages__ with the index of the counter - /// producing them. Let's implement our __view logic__ now: - /// - /// ``` - /// # mod counter { - /// # type Text = iced_pure::widget::Text<iced_native::renderer::Null>; - /// # - /// # #[derive(Debug, Clone, Copy)] - /// # pub enum Message {} - /// # pub struct Counter; - /// # - /// # impl Counter { - /// # pub fn view(&mut self) -> Text { - /// # Text::new("") - /// # } - /// # } - /// # } - /// # - /// # mod iced_wgpu { - /// # pub use iced_native::renderer::Null as Renderer; - /// # } - /// # - /// # use counter::Counter; - /// # - /// # struct ManyCounters { - /// # counters: Vec<Counter>, - /// # } - /// # - /// # #[derive(Debug, Clone, Copy)] - /// # pub enum Message { - /// # Counter(usize, counter::Message) - /// # } - /// use iced_pure::Element; - /// use iced_pure::widget::Row; - /// use iced_wgpu::Renderer; - /// - /// impl ManyCounters { - /// pub fn view(&mut self) -> Row<Message, Renderer> { - /// // We can quickly populate a `Row` by folding over our counters - /// self.counters.iter_mut().enumerate().fold( - /// Row::new().spacing(20), - /// |row, (index, counter)| { - /// // We display the counter - /// let element: Element<counter::Message, Renderer> = - /// counter.view().into(); - /// - /// row.push( - /// // Here we turn our `Element<counter::Message>` into - /// // an `Element<Message>` by combining the `index` and the - /// // message of the `element`. - /// element.map(move |message| Message::Counter(index, message)) - /// ) - /// } - /// ) - /// } - /// } - /// ``` - /// - /// Finally, our __update logic__ is pretty straightforward: simple - /// delegation. - /// - /// ``` - /// # mod counter { - /// # #[derive(Debug, Clone, Copy)] - /// # pub enum Message {} - /// # pub struct Counter; - /// # - /// # impl Counter { - /// # pub fn update(&mut self, _message: Message) {} - /// # } - /// # } - /// # - /// # use counter::Counter; - /// # - /// # struct ManyCounters { - /// # counters: Vec<Counter>, - /// # } - /// # - /// # #[derive(Debug, Clone, Copy)] - /// # pub enum Message { - /// # Counter(usize, counter::Message) - /// # } - /// impl ManyCounters { - /// pub fn update(&mut self, message: Message) { - /// match message { - /// Message::Counter(index, counter_msg) => { - /// if let Some(counter) = self.counters.get_mut(index) { - /// counter.update(counter_msg); - /// } - /// } - /// } - /// } - /// } - /// ``` - pub fn map<B>( - self, - f: impl Fn(Message) -> B + 'a, - ) -> Element<'a, B, Renderer> - where - Message: 'a, - Renderer: iced_native::Renderer + 'a, - B: 'a, - { - Element::new(Map::new(self.widget, f)) - } -} - -struct Map<'a, A, B, Renderer> { - widget: Box<dyn Widget<A, Renderer> + 'a>, - mapper: Box<dyn Fn(A) -> B + 'a>, -} - -impl<'a, A, B, Renderer> Map<'a, A, B, Renderer> { - pub fn new<F>( - widget: Box<dyn Widget<A, Renderer> + 'a>, - mapper: F, - ) -> Map<'a, A, B, Renderer> - where - F: 'a + Fn(A) -> B, - { - Map { - widget, - mapper: Box::new(mapper), - } - } -} - -impl<'a, A, B, Renderer> Widget<B, Renderer> for Map<'a, A, B, Renderer> -where - Renderer: iced_native::Renderer + 'a, - A: 'a, - B: 'a, -{ - fn tag(&self) -> tree::Tag { - self.widget.tag() - } - - fn state(&self) -> tree::State { - self.widget.state() - } - - fn children(&self) -> Vec<Tree> { - self.widget.children() - } - - fn diff(&self, tree: &mut Tree) { - self.widget.diff(tree) - } - - fn width(&self) -> Length { - self.widget.width() - } - - fn height(&self) -> Length { - self.widget.height() - } - - fn layout( - &self, - renderer: &Renderer, - limits: &layout::Limits, - ) -> layout::Node { - self.widget.layout(renderer, limits) - } - - fn on_event( - &mut self, - tree: &mut Tree, - event: Event, - layout: Layout<'_>, - cursor_position: Point, - renderer: &Renderer, - clipboard: &mut dyn Clipboard, - shell: &mut Shell<'_, B>, - ) -> event::Status { - let mut local_messages = Vec::new(); - let mut local_shell = Shell::new(&mut local_messages); - - let status = self.widget.on_event( - tree, - event, - layout, - cursor_position, - renderer, - clipboard, - &mut local_shell, - ); - - shell.merge(local_shell, &self.mapper); - - status - } - - fn draw( - &self, - tree: &Tree, - renderer: &mut Renderer, - theme: &Renderer::Theme, - style: &renderer::Style, - layout: Layout<'_>, - cursor_position: Point, - viewport: &Rectangle, - ) { - self.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 { - self.widget.mouse_interaction( - tree, - layout, - cursor_position, - viewport, - renderer, - ) - } - - fn overlay<'b>( - &'b self, - tree: &'b mut Tree, - layout: Layout<'_>, - renderer: &Renderer, - ) -> Option<overlay::Element<'b, B, Renderer>> { - let mapper = &self.mapper; - - self.widget - .overlay(tree, layout, renderer) - .map(move |overlay| overlay.map(mapper)) - } -} - -impl<'a, Message, Renderer> Borrow<dyn Widget<Message, Renderer> + 'a> - for Element<'a, Message, Renderer> -{ - fn borrow(&self) -> &(dyn Widget<Message, Renderer> + 'a) { - self.widget.borrow() - } -} - -impl<'a, Message, Renderer> Borrow<dyn Widget<Message, Renderer> + 'a> - for &Element<'a, Message, Renderer> -{ - fn borrow(&self) -> &(dyn Widget<Message, Renderer> + 'a) { - self.widget.borrow() - } -} |