summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector@hecrj.dev>2024-04-25 06:05:00 +0200
committerLibravatar Héctor Ramón Jiménez <hector@hecrj.dev>2024-04-25 06:05:37 +0200
commit4cd45643d7d2aa83212162f17a9b28ddae4a9340 (patch)
treefbddb2c21c41a4d76c10ee0695dd5e1fd9669f14
parent9492da11d90893b396e8dfdae47cc54c6ab42411 (diff)
downloadiced-4cd45643d7d2aa83212162f17a9b28ddae4a9340.tar.gz
iced-4cd45643d7d2aa83212162f17a9b28ddae4a9340.tar.bz2
iced-4cd45643d7d2aa83212162f17a9b28ddae4a9340.zip
Introduce `opaque` widget helper
-rw-r--r--core/src/mouse/interaction.rs1
-rw-r--r--core/src/overlay.rs2
-rw-r--r--core/src/widget.rs2
-rw-r--r--examples/loupe/src/main.rs2
-rw-r--r--runtime/src/multi_window/state.rs2
-rw-r--r--runtime/src/program/state.rs2
-rw-r--r--widget/src/helpers.rs169
-rw-r--r--widget/src/image/viewer.rs2
-rw-r--r--widget/src/mouse_area.rs2
-rw-r--r--widget/src/scrollable.rs2
-rw-r--r--widget/src/stack.rs2
-rw-r--r--winit/src/conversion.rs4
-rw-r--r--winit/src/multi_window/window_manager.rs2
13 files changed, 182 insertions, 12 deletions
diff --git a/core/src/mouse/interaction.rs b/core/src/mouse/interaction.rs
index 6ad66229..065eb8e7 100644
--- a/core/src/mouse/interaction.rs
+++ b/core/src/mouse/interaction.rs
@@ -3,6 +3,7 @@
#[allow(missing_docs)]
pub enum Interaction {
#[default]
+ None,
Idle,
Pointer,
Grab,
diff --git a/core/src/overlay.rs b/core/src/overlay.rs
index 03076a30..3a57fe16 100644
--- a/core/src/overlay.rs
+++ b/core/src/overlay.rs
@@ -79,7 +79,7 @@ where
_viewport: &Rectangle,
_renderer: &Renderer,
) -> mouse::Interaction {
- mouse::Interaction::Idle
+ mouse::Interaction::None
}
/// Returns true if the cursor is over the [`Overlay`].
diff --git a/core/src/widget.rs b/core/src/widget.rs
index 58a9f19b..b02e3a4f 100644
--- a/core/src/widget.rs
+++ b/core/src/widget.rs
@@ -137,7 +137,7 @@ where
_viewport: &Rectangle,
_renderer: &Renderer,
) -> mouse::Interaction {
- mouse::Interaction::Idle
+ mouse::Interaction::None
}
/// Returns the overlay of the [`Widget`], if there is any.
diff --git a/examples/loupe/src/main.rs b/examples/loupe/src/main.rs
index 6a5ff123..42b7f471 100644
--- a/examples/loupe/src/main.rs
+++ b/examples/loupe/src/main.rs
@@ -159,7 +159,7 @@ mod loupe {
if cursor.is_over(layout.bounds()) {
mouse::Interaction::ZoomIn
} else {
- mouse::Interaction::Idle
+ mouse::Interaction::None
}
}
}
diff --git a/runtime/src/multi_window/state.rs b/runtime/src/multi_window/state.rs
index afd04519..10366ec0 100644
--- a/runtime/src/multi_window/state.rs
+++ b/runtime/src/multi_window/state.rs
@@ -48,7 +48,7 @@ where
caches,
queued_events: Vec::new(),
queued_messages: Vec::new(),
- mouse_interaction: mouse::Interaction::Idle,
+ mouse_interaction: mouse::Interaction::None,
}
}
diff --git a/runtime/src/program/state.rs b/runtime/src/program/state.rs
index d685b07c..c6589c22 100644
--- a/runtime/src/program/state.rs
+++ b/runtime/src/program/state.rs
@@ -47,7 +47,7 @@ where
cache,
queued_events: Vec::new(),
queued_messages: Vec::new(),
- mouse_interaction: mouse::Interaction::Idle,
+ mouse_interaction: mouse::Interaction::None,
}
}
diff --git a/widget/src/helpers.rs b/widget/src/helpers.rs
index 2afed3e6..fd345251 100644
--- a/widget/src/helpers.rs
+++ b/widget/src/helpers.rs
@@ -5,7 +5,7 @@ use crate::combo_box::{self, ComboBox};
use crate::container::{self, Container};
use crate::core;
use crate::core::widget::operation;
-use crate::core::{Element, Length, Pixels};
+use crate::core::{Element, Length, Pixels, Widget};
use crate::keyed;
use crate::overlay;
use crate::pick_list::{self, PickList};
@@ -123,6 +123,173 @@ where
Stack::with_children(children)
}
+/// Wraps the given widget and captures any mouse button presses inside the bounds of
+/// the widget—therefore making it _opaque_.
+///
+/// This helper is meant to be used to mark elements in a [`Stack`] to avoid mouse
+/// events from passing through layers.
+///
+/// [`Stack`]: crate::Stack
+pub fn opaque<'a, Message, Theme, Renderer>(
+ content: impl Into<Element<'a, Message, Theme, Renderer>>,
+) -> Element<'a, Message, Theme, Renderer>
+where
+ Message: 'a,
+ Theme: 'a,
+ Renderer: core::Renderer + 'a,
+{
+ use crate::core::event::{self, Event};
+ use crate::core::layout::{self, Layout};
+ use crate::core::mouse;
+ use crate::core::renderer;
+ use crate::core::widget::tree::{self, Tree};
+ use crate::core::{Rectangle, Shell, Size};
+
+ struct Opaque<'a, Message, Theme, Renderer> {
+ content: Element<'a, Message, Theme, Renderer>,
+ }
+
+ impl<'a, Message, Theme, Renderer> Widget<Message, Theme, Renderer>
+ for Opaque<'a, Message, Theme, Renderer>
+ where
+ Renderer: core::Renderer,
+ {
+ fn tag(&self) -> tree::Tag {
+ self.content.as_widget().tag()
+ }
+
+ fn state(&self) -> tree::State {
+ self.content.as_widget().state()
+ }
+
+ fn children(&self) -> Vec<Tree> {
+ self.content.as_widget().children()
+ }
+
+ fn diff(&self, tree: &mut Tree) {
+ self.content.as_widget().diff(tree);
+ }
+
+ fn size(&self) -> Size<Length> {
+ self.content.as_widget().size()
+ }
+
+ fn size_hint(&self) -> Size<Length> {
+ self.content.as_widget().size_hint()
+ }
+
+ fn layout(
+ &self,
+ tree: &mut Tree,
+ renderer: &Renderer,
+ limits: &layout::Limits,
+ ) -> layout::Node {
+ self.content.as_widget().layout(tree, renderer, limits)
+ }
+
+ fn draw(
+ &self,
+ tree: &Tree,
+ renderer: &mut Renderer,
+ theme: &Theme,
+ style: &renderer::Style,
+ layout: Layout<'_>,
+ cursor: mouse::Cursor,
+ viewport: &Rectangle,
+ ) {
+ self.content
+ .as_widget()
+ .draw(tree, renderer, theme, style, layout, cursor, viewport);
+ }
+
+ fn operate(
+ &self,
+ state: &mut Tree,
+ layout: Layout<'_>,
+ renderer: &Renderer,
+ operation: &mut dyn operation::Operation<Message>,
+ ) {
+ self.content
+ .as_widget()
+ .operate(state, layout, renderer, operation);
+ }
+
+ fn on_event(
+ &mut self,
+ state: &mut Tree,
+ event: Event,
+ layout: Layout<'_>,
+ cursor: mouse::Cursor,
+ renderer: &Renderer,
+ clipboard: &mut dyn core::Clipboard,
+ shell: &mut Shell<'_, Message>,
+ viewport: &Rectangle,
+ ) -> event::Status {
+ let is_mouse_press = matches!(
+ event,
+ core::Event::Mouse(mouse::Event::ButtonPressed(_))
+ );
+
+ if let core::event::Status::Captured =
+ self.content.as_widget_mut().on_event(
+ state, event, layout, cursor, renderer, clipboard, shell,
+ viewport,
+ )
+ {
+ return event::Status::Captured;
+ }
+
+ if is_mouse_press && cursor.is_over(layout.bounds()) {
+ event::Status::Captured
+ } else {
+ event::Status::Ignored
+ }
+ }
+
+ fn mouse_interaction(
+ &self,
+ state: &core::widget::Tree,
+ layout: core::Layout<'_>,
+ cursor: core::mouse::Cursor,
+ viewport: &core::Rectangle,
+ renderer: &Renderer,
+ ) -> core::mouse::Interaction {
+ let interaction = self
+ .content
+ .as_widget()
+ .mouse_interaction(state, layout, cursor, viewport, renderer);
+
+ if interaction == mouse::Interaction::None
+ && cursor.is_over(layout.bounds())
+ {
+ mouse::Interaction::Idle
+ } else {
+ interaction
+ }
+ }
+
+ fn overlay<'b>(
+ &'b mut self,
+ state: &'b mut core::widget::Tree,
+ layout: core::Layout<'_>,
+ renderer: &Renderer,
+ translation: core::Vector,
+ ) -> Option<core::overlay::Element<'b, Message, Theme, Renderer>>
+ {
+ self.content.as_widget_mut().overlay(
+ state,
+ layout,
+ renderer,
+ translation,
+ )
+ }
+ }
+
+ Element::new(Opaque {
+ content: content.into(),
+ })
+}
+
/// Creates a new [`Scrollable`] with the provided content.
///
/// [`Scrollable`]: crate::Scrollable
diff --git a/widget/src/image/viewer.rs b/widget/src/image/viewer.rs
index 5f7bb345..75d73b19 100644
--- a/widget/src/image/viewer.rs
+++ b/widget/src/image/viewer.rs
@@ -304,7 +304,7 @@ where
} else if is_mouse_over {
mouse::Interaction::Grab
} else {
- mouse::Interaction::Idle
+ mouse::Interaction::None
}
}
diff --git a/widget/src/mouse_area.rs b/widget/src/mouse_area.rs
index 9634e477..d7235cf6 100644
--- a/widget/src/mouse_area.rs
+++ b/widget/src/mouse_area.rs
@@ -232,7 +232,7 @@ where
);
match (self.interaction, content_interaction) {
- (Some(interaction), mouse::Interaction::Idle)
+ (Some(interaction), mouse::Interaction::None)
if cursor.is_over(layout.bounds()) =>
{
interaction
diff --git a/widget/src/scrollable.rs b/widget/src/scrollable.rs
index cdc143a2..10e81cee 100644
--- a/widget/src/scrollable.rs
+++ b/widget/src/scrollable.rs
@@ -857,7 +857,7 @@ where
if (mouse_over_x_scrollbar || mouse_over_y_scrollbar)
|| state.scrollers_grabbed()
{
- mouse::Interaction::Idle
+ mouse::Interaction::None
} else {
let translation =
state.translation(self.direction, bounds, content_bounds);
diff --git a/widget/src/stack.rs b/widget/src/stack.rs
index 6e5dacd2..8a0ea2eb 100644
--- a/widget/src/stack.rs
+++ b/widget/src/stack.rs
@@ -249,7 +249,7 @@ where
state, layout, cursor, viewport, renderer,
)
})
- .find(|&interaction| interaction != mouse::Interaction::Idle)
+ .find(|&interaction| interaction != mouse::Interaction::None)
.unwrap_or_default()
}
diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs
index fc3d1c08..0f83dac3 100644
--- a/winit/src/conversion.rs
+++ b/winit/src/conversion.rs
@@ -396,7 +396,9 @@ pub fn mouse_interaction(
use mouse::Interaction;
match interaction {
- Interaction::Idle => winit::window::CursorIcon::Default,
+ Interaction::None | Interaction::Idle => {
+ winit::window::CursorIcon::Default
+ }
Interaction::Pointer => winit::window::CursorIcon::Pointer,
Interaction::Working => winit::window::CursorIcon::Progress,
Interaction::Grab => winit::window::CursorIcon::Grab,
diff --git a/winit/src/multi_window/window_manager.rs b/winit/src/multi_window/window_manager.rs
index 71c1688b..3a0c8556 100644
--- a/winit/src/multi_window/window_manager.rs
+++ b/winit/src/multi_window/window_manager.rs
@@ -60,7 +60,7 @@ where
exit_on_close_request,
surface,
renderer,
- mouse_interaction: mouse::Interaction::Idle,
+ mouse_interaction: mouse::Interaction::None,
},
);