Skip to content

Commit

Permalink
Merge pull request #2147 from Remmirad/mouse_area_hover_events
Browse files Browse the repository at this point in the history
Add mouse move events to MouseArea
  • Loading branch information
hecrj committed Feb 3, 2024
2 parents 1d58d44 + 3da6afd commit 6756594
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 3 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Texture filtering options for `Image`. [#1894](https://github.com/iced-rs/iced/pull/1894)
- `default` and `shift_step` methods for `slider` widgets. [#2100](https://github.com/iced-rs/iced/pull/2100)
- `Custom` variant to `command::Action`. [#2146](https://github.com/iced-rs/iced/pull/2146)
- Mouse movement events for `MouseArea`. [#2147](https://github.com/iced-rs/iced/pull/2147)

### Changed
- Enable WebGPU backend in `wgpu` by default instead of WebGL. [#2068](https://github.com/iced-rs/iced/pull/2068)
Expand Down
69 changes: 66 additions & 3 deletions widget/src/mouse_area.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! A container for capturing mouse events.

use iced_renderer::core::Point;

use crate::core::event::{self, Event};
use crate::core::layout;
use crate::core::mouse;
Expand All @@ -26,6 +28,9 @@ pub struct MouseArea<
on_right_release: Option<Message>,
on_middle_press: Option<Message>,
on_middle_release: Option<Message>,
on_mouse_enter: Option<Message>,
on_mouse_move: Option<Box<dyn Fn(Point) -> Message>>,
on_mouse_exit: Option<Message>,
}

impl<'a, Message, Theme, Renderer> MouseArea<'a, Message, Theme, Renderer> {
Expand Down Expand Up @@ -70,12 +75,36 @@ impl<'a, Message, Theme, Renderer> MouseArea<'a, Message, Theme, Renderer> {
self.on_middle_release = Some(message);
self
}

/// The message to emit when the mouse enters the area.
#[must_use]
pub fn on_mouse_enter(mut self, message: Message) -> Self {
self.on_mouse_enter = Some(message);
self
}

/// The message to emit when the mouse moves in the area.
#[must_use]
pub fn on_mouse_move<F>(mut self, build_message: F) -> Self
where
F: Fn(Point) -> Message + 'static,
{
self.on_mouse_move = Some(Box::new(build_message));
self
}

/// The message to emit when the mouse exits the area.
#[must_use]
pub fn on_mouse_exit(mut self, message: Message) -> Self {
self.on_mouse_exit = Some(message);
self
}
}

/// Local state of the [`MouseArea`].
#[derive(Default)]
struct State {
// TODO: Support on_mouse_enter and on_mouse_exit
is_hovered: bool,
}

impl<'a, Message, Theme, Renderer> MouseArea<'a, Message, Theme, Renderer> {
Expand All @@ -91,6 +120,9 @@ impl<'a, Message, Theme, Renderer> MouseArea<'a, Message, Theme, Renderer> {
on_right_release: None,
on_middle_press: None,
on_middle_release: None,
on_mouse_enter: None,
on_mouse_move: None,
on_mouse_exit: None,
}
}
}
Expand Down Expand Up @@ -171,7 +203,7 @@ where
return event::Status::Captured;
}

update(self, &event, layout, cursor, shell)
update(self, tree, event, layout, cursor, shell)
}

fn mouse_interaction(
Expand Down Expand Up @@ -246,11 +278,42 @@ where
/// accordingly.
fn update<Message: Clone, Theme, Renderer>(
widget: &mut MouseArea<'_, Message, Theme, Renderer>,
event: &Event,
tree: &mut Tree,
event: Event,
layout: Layout<'_>,
cursor: mouse::Cursor,
shell: &mut Shell<'_, Message>,
) -> event::Status {
if let Event::Mouse(mouse::Event::CursorMoved { .. })
| Event::Touch(touch::Event::FingerMoved { .. }) = event
{
let state: &mut State = tree.state.downcast_mut();

let was_hovered = state.is_hovered;
state.is_hovered = cursor.is_over(layout.bounds());

match (
widget.on_mouse_enter.as_ref(),
widget.on_mouse_move.as_ref(),
widget.on_mouse_exit.as_ref(),
) {
(Some(on_mouse_enter), _, _)
if state.is_hovered && !was_hovered =>
{
shell.publish(on_mouse_enter.clone());
}
(_, Some(on_mouse_move), _) if state.is_hovered => {
if let Some(position) = cursor.position_in(layout.bounds()) {
shell.publish(on_mouse_move(position));
}
}
(_, _, Some(on_mouse_exit)) if !state.is_hovered && was_hovered => {
shell.publish(on_mouse_exit.clone());
}
_ => {}
}
}

if !cursor.is_over(layout.bounds()) {
return event::Status::Ignored;
}
Expand Down

0 comments on commit 6756594

Please sign in to comment.