diff options
Diffstat (limited to 'pure/src/element.rs')
-rw-r--r-- | pure/src/element.rs | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/pure/src/element.rs b/pure/src/element.rs index 08096103..704b3d0b 100644 --- a/pure/src/element.rs +++ b/pure/src/element.rs @@ -8,25 +8,171 @@ use iced_native::mouse; use iced_native::renderer; use iced_native::{Clipboard, Length, Point, Rectangle, Shell}; +/// 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 { 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, |