diff options
Diffstat (limited to '')
| -rw-r--r-- | native/src/element.rs | 5 | ||||
| -rw-r--r-- | native/src/layer.rs | 34 | ||||
| -rw-r--r-- | native/src/layout.rs | 7 | ||||
| -rw-r--r-- | native/src/lib.rs | 2 | ||||
| -rw-r--r-- | native/src/overlay.rs | 37 | ||||
| -rw-r--r-- | native/src/renderer.rs | 9 | ||||
| -rw-r--r-- | native/src/renderer/null.rs | 3 | ||||
| -rw-r--r-- | native/src/user_interface.rs | 149 | ||||
| -rw-r--r-- | native/src/widget.rs | 5 | ||||
| -rw-r--r-- | native/src/widget/column.rs | 15 | ||||
| -rw-r--r-- | native/src/widget/container.rs | 11 | 
11 files changed, 224 insertions, 53 deletions
| diff --git a/native/src/element.rs b/native/src/element.rs index c6d65550..01379d2d 100644 --- a/native/src/element.rs +++ b/native/src/element.rs @@ -274,8 +274,9 @@ where      pub fn overlay(          &mut self, -    ) -> Option<Box<dyn Overlay<Message, Renderer> + 'a>> { -        self.widget.overlay() +        layout: Layout<'_>, +    ) -> Option<Overlay<'a, Message, Renderer>> { +        self.widget.overlay(layout)      }  } diff --git a/native/src/layer.rs b/native/src/layer.rs new file mode 100644 index 00000000..d89fb4e5 --- /dev/null +++ b/native/src/layer.rs @@ -0,0 +1,34 @@ +use crate::{layout, Clipboard, Event, Hasher, Layout, Point, Size}; + +pub trait Layer<Message, Renderer> +where +    Renderer: crate::Renderer, +{ +    fn layout( +        &self, +        renderer: &Renderer, +        bounds: Size, +        position: Point, +    ) -> layout::Node; + +    fn draw( +        &self, +        renderer: &mut Renderer, +        defaults: &Renderer::Defaults, +        layout: Layout<'_>, +        cursor_position: Point, +    ) -> Renderer::Output; + +    fn hash_layout(&self, state: &mut Hasher, position: Point); + +    fn on_event( +        &mut self, +        _event: Event, +        _layout: Layout<'_>, +        _cursor_position: Point, +        _messages: &mut Vec<Message>, +        _renderer: &Renderer, +        _clipboard: Option<&dyn Clipboard>, +    ) { +    } +} diff --git a/native/src/layout.rs b/native/src/layout.rs index 4a3ab94a..178f0f24 100644 --- a/native/src/layout.rs +++ b/native/src/layout.rs @@ -34,6 +34,13 @@ impl<'a> Layout<'a> {          }      } +    /// Gets the position of the [`Layout`]. +    /// +    /// [`Layout`]: struct.Layout.html +    pub fn position(&self) -> Point { +        self.position +    } +      /// Gets the bounds of the [`Layout`].      ///      /// The returned [`Rectangle`] describes the position and size of a diff --git a/native/src/lib.rs b/native/src/lib.rs index dbec068d..6974c2bd 100644 --- a/native/src/lib.rs +++ b/native/src/lib.rs @@ -48,6 +48,7 @@ mod clipboard;  mod element;  mod event;  mod hasher; +mod layer;  mod overlay;  mod runtime;  mod user_interface; @@ -75,6 +76,7 @@ pub use debug::Debug;  pub use element::Element;  pub use event::Event;  pub use hasher::Hasher; +pub use layer::Layer;  pub use layout::Layout;  pub use overlay::Overlay;  pub use program::Program; diff --git a/native/src/overlay.rs b/native/src/overlay.rs index d34432a4..a4bd5ea3 100644 --- a/native/src/overlay.rs +++ b/native/src/overlay.rs @@ -1,26 +1,41 @@ -use crate::{layout, Clipboard, Event, Hasher, Layout, Point}; +use crate::{layout, Clipboard, Event, Hasher, Layer, Layout, Point, Size}; -pub trait Overlay<Message, Renderer> +#[allow(missing_debug_implementations)] +pub struct Overlay<'a, Message, Renderer> { +    position: Point, +    layer: Box<dyn Layer<Message, Renderer> + 'a>, +} + +impl<'a, Message, Renderer> Overlay<'a, Message, Renderer>  where      Renderer: crate::Renderer,  { -    fn layout( -        &self, -        renderer: &Renderer, -        limits: &layout::Limits, -    ) -> layout::Node; +    pub fn new( +        position: Point, +        layer: Box<dyn Layer<Message, Renderer> + 'a>, +    ) -> Self { +        Self { position, layer } +    } -    fn draw( +    pub fn layout(&self, renderer: &Renderer, bounds: Size) -> layout::Node { +        self.layer.layout(renderer, bounds, self.position) +    } + +    pub fn draw(          &self,          renderer: &mut Renderer,          defaults: &Renderer::Defaults,          layout: Layout<'_>,          cursor_position: Point, -    ) -> Renderer::Output; +    ) -> Renderer::Output { +        self.layer.draw(renderer, defaults, layout, cursor_position) +    } -    fn hash_layout(&self, state: &mut Hasher); +    pub fn hash_layout(&self, state: &mut Hasher) { +        self.layer.hash_layout(state, self.position); +    } -    fn on_event( +    pub fn on_event(          &mut self,          _event: Event,          _layout: Layout<'_>, diff --git a/native/src/renderer.rs b/native/src/renderer.rs index a16df72b..29a091a4 100644 --- a/native/src/renderer.rs +++ b/native/src/renderer.rs @@ -25,7 +25,7 @@ mod null;  #[cfg(debug_assertions)]  pub use null::Null; -use crate::{layout, Element}; +use crate::{layout, Element, Rectangle};  /// A component that can take the state of a user interface and produce an  /// output for its users. @@ -56,4 +56,11 @@ pub trait Renderer: Sized {      ) -> layout::Node {          element.layout(self, limits)      } + +    fn overlay( +        &mut self, +        base: Self::Output, +        overlay: Self::Output, +        overlay_bounds: Rectangle, +    ) -> Self::Output;  } diff --git a/native/src/renderer/null.rs b/native/src/renderer/null.rs index 5fd3627b..bd6aca29 100644 --- a/native/src/renderer/null.rs +++ b/native/src/renderer/null.rs @@ -22,6 +22,9 @@ impl Null {  impl Renderer for Null {      type Output = ();      type Defaults = (); + +    fn overlay(&mut self, _base: (), _overlay: (), _overlay_bounds: Rectangle) { +    }  }  impl column::Renderer for Null { diff --git a/native/src/user_interface.rs b/native/src/user_interface.rs index b9646043..6758bce3 100644 --- a/native/src/user_interface.rs +++ b/native/src/user_interface.rs @@ -1,4 +1,4 @@ -use crate::{layout, Clipboard, Element, Event, Layout, Point, Size}; +use crate::{layout, Clipboard, Element, Event, Layout, Overlay, Point, Size};  use std::hash::Hasher; @@ -19,12 +19,17 @@ use std::hash::Hasher;  /// [`UserInterface`]: struct.UserInterface.html  #[allow(missing_debug_implementations)]  pub struct UserInterface<'a, Message, Renderer> { -    hash: u64, -    root: Element<'a, Message, Renderer>, -    layout: layout::Node, +    base: Layer<Element<'a, Message, Renderer>>, +    overlay: Option<Layer<Overlay<'a, Message, Renderer>>>,      bounds: Size,  } +struct Layer<T> { +    root: T, +    layout: layout::Node, +    hash: u64, +} +  impl<'a, Message, Renderer> UserInterface<'a, Message, Renderer>  where      Renderer: crate::Renderer, @@ -92,27 +97,45 @@ where          cache: Cache,          renderer: &mut Renderer,      ) -> Self { -        let root = root.into(); +        let mut root = root.into(); -        let hash = { -            let hasher = &mut crate::Hasher::default(); -            root.hash_layout(hasher); +        let (base, overlay) = { +            let hash = { +                let hasher = &mut crate::Hasher::default(); +                root.hash_layout(hasher); -            hasher.finish() -        }; +                hasher.finish() +            }; -        let layout_is_cached = hash == cache.hash && bounds == cache.bounds; +            let layout_is_cached = hash == cache.hash && bounds == cache.bounds; -        let layout = if layout_is_cached { -            cache.layout -        } else { -            renderer.layout(&root, &layout::Limits::new(Size::ZERO, bounds)) +            let layout = if layout_is_cached { +                cache.layout +            } else { +                renderer.layout(&root, &layout::Limits::new(Size::ZERO, bounds)) +            }; + +            let overlay = root.overlay(Layout::new(&layout)); + +            (Layer { root, layout, hash }, overlay)          }; +        let overlay = overlay.map(|root| { +            let hash = { +                let hasher = &mut crate::Hasher::default(); +                root.hash_layout(hasher); + +                hasher.finish() +            }; + +            let layout = root.layout(&renderer, bounds); + +            Layer { root, layout, hash } +        }); +          UserInterface { -            hash, -            root, -            layout, +            base, +            overlay,              bounds,          }      } @@ -193,14 +216,42 @@ where          let mut messages = Vec::new();          for event in events { -            self.root.widget.on_event( -                event, -                Layout::new(&self.layout), -                cursor_position, -                &mut messages, -                renderer, -                clipboard, -            ); +            if let Some(overlay) = &mut self.overlay { +                overlay.root.on_event( +                    event.clone(), +                    Layout::new(&overlay.layout), +                    cursor_position, +                    &mut messages, +                    renderer, +                    clipboard, +                ); + +                let base_cursor = +                    if overlay.layout.bounds().contains(cursor_position) { +                        // TODO: Encode cursor availability +                        Point::new(-1.0, -1.0) +                    } else { +                        cursor_position +                    }; + +                self.base.root.widget.on_event( +                    event, +                    Layout::new(&self.base.layout), +                    base_cursor, +                    &mut messages, +                    renderer, +                    clipboard, +                ); +            } else { +                self.base.root.widget.on_event( +                    event, +                    Layout::new(&self.base.layout), +                    cursor_position, +                    &mut messages, +                    renderer, +                    clipboard, +                ); +            }          }          messages @@ -280,12 +331,42 @@ where          renderer: &mut Renderer,          cursor_position: Point,      ) -> Renderer::Output { -        self.root.widget.draw( -            renderer, -            &Renderer::Defaults::default(), -            Layout::new(&self.layout), -            cursor_position, -        ) +        if let Some(overlay) = &self.overlay { +            let overlay_bounds = overlay.layout.bounds(); + +            let base_cursor = if overlay_bounds.contains(cursor_position) { +                Point::new(-1.0, -1.0) +            } else { +                cursor_position +            }; + +            let base_primitives = self.base.root.widget.draw( +                renderer, +                &Renderer::Defaults::default(), +                Layout::new(&self.base.layout), +                base_cursor, +            ); + +            let overlay_primitives = overlay.root.draw( +                renderer, +                &Renderer::Defaults::default(), +                Layout::new(&overlay.layout), +                cursor_position, +            ); + +            renderer.overlay( +                base_primitives, +                overlay_primitives, +                overlay_bounds, +            ) +        } else { +            self.base.root.widget.draw( +                renderer, +                &Renderer::Defaults::default(), +                Layout::new(&self.base.layout), +                cursor_position, +            ) +        }      }      /// Extract the [`Cache`] of the [`UserInterface`], consuming it in the @@ -295,8 +376,8 @@ where      /// [`UserInterface`]: struct.UserInterface.html      pub fn into_cache(self) -> Cache {          Cache { -            hash: self.hash, -            layout: self.layout, +            hash: self.base.hash, +            layout: self.base.layout,              bounds: self.bounds,          }      } diff --git a/native/src/widget.rs b/native/src/widget.rs index dd1a97d2..0494636f 100644 --- a/native/src/widget.rs +++ b/native/src/widget.rs @@ -176,7 +176,10 @@ where      ) {      } -    fn overlay(&mut self) -> Option<Box<dyn Overlay<Message, Renderer> + 'a>> { +    fn overlay( +        &mut self, +        _layout: Layout<'_>, +    ) -> Option<Overlay<'a, Message, Renderer>> {          None      }  } diff --git a/native/src/widget/column.rs b/native/src/widget/column.rs index 6afc94d6..9a6dbdb3 100644 --- a/native/src/widget/column.rs +++ b/native/src/widget/column.rs @@ -2,8 +2,8 @@  use std::hash::Hash;  use crate::{ -    layout, Align, Clipboard, Element, Event, Hasher, Layout, Length, Point, -    Widget, +    layout, Align, Clipboard, Element, Event, Hasher, Layout, Length, Overlay, +    Point, Widget,  };  use std::u32; @@ -204,6 +204,17 @@ where              child.widget.hash_layout(state);          }      } + +    fn overlay( +        &mut self, +        layout: Layout<'_>, +    ) -> Option<Overlay<'a, Message, Renderer>> { +        self.children +            .iter_mut() +            .zip(layout.children()) +            .filter_map(|(child, layout)| child.widget.overlay(layout)) +            .next() +    }  }  /// The renderer of a [`Column`]. diff --git a/native/src/widget/container.rs b/native/src/widget/container.rs index 3ad12eeb..3bdb1a27 100644 --- a/native/src/widget/container.rs +++ b/native/src/widget/container.rs @@ -2,8 +2,8 @@  use std::hash::Hash;  use crate::{ -    layout, Align, Clipboard, Element, Event, Hasher, Layout, Length, Point, -    Rectangle, Widget, +    layout, Align, Clipboard, Element, Event, Hasher, Layout, Length, Overlay, +    Point, Rectangle, Widget,  };  use std::u32; @@ -214,6 +214,13 @@ where          self.content.hash_layout(state);      } + +    fn overlay( +        &mut self, +        layout: Layout<'_>, +    ) -> Option<Overlay<'a, Message, Renderer>> { +        self.content.overlay(layout.children().next().unwrap()) +    }  }  /// The renderer of a [`Container`]. | 
