summaryrefslogtreecommitdiffstats
path: root/native
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón <hector0193@gmail.com>2023-01-24 02:14:50 +0100
committerLibravatar GitHub <noreply@github.com>2023-01-24 02:14:50 +0100
commit2dea5fe058f825db1a03cfce1fa84efbcb46a906 (patch)
tree1991b0c69784d37671686776a0296f047ac16731 /native
parenteb4fcba05fb54741289a28ec9b921c90c9acc7fd (diff)
parent01c484245be54c1aeb6605659fb0f222856c28da (diff)
downloadiced-2dea5fe058f825db1a03cfce1fa84efbcb46a906.tar.gz
iced-2dea5fe058f825db1a03cfce1fa84efbcb46a906.tar.bz2
iced-2dea5fe058f825db1a03cfce1fa84efbcb46a906.zip
Merge pull request #1655 from tarkah/feat/group-overlay
Group Overlay
Diffstat (limited to 'native')
-rw-r--r--native/src/overlay.rs18
-rw-r--r--native/src/overlay/element.rs9
-rw-r--r--native/src/overlay/group.rs172
-rw-r--r--native/src/shell.rs5
-rw-r--r--native/src/user_interface.rs9
-rw-r--r--native/src/widget/pane_grid.rs13
6 files changed, 216 insertions, 10 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()
+ }
+}
diff --git a/native/src/shell.rs b/native/src/shell.rs
index f1ddb48e..74a5c616 100644
--- a/native/src/shell.rs
+++ b/native/src/shell.rs
@@ -25,6 +25,11 @@ impl<'a, Message> Shell<'a, Message> {
}
}
+ /// Returns true if the [`Shell`] contains no published messages
+ pub fn is_empty(&self) -> bool {
+ self.messages.is_empty()
+ }
+
/// Publish the given `Message` for an application to process it.
pub fn publish(&mut self, message: Message) {
self.messages.push(message);
diff --git a/native/src/user_interface.rs b/native/src/user_interface.rs
index 29cc3472..0def730c 100644
--- a/native/src/user_interface.rs
+++ b/native/src/user_interface.rs
@@ -261,7 +261,11 @@ where
}
}
- let base_cursor = if layout.bounds().contains(cursor_position) {
+ let base_cursor = if manual_overlay
+ .as_ref()
+ .unwrap()
+ .is_over(Layout::new(&layout), cursor_position)
+ {
// TODO: Type-safe cursor availability
Point::new(-1.0, -1.0)
} else {
@@ -504,7 +508,8 @@ where
);
});
- if overlay_bounds.contains(cursor_position) {
+ if overlay.is_over(Layout::new(layout), cursor_position)
+ {
overlay_interaction
} else {
base_interaction
diff --git a/native/src/widget/pane_grid.rs b/native/src/widget/pane_grid.rs
index 8dbd1825..eb04c0ba 100644
--- a/native/src/widget/pane_grid.rs
+++ b/native/src/widget/pane_grid.rs
@@ -35,7 +35,7 @@ pub use iced_style::pane_grid::{Line, StyleSheet};
use crate::event::{self, Event};
use crate::layout;
use crate::mouse;
-use crate::overlay;
+use crate::overlay::{self, Group};
use crate::renderer;
use crate::touch;
use crate::widget;
@@ -450,14 +450,17 @@ where
layout: Layout<'_>,
renderer: &Renderer,
) -> Option<overlay::Element<'_, Message, Renderer>> {
- self.contents
+ let children = self
+ .contents
.iter_mut()
.zip(&mut tree.children)
.zip(layout.children())
- .filter_map(|(((_, pane), tree), layout)| {
- pane.overlay(tree, layout, renderer)
+ .filter_map(|(((_, content), state), layout)| {
+ content.overlay(state, layout, renderer)
})
- .next()
+ .collect::<Vec<_>>();
+
+ (!children.is_empty()).then(|| Group::with_children(children).overlay())
}
}