Skip to content

Commit 6756594

Browse files
authored
Merge pull request #2147 from Remmirad/mouse_area_hover_events
Add mouse move events to MouseArea
2 parents 1d58d44 + 3da6afd commit 6756594

2 files changed

Lines changed: 67 additions & 3 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3232
- Texture filtering options for `Image`. [#1894](https://github.com/iced-rs/iced/pull/1894)
3333
- `default` and `shift_step` methods for `slider` widgets. [#2100](https://github.com/iced-rs/iced/pull/2100)
3434
- `Custom` variant to `command::Action`. [#2146](https://github.com/iced-rs/iced/pull/2146)
35+
- Mouse movement events for `MouseArea`. [#2147](https://github.com/iced-rs/iced/pull/2147)
3536

3637
### Changed
3738
- Enable WebGPU backend in `wgpu` by default instead of WebGL. [#2068](https://github.com/iced-rs/iced/pull/2068)

widget/src/mouse_area.rs

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
//! A container for capturing mouse events.
22
3+
use iced_renderer::core::Point;
4+
35
use crate::core::event::{self, Event};
46
use crate::core::layout;
57
use crate::core::mouse;
@@ -26,6 +28,9 @@ pub struct MouseArea<
2628
on_right_release: Option<Message>,
2729
on_middle_press: Option<Message>,
2830
on_middle_release: Option<Message>,
31+
on_mouse_enter: Option<Message>,
32+
on_mouse_move: Option<Box<dyn Fn(Point) -> Message>>,
33+
on_mouse_exit: Option<Message>,
2934
}
3035

3136
impl<'a, Message, Theme, Renderer> MouseArea<'a, Message, Theme, Renderer> {
@@ -70,12 +75,36 @@ impl<'a, Message, Theme, Renderer> MouseArea<'a, Message, Theme, Renderer> {
7075
self.on_middle_release = Some(message);
7176
self
7277
}
78+
79+
/// The message to emit when the mouse enters the area.
80+
#[must_use]
81+
pub fn on_mouse_enter(mut self, message: Message) -> Self {
82+
self.on_mouse_enter = Some(message);
83+
self
84+
}
85+
86+
/// The message to emit when the mouse moves in the area.
87+
#[must_use]
88+
pub fn on_mouse_move<F>(mut self, build_message: F) -> Self
89+
where
90+
F: Fn(Point) -> Message + 'static,
91+
{
92+
self.on_mouse_move = Some(Box::new(build_message));
93+
self
94+
}
95+
96+
/// The message to emit when the mouse exits the area.
97+
#[must_use]
98+
pub fn on_mouse_exit(mut self, message: Message) -> Self {
99+
self.on_mouse_exit = Some(message);
100+
self
101+
}
73102
}
74103

75104
/// Local state of the [`MouseArea`].
76105
#[derive(Default)]
77106
struct State {
78-
// TODO: Support on_mouse_enter and on_mouse_exit
107+
is_hovered: bool,
79108
}
80109

81110
impl<'a, Message, Theme, Renderer> MouseArea<'a, Message, Theme, Renderer> {
@@ -91,6 +120,9 @@ impl<'a, Message, Theme, Renderer> MouseArea<'a, Message, Theme, Renderer> {
91120
on_right_release: None,
92121
on_middle_press: None,
93122
on_middle_release: None,
123+
on_mouse_enter: None,
124+
on_mouse_move: None,
125+
on_mouse_exit: None,
94126
}
95127
}
96128
}
@@ -171,7 +203,7 @@ where
171203
return event::Status::Captured;
172204
}
173205

174-
update(self, &event, layout, cursor, shell)
206+
update(self, tree, event, layout, cursor, shell)
175207
}
176208

177209
fn mouse_interaction(
@@ -246,11 +278,42 @@ where
246278
/// accordingly.
247279
fn update<Message: Clone, Theme, Renderer>(
248280
widget: &mut MouseArea<'_, Message, Theme, Renderer>,
249-
event: &Event,
281+
tree: &mut Tree,
282+
event: Event,
250283
layout: Layout<'_>,
251284
cursor: mouse::Cursor,
252285
shell: &mut Shell<'_, Message>,
253286
) -> event::Status {
287+
if let Event::Mouse(mouse::Event::CursorMoved { .. })
288+
| Event::Touch(touch::Event::FingerMoved { .. }) = event
289+
{
290+
let state: &mut State = tree.state.downcast_mut();
291+
292+
let was_hovered = state.is_hovered;
293+
state.is_hovered = cursor.is_over(layout.bounds());
294+
295+
match (
296+
widget.on_mouse_enter.as_ref(),
297+
widget.on_mouse_move.as_ref(),
298+
widget.on_mouse_exit.as_ref(),
299+
) {
300+
(Some(on_mouse_enter), _, _)
301+
if state.is_hovered && !was_hovered =>
302+
{
303+
shell.publish(on_mouse_enter.clone());
304+
}
305+
(_, Some(on_mouse_move), _) if state.is_hovered => {
306+
if let Some(position) = cursor.position_in(layout.bounds()) {
307+
shell.publish(on_mouse_move(position));
308+
}
309+
}
310+
(_, _, Some(on_mouse_exit)) if !state.is_hovered && was_hovered => {
311+
shell.publish(on_mouse_exit.clone());
312+
}
313+
_ => {}
314+
}
315+
}
316+
254317
if !cursor.is_over(layout.bounds()) {
255318
return event::Status::Ignored;
256319
}

0 commit comments

Comments
 (0)