diff options
| author | 2023-01-24 02:14:50 +0100 | |
|---|---|---|
| committer | 2023-01-24 02:14:50 +0100 | |
| commit | 2dea5fe058f825db1a03cfce1fa84efbcb46a906 (patch) | |
| tree | 1991b0c69784d37671686776a0296f047ac16731 /native/src/overlay | |
| parent | eb4fcba05fb54741289a28ec9b921c90c9acc7fd (diff) | |
| parent | 01c484245be54c1aeb6605659fb0f222856c28da (diff) | |
| download | iced-2dea5fe058f825db1a03cfce1fa84efbcb46a906.tar.gz iced-2dea5fe058f825db1a03cfce1fa84efbcb46a906.tar.bz2 iced-2dea5fe058f825db1a03cfce1fa84efbcb46a906.zip  | |
Merge pull request #1655 from tarkah/feat/group-overlay
Group Overlay
Diffstat (limited to '')
| -rw-r--r-- | native/src/overlay.rs | 18 | ||||
| -rw-r--r-- | native/src/overlay/element.rs | 9 | ||||
| -rw-r--r-- | native/src/overlay/group.rs | 172 | 
3 files changed, 196 insertions, 3 deletions
diff --git a/native/src/overlay.rs b/native/src/overlay.rs index 22f8b6ec..6cada416 100644 --- a/native/src/overlay.rs +++ b/native/src/overlay.rs @@ -1,9 +1,11 @@  //! Display interactive elements on top of other widgets.  mod element; +mod group;  pub mod menu;  pub use element::Element; +pub use group::Group;  pub use menu::Menu;  use crate::event::{self, Event}; @@ -87,9 +89,17 @@ where      ) -> mouse::Interaction {          mouse::Interaction::Idle      } + +    /// Returns true if the cursor is over the [`Overlay`]. +    /// +    /// By default, it returns true if the bounds of the `layout` contain +    /// the `cursor_position`. +    fn is_over(&self, layout: Layout<'_>, cursor_position: Point) -> bool { +        layout.bounds().contains(cursor_position) +    }  } -/// Obtains the first overlay [`Element`] found in the given children. +/// Returns a [`Group`] of overlay [`Element`] children.  ///  /// This method will generally only be used by advanced users that are  /// implementing the [`Widget`](crate::Widget) trait. @@ -102,12 +112,14 @@ pub fn from_children<'a, Message, Renderer>(  where      Renderer: crate::Renderer,  { -    children +    let children = children          .iter_mut()          .zip(&mut tree.children)          .zip(layout.children())          .filter_map(|((child, state), layout)| {              child.as_widget_mut().overlay(state, layout, renderer)          }) -        .next() +        .collect::<Vec<_>>(); + +    (!children.is_empty()).then(|| Group::with_children(children).overlay())  } diff --git a/native/src/overlay/element.rs b/native/src/overlay/element.rs index 41a8a597..bdf7766e 100644 --- a/native/src/overlay/element.rs +++ b/native/src/overlay/element.rs @@ -115,6 +115,11 @@ where      ) {          self.overlay.operate(layout, renderer, operation);      } + +    /// Returns true if the cursor is over the [`Element`]. +    pub fn is_over(&self, layout: Layout<'_>, cursor_position: Point) -> bool { +        self.overlay.is_over(layout, cursor_position) +    }  }  struct Map<'a, A, B, Renderer> { @@ -252,4 +257,8 @@ where          self.content              .draw(renderer, theme, style, layout, cursor_position)      } + +    fn is_over(&self, layout: Layout<'_>, cursor_position: Point) -> bool { +        self.content.is_over(layout, cursor_position) +    }  } diff --git a/native/src/overlay/group.rs b/native/src/overlay/group.rs new file mode 100644 index 00000000..5c9cf809 --- /dev/null +++ b/native/src/overlay/group.rs @@ -0,0 +1,172 @@ +use iced_core::{Point, Rectangle, Size}; + +use crate::event; +use crate::layout; +use crate::mouse; +use crate::overlay; +use crate::renderer; +use crate::widget; +use crate::{Clipboard, Event, Layout, Overlay, Shell}; + +/// An [`Overlay`] container that displays multiple overlay [`overlay::Element`] +/// children. +#[allow(missing_debug_implementations)] +pub struct Group<'a, Message, Renderer> { +    children: Vec<overlay::Element<'a, Message, Renderer>>, +} + +impl<'a, Message, Renderer> Group<'a, Message, Renderer> +where +    Renderer: 'a + crate::Renderer, +    Message: 'a, +{ +    /// Creates an empty [`Group`]. +    pub fn new() -> Self { +        Self::default() +    } + +    /// Creates a [`Group`] with the given elements. +    pub fn with_children( +        children: Vec<overlay::Element<'a, Message, Renderer>>, +    ) -> Self { +        Group { children } +    } + +    /// Adds an [`overlay::Element`] to the [`Group`]. +    pub fn push( +        mut self, +        child: impl Into<overlay::Element<'a, Message, Renderer>>, +    ) -> Self { +        self.children.push(child.into()); +        self +    } + +    /// Turns the [`Group`] into an overlay [`overlay::Element`]. +    pub fn overlay(self) -> overlay::Element<'a, Message, Renderer> { +        overlay::Element::new(Point::ORIGIN, Box::new(self)) +    } +} + +impl<'a, Message, Renderer> Default for Group<'a, Message, Renderer> +where +    Renderer: 'a + crate::Renderer, +    Message: 'a, +{ +    fn default() -> Self { +        Self::with_children(Vec::new()) +    } +} + +impl<'a, Message, Renderer> Overlay<Message, Renderer> +    for Group<'a, Message, Renderer> +where +    Renderer: crate::Renderer, +{ +    fn layout( +        &self, +        renderer: &Renderer, +        bounds: Size, +        _position: Point, +    ) -> layout::Node { +        layout::Node::with_children( +            bounds, +            self.children +                .iter() +                .map(|child| child.layout(renderer, bounds)) +                .collect(), +        ) +    } + +    fn on_event( +        &mut self, +        event: Event, +        layout: Layout<'_>, +        cursor_position: Point, +        renderer: &Renderer, +        clipboard: &mut dyn Clipboard, +        shell: &mut Shell<'_, Message>, +    ) -> event::Status { +        self.children +            .iter_mut() +            .zip(layout.children()) +            .map(|(child, layout)| { +                child.on_event( +                    event.clone(), +                    layout, +                    cursor_position, +                    renderer, +                    clipboard, +                    shell, +                ) +            }) +            .fold(event::Status::Ignored, event::Status::merge) +    } + +    fn draw( +        &self, +        renderer: &mut Renderer, +        theme: &<Renderer as crate::Renderer>::Theme, +        style: &renderer::Style, +        layout: Layout<'_>, +        cursor_position: Point, +    ) { +        for (child, layout) in self.children.iter().zip(layout.children()) { +            child.draw(renderer, theme, style, layout, cursor_position); +        } +    } + +    fn mouse_interaction( +        &self, +        layout: Layout<'_>, +        cursor_position: Point, +        viewport: &Rectangle, +        renderer: &Renderer, +    ) -> mouse::Interaction { +        self.children +            .iter() +            .zip(layout.children()) +            .map(|(child, layout)| { +                child.mouse_interaction( +                    layout, +                    cursor_position, +                    viewport, +                    renderer, +                ) +            }) +            .max() +            .unwrap_or_default() +    } + +    fn operate( +        &mut self, +        layout: Layout<'_>, +        renderer: &Renderer, +        operation: &mut dyn widget::Operation<Message>, +    ) { +        operation.container(None, &mut |operation| { +            self.children.iter_mut().zip(layout.children()).for_each( +                |(child, layout)| { +                    child.operate(layout, renderer, operation); +                }, +            ) +        }); +    } + +    fn is_over(&self, layout: Layout<'_>, cursor_position: Point) -> bool { +        self.children +            .iter() +            .zip(layout.children()) +            .any(|(child, layout)| child.is_over(layout, cursor_position)) +    } +} + +impl<'a, Message, Renderer> From<Group<'a, Message, Renderer>> +    for overlay::Element<'a, Message, Renderer> +where +    Renderer: 'a + crate::Renderer, +    Message: 'a, +{ +    fn from(group: Group<'a, Message, Renderer>) -> Self { +        group.overlay() +    } +}  | 
