From 8b8f7563ad33dafeadf6238e377748cdec17d67a Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 10 Sep 2019 19:41:49 +0200 Subject: Switch to workspace layout --- src/element.rs | 370 --------------------------------------------------------- 1 file changed, 370 deletions(-) delete mode 100644 src/element.rs (limited to 'src/element.rs') diff --git a/src/element.rs b/src/element.rs deleted file mode 100644 index 70d06f42..00000000 --- a/src/element.rs +++ /dev/null @@ -1,370 +0,0 @@ -use stretch::{geometry, result}; - -use crate::{ - renderer, Event, Hasher, Layout, MouseCursor, Node, Point, Widget, -}; - -/// 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` -/// to turn it into an [`Element`]. -/// -/// [built-in widget]: widget/index.html#built-in-widgets -/// [`Widget`]: widget/trait.Widget.html -/// [`Element`]: struct.Element.html -pub struct Element<'a, Message, Renderer> { - pub(crate) widget: Box + 'a>, -} - -impl<'a, Message, Renderer> std::fmt::Debug for Element<'a, Message, Renderer> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("Element") - .field("widget", &self.widget) - .finish() - } -} - -impl<'a, Message, Renderer> Element<'a, Message, Renderer> { - /// Create a new [`Element`] containing the given [`Widget`]. - /// - /// [`Element`]: struct.Element.html - /// [`Widget`]: widget/trait.Widget.html - pub fn new( - widget: impl Widget + 'a, - ) -> Element<'a, Message, Renderer> { - Element { - widget: Box::new(widget), - } - } - - /// 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__. - /// - /// [`Element`]: struct.Element.html - /// - /// # 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, - /// } - /// ``` - /// - /// 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 { - /// # use iced::{button, Button}; - /// # - /// # #[derive(Debug, Clone, Copy)] - /// # pub enum Message {} - /// # pub struct Counter(button::State); - /// # - /// # impl Counter { - /// # pub fn view(&mut self) -> Button { - /// # Button::new(&mut self.0, "_") - /// # } - /// # } - /// # } - /// # - /// # mod iced_wgpu { - /// # use iced::{ - /// # button, MouseCursor, Node, Point, Rectangle, Style, - /// # }; - /// # pub struct Renderer; - /// # - /// # impl button::Renderer for Renderer { - /// # fn draw( - /// # &mut self, - /// # _cursor_position: Point, - /// # _bounds: Rectangle, - /// # _state: &button::State, - /// # _label: &str, - /// # _class: button::Class, - /// # ) -> MouseCursor { - /// # MouseCursor::OutOfBounds - /// # } - /// # } - /// # } - /// # - /// # use counter::Counter; - /// # - /// # struct ManyCounters { - /// # counters: Vec, - /// # } - /// # - /// # #[derive(Debug, Clone, Copy)] - /// # pub enum Message { - /// # Counter(usize, counter::Message) - /// # } - /// use iced::{Element, Row}; - /// use iced_wgpu::Renderer; - /// - /// impl ManyCounters { - /// pub fn view(&mut self) -> Row { - /// // 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.view().into(); - /// - /// row.push( - /// // Here we turn our `Element` into - /// // an `Element` 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, - /// # } - /// # - /// # #[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(self, f: F) -> Element<'a, B, Renderer> - where - Message: 'static + Copy, - Renderer: 'a, - B: 'static, - F: 'static + Fn(Message) -> B, - { - Element { - widget: Box::new(Map::new(self.widget, f)), - } - } - - /// Marks the [`Element`] as _to-be-explained_. - /// - /// The [`Renderer`] will explain the layout of the [`Element`] graphically. - /// This can be very useful for debugging your layout! - /// - /// [`Element`]: struct.Element.html - /// [`Renderer`]: trait.Renderer.html - pub fn explain( - self, - color: Renderer::Color, - ) -> Element<'a, Message, Renderer> - where - Message: 'static, - Renderer: 'a + renderer::Debugger, - { - Element { - widget: Box::new(Explain::new(self, color)), - } - } - - pub(crate) fn compute_layout(&self, renderer: &Renderer) -> result::Layout { - let node = self.widget.node(renderer); - - node.0.compute_layout(geometry::Size::undefined()).unwrap() - } - - pub(crate) fn hash_layout(&self, state: &mut Hasher) { - self.widget.hash_layout(state); - } -} - -struct Map<'a, A, B, Renderer> { - widget: Box + 'a>, - mapper: Box B>, -} - -impl<'a, A, B, Renderer> std::fmt::Debug for Map<'a, A, B, Renderer> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("Map").field("widget", &self.widget).finish() - } -} - -impl<'a, A, B, Renderer> Map<'a, A, B, Renderer> { - pub fn new( - widget: Box + 'a>, - mapper: F, - ) -> Map<'a, A, B, Renderer> - where - F: 'static + Fn(A) -> B, - { - Map { - widget, - mapper: Box::new(mapper), - } - } -} - -impl<'a, A, B, Renderer> Widget for Map<'a, A, B, Renderer> -where - A: Copy, -{ - fn node(&self, renderer: &Renderer) -> Node { - self.widget.node(renderer) - } - - fn on_event( - &mut self, - event: Event, - layout: Layout<'_>, - cursor_position: Point, - messages: &mut Vec, - ) { - let mut original_messages = Vec::new(); - - self.widget.on_event( - event, - layout, - cursor_position, - &mut original_messages, - ); - - original_messages - .iter() - .cloned() - .for_each(|message| messages.push((self.mapper)(message))); - } - - fn draw( - &self, - renderer: &mut Renderer, - layout: Layout<'_>, - cursor_position: Point, - ) -> MouseCursor { - self.widget.draw(renderer, layout, cursor_position) - } - - fn hash_layout(&self, state: &mut Hasher) { - self.widget.hash_layout(state); - } -} - -struct Explain<'a, Message, Renderer: renderer::Debugger> { - element: Element<'a, Message, Renderer>, - color: Renderer::Color, -} - -impl<'a, Message, Renderer> std::fmt::Debug for Explain<'a, Message, Renderer> -where - Renderer: renderer::Debugger, -{ - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("Explain") - .field("element", &self.element) - .finish() - } -} - -impl<'a, Message, Renderer> Explain<'a, Message, Renderer> -where - Renderer: renderer::Debugger, -{ - fn new( - element: Element<'a, Message, Renderer>, - color: Renderer::Color, - ) -> Self { - Explain { element, color } - } -} - -impl<'a, Message, Renderer> Widget - for Explain<'a, Message, Renderer> -where - Renderer: renderer::Debugger, -{ - fn node(&self, renderer: &Renderer) -> Node { - self.element.widget.node(renderer) - } - - fn on_event( - &mut self, - event: Event, - layout: Layout<'_>, - cursor_position: Point, - messages: &mut Vec, - ) { - self.element - .widget - .on_event(event, layout, cursor_position, messages) - } - - fn draw( - &self, - renderer: &mut Renderer, - layout: Layout<'_>, - cursor_position: Point, - ) -> MouseCursor { - renderer.explain(&layout, self.color); - - self.element.widget.draw(renderer, layout, cursor_position) - } - - fn hash_layout(&self, state: &mut Hasher) { - self.element.widget.hash_layout(state); - } -} -- cgit From a97401aed2a173260a4abfdb65a77975ce6c0f01 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 14 Sep 2019 19:16:06 +0200 Subject: Rethink workspace structure --- src/element.rs | 370 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 370 insertions(+) create mode 100644 src/element.rs (limited to 'src/element.rs') diff --git a/src/element.rs b/src/element.rs new file mode 100644 index 00000000..70d06f42 --- /dev/null +++ b/src/element.rs @@ -0,0 +1,370 @@ +use stretch::{geometry, result}; + +use crate::{ + renderer, Event, Hasher, Layout, MouseCursor, Node, Point, Widget, +}; + +/// 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` +/// to turn it into an [`Element`]. +/// +/// [built-in widget]: widget/index.html#built-in-widgets +/// [`Widget`]: widget/trait.Widget.html +/// [`Element`]: struct.Element.html +pub struct Element<'a, Message, Renderer> { + pub(crate) widget: Box + 'a>, +} + +impl<'a, Message, Renderer> std::fmt::Debug for Element<'a, Message, Renderer> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Element") + .field("widget", &self.widget) + .finish() + } +} + +impl<'a, Message, Renderer> Element<'a, Message, Renderer> { + /// Create a new [`Element`] containing the given [`Widget`]. + /// + /// [`Element`]: struct.Element.html + /// [`Widget`]: widget/trait.Widget.html + pub fn new( + widget: impl Widget + 'a, + ) -> Element<'a, Message, Renderer> { + Element { + widget: Box::new(widget), + } + } + + /// 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__. + /// + /// [`Element`]: struct.Element.html + /// + /// # 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, + /// } + /// ``` + /// + /// 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 { + /// # use iced::{button, Button}; + /// # + /// # #[derive(Debug, Clone, Copy)] + /// # pub enum Message {} + /// # pub struct Counter(button::State); + /// # + /// # impl Counter { + /// # pub fn view(&mut self) -> Button { + /// # Button::new(&mut self.0, "_") + /// # } + /// # } + /// # } + /// # + /// # mod iced_wgpu { + /// # use iced::{ + /// # button, MouseCursor, Node, Point, Rectangle, Style, + /// # }; + /// # pub struct Renderer; + /// # + /// # impl button::Renderer for Renderer { + /// # fn draw( + /// # &mut self, + /// # _cursor_position: Point, + /// # _bounds: Rectangle, + /// # _state: &button::State, + /// # _label: &str, + /// # _class: button::Class, + /// # ) -> MouseCursor { + /// # MouseCursor::OutOfBounds + /// # } + /// # } + /// # } + /// # + /// # use counter::Counter; + /// # + /// # struct ManyCounters { + /// # counters: Vec, + /// # } + /// # + /// # #[derive(Debug, Clone, Copy)] + /// # pub enum Message { + /// # Counter(usize, counter::Message) + /// # } + /// use iced::{Element, Row}; + /// use iced_wgpu::Renderer; + /// + /// impl ManyCounters { + /// pub fn view(&mut self) -> Row { + /// // 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.view().into(); + /// + /// row.push( + /// // Here we turn our `Element` into + /// // an `Element` 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, + /// # } + /// # + /// # #[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(self, f: F) -> Element<'a, B, Renderer> + where + Message: 'static + Copy, + Renderer: 'a, + B: 'static, + F: 'static + Fn(Message) -> B, + { + Element { + widget: Box::new(Map::new(self.widget, f)), + } + } + + /// Marks the [`Element`] as _to-be-explained_. + /// + /// The [`Renderer`] will explain the layout of the [`Element`] graphically. + /// This can be very useful for debugging your layout! + /// + /// [`Element`]: struct.Element.html + /// [`Renderer`]: trait.Renderer.html + pub fn explain( + self, + color: Renderer::Color, + ) -> Element<'a, Message, Renderer> + where + Message: 'static, + Renderer: 'a + renderer::Debugger, + { + Element { + widget: Box::new(Explain::new(self, color)), + } + } + + pub(crate) fn compute_layout(&self, renderer: &Renderer) -> result::Layout { + let node = self.widget.node(renderer); + + node.0.compute_layout(geometry::Size::undefined()).unwrap() + } + + pub(crate) fn hash_layout(&self, state: &mut Hasher) { + self.widget.hash_layout(state); + } +} + +struct Map<'a, A, B, Renderer> { + widget: Box + 'a>, + mapper: Box B>, +} + +impl<'a, A, B, Renderer> std::fmt::Debug for Map<'a, A, B, Renderer> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Map").field("widget", &self.widget).finish() + } +} + +impl<'a, A, B, Renderer> Map<'a, A, B, Renderer> { + pub fn new( + widget: Box + 'a>, + mapper: F, + ) -> Map<'a, A, B, Renderer> + where + F: 'static + Fn(A) -> B, + { + Map { + widget, + mapper: Box::new(mapper), + } + } +} + +impl<'a, A, B, Renderer> Widget for Map<'a, A, B, Renderer> +where + A: Copy, +{ + fn node(&self, renderer: &Renderer) -> Node { + self.widget.node(renderer) + } + + fn on_event( + &mut self, + event: Event, + layout: Layout<'_>, + cursor_position: Point, + messages: &mut Vec, + ) { + let mut original_messages = Vec::new(); + + self.widget.on_event( + event, + layout, + cursor_position, + &mut original_messages, + ); + + original_messages + .iter() + .cloned() + .for_each(|message| messages.push((self.mapper)(message))); + } + + fn draw( + &self, + renderer: &mut Renderer, + layout: Layout<'_>, + cursor_position: Point, + ) -> MouseCursor { + self.widget.draw(renderer, layout, cursor_position) + } + + fn hash_layout(&self, state: &mut Hasher) { + self.widget.hash_layout(state); + } +} + +struct Explain<'a, Message, Renderer: renderer::Debugger> { + element: Element<'a, Message, Renderer>, + color: Renderer::Color, +} + +impl<'a, Message, Renderer> std::fmt::Debug for Explain<'a, Message, Renderer> +where + Renderer: renderer::Debugger, +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Explain") + .field("element", &self.element) + .finish() + } +} + +impl<'a, Message, Renderer> Explain<'a, Message, Renderer> +where + Renderer: renderer::Debugger, +{ + fn new( + element: Element<'a, Message, Renderer>, + color: Renderer::Color, + ) -> Self { + Explain { element, color } + } +} + +impl<'a, Message, Renderer> Widget + for Explain<'a, Message, Renderer> +where + Renderer: renderer::Debugger, +{ + fn node(&self, renderer: &Renderer) -> Node { + self.element.widget.node(renderer) + } + + fn on_event( + &mut self, + event: Event, + layout: Layout<'_>, + cursor_position: Point, + messages: &mut Vec, + ) { + self.element + .widget + .on_event(event, layout, cursor_position, messages) + } + + fn draw( + &self, + renderer: &mut Renderer, + layout: Layout<'_>, + cursor_position: Point, + ) -> MouseCursor { + renderer.explain(&layout, self.color); + + self.element.widget.draw(renderer, layout, cursor_position) + } + + fn hash_layout(&self, state: &mut Hasher) { + self.element.widget.hash_layout(state); + } +} -- cgit From f9de39ddaa3020a9585b1648afb0ead45dfd7aa9 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 19 Sep 2019 15:01:12 +0200 Subject: Unify `web` and `ggez` tour examples :tada: --- src/element.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src/element.rs') diff --git a/src/element.rs b/src/element.rs index 70d06f42..c13bf4a0 100644 --- a/src/element.rs +++ b/src/element.rs @@ -223,7 +223,10 @@ impl<'a, Message, Renderer> Element<'a, Message, Renderer> { } } - pub(crate) fn compute_layout(&self, renderer: &Renderer) -> result::Layout { + pub(crate) fn compute_layout( + &self, + renderer: &mut Renderer, + ) -> result::Layout { let node = self.widget.node(renderer); node.0.compute_layout(geometry::Size::undefined()).unwrap() @@ -264,7 +267,7 @@ impl<'a, A, B, Renderer> Widget for Map<'a, A, B, Renderer> where A: Copy, { - fn node(&self, renderer: &Renderer) -> Node { + fn node(&self, renderer: &mut Renderer) -> Node { self.widget.node(renderer) } @@ -337,7 +340,7 @@ impl<'a, Message, Renderer> Widget where Renderer: renderer::Debugger, { - fn node(&self, renderer: &Renderer) -> Node { + fn node(&self, renderer: &mut Renderer) -> Node { self.element.widget.node(renderer) } -- cgit From b83a4b42dd912b5f59d40e7d4f7f7ccdabc43019 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 19 Sep 2019 18:47:01 +0200 Subject: Remove generic `Color` in widgets --- src/element.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'src/element.rs') diff --git a/src/element.rs b/src/element.rs index c13bf4a0..f6276fbf 100644 --- a/src/element.rs +++ b/src/element.rs @@ -1,7 +1,7 @@ use stretch::{geometry, result}; use crate::{ - renderer, Event, Hasher, Layout, MouseCursor, Node, Point, Widget, + renderer, Color, Event, Hasher, Layout, MouseCursor, Node, Point, Widget, }; /// A generic [`Widget`]. @@ -210,16 +210,16 @@ impl<'a, Message, Renderer> Element<'a, Message, Renderer> { /// /// [`Element`]: struct.Element.html /// [`Renderer`]: trait.Renderer.html - pub fn explain( + pub fn explain>( self, - color: Renderer::Color, + color: C, ) -> Element<'a, Message, Renderer> where Message: 'static, Renderer: 'a + renderer::Debugger, { Element { - widget: Box::new(Explain::new(self, color)), + widget: Box::new(Explain::new(self, color.into())), } } @@ -309,7 +309,7 @@ where struct Explain<'a, Message, Renderer: renderer::Debugger> { element: Element<'a, Message, Renderer>, - color: Renderer::Color, + color: Color, } impl<'a, Message, Renderer> std::fmt::Debug for Explain<'a, Message, Renderer> @@ -327,10 +327,7 @@ impl<'a, Message, Renderer> Explain<'a, Message, Renderer> where Renderer: renderer::Debugger, { - fn new( - element: Element<'a, Message, Renderer>, - color: Renderer::Color, - ) -> Self { + fn new(element: Element<'a, Message, Renderer>, color: Color) -> Self { Explain { element, color } } } -- cgit From b9e0f7494881ad7cdfbcbc16878ecc6ef717753f Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 20 Sep 2019 19:15:31 +0200 Subject: Create `iced_core` and `iced_native` --- src/element.rs | 370 --------------------------------------------------------- 1 file changed, 370 deletions(-) delete mode 100644 src/element.rs (limited to 'src/element.rs') diff --git a/src/element.rs b/src/element.rs deleted file mode 100644 index f6276fbf..00000000 --- a/src/element.rs +++ /dev/null @@ -1,370 +0,0 @@ -use stretch::{geometry, result}; - -use crate::{ - renderer, Color, Event, Hasher, Layout, MouseCursor, Node, Point, Widget, -}; - -/// 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` -/// to turn it into an [`Element`]. -/// -/// [built-in widget]: widget/index.html#built-in-widgets -/// [`Widget`]: widget/trait.Widget.html -/// [`Element`]: struct.Element.html -pub struct Element<'a, Message, Renderer> { - pub(crate) widget: Box + 'a>, -} - -impl<'a, Message, Renderer> std::fmt::Debug for Element<'a, Message, Renderer> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("Element") - .field("widget", &self.widget) - .finish() - } -} - -impl<'a, Message, Renderer> Element<'a, Message, Renderer> { - /// Create a new [`Element`] containing the given [`Widget`]. - /// - /// [`Element`]: struct.Element.html - /// [`Widget`]: widget/trait.Widget.html - pub fn new( - widget: impl Widget + 'a, - ) -> Element<'a, Message, Renderer> { - Element { - widget: Box::new(widget), - } - } - - /// 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__. - /// - /// [`Element`]: struct.Element.html - /// - /// # 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, - /// } - /// ``` - /// - /// 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 { - /// # use iced::{button, Button}; - /// # - /// # #[derive(Debug, Clone, Copy)] - /// # pub enum Message {} - /// # pub struct Counter(button::State); - /// # - /// # impl Counter { - /// # pub fn view(&mut self) -> Button { - /// # Button::new(&mut self.0, "_") - /// # } - /// # } - /// # } - /// # - /// # mod iced_wgpu { - /// # use iced::{ - /// # button, MouseCursor, Node, Point, Rectangle, Style, - /// # }; - /// # pub struct Renderer; - /// # - /// # impl button::Renderer for Renderer { - /// # fn draw( - /// # &mut self, - /// # _cursor_position: Point, - /// # _bounds: Rectangle, - /// # _state: &button::State, - /// # _label: &str, - /// # _class: button::Class, - /// # ) -> MouseCursor { - /// # MouseCursor::OutOfBounds - /// # } - /// # } - /// # } - /// # - /// # use counter::Counter; - /// # - /// # struct ManyCounters { - /// # counters: Vec, - /// # } - /// # - /// # #[derive(Debug, Clone, Copy)] - /// # pub enum Message { - /// # Counter(usize, counter::Message) - /// # } - /// use iced::{Element, Row}; - /// use iced_wgpu::Renderer; - /// - /// impl ManyCounters { - /// pub fn view(&mut self) -> Row { - /// // 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.view().into(); - /// - /// row.push( - /// // Here we turn our `Element` into - /// // an `Element` 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, - /// # } - /// # - /// # #[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(self, f: F) -> Element<'a, B, Renderer> - where - Message: 'static + Copy, - Renderer: 'a, - B: 'static, - F: 'static + Fn(Message) -> B, - { - Element { - widget: Box::new(Map::new(self.widget, f)), - } - } - - /// Marks the [`Element`] as _to-be-explained_. - /// - /// The [`Renderer`] will explain the layout of the [`Element`] graphically. - /// This can be very useful for debugging your layout! - /// - /// [`Element`]: struct.Element.html - /// [`Renderer`]: trait.Renderer.html - pub fn explain>( - self, - color: C, - ) -> Element<'a, Message, Renderer> - where - Message: 'static, - Renderer: 'a + renderer::Debugger, - { - Element { - widget: Box::new(Explain::new(self, color.into())), - } - } - - pub(crate) fn compute_layout( - &self, - renderer: &mut Renderer, - ) -> result::Layout { - let node = self.widget.node(renderer); - - node.0.compute_layout(geometry::Size::undefined()).unwrap() - } - - pub(crate) fn hash_layout(&self, state: &mut Hasher) { - self.widget.hash_layout(state); - } -} - -struct Map<'a, A, B, Renderer> { - widget: Box + 'a>, - mapper: Box B>, -} - -impl<'a, A, B, Renderer> std::fmt::Debug for Map<'a, A, B, Renderer> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("Map").field("widget", &self.widget).finish() - } -} - -impl<'a, A, B, Renderer> Map<'a, A, B, Renderer> { - pub fn new( - widget: Box + 'a>, - mapper: F, - ) -> Map<'a, A, B, Renderer> - where - F: 'static + Fn(A) -> B, - { - Map { - widget, - mapper: Box::new(mapper), - } - } -} - -impl<'a, A, B, Renderer> Widget for Map<'a, A, B, Renderer> -where - A: Copy, -{ - fn node(&self, renderer: &mut Renderer) -> Node { - self.widget.node(renderer) - } - - fn on_event( - &mut self, - event: Event, - layout: Layout<'_>, - cursor_position: Point, - messages: &mut Vec, - ) { - let mut original_messages = Vec::new(); - - self.widget.on_event( - event, - layout, - cursor_position, - &mut original_messages, - ); - - original_messages - .iter() - .cloned() - .for_each(|message| messages.push((self.mapper)(message))); - } - - fn draw( - &self, - renderer: &mut Renderer, - layout: Layout<'_>, - cursor_position: Point, - ) -> MouseCursor { - self.widget.draw(renderer, layout, cursor_position) - } - - fn hash_layout(&self, state: &mut Hasher) { - self.widget.hash_layout(state); - } -} - -struct Explain<'a, Message, Renderer: renderer::Debugger> { - element: Element<'a, Message, Renderer>, - color: Color, -} - -impl<'a, Message, Renderer> std::fmt::Debug for Explain<'a, Message, Renderer> -where - Renderer: renderer::Debugger, -{ - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("Explain") - .field("element", &self.element) - .finish() - } -} - -impl<'a, Message, Renderer> Explain<'a, Message, Renderer> -where - Renderer: renderer::Debugger, -{ - fn new(element: Element<'a, Message, Renderer>, color: Color) -> Self { - Explain { element, color } - } -} - -impl<'a, Message, Renderer> Widget - for Explain<'a, Message, Renderer> -where - Renderer: renderer::Debugger, -{ - fn node(&self, renderer: &mut Renderer) -> Node { - self.element.widget.node(renderer) - } - - fn on_event( - &mut self, - event: Event, - layout: Layout<'_>, - cursor_position: Point, - messages: &mut Vec, - ) { - self.element - .widget - .on_event(event, layout, cursor_position, messages) - } - - fn draw( - &self, - renderer: &mut Renderer, - layout: Layout<'_>, - cursor_position: Point, - ) -> MouseCursor { - renderer.explain(&layout, self.color); - - self.element.widget.draw(renderer, layout, cursor_position) - } - - fn hash_layout(&self, state: &mut Hasher) { - self.element.widget.hash_layout(state); - } -} -- cgit