diff options
Diffstat (limited to 'widget')
| -rw-r--r-- | widget/src/mouse_area.rs | 75 | 
1 files changed, 73 insertions, 2 deletions
| diff --git a/widget/src/mouse_area.rs b/widget/src/mouse_area.rs index 88f7d126..1487aaa5 100644 --- a/widget/src/mouse_area.rs +++ b/widget/src/mouse_area.rs @@ -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; @@ -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 FnMut(Point) -> Message>>, +    on_mouse_exit: Option<Message>,  }  impl<'a, Message, Theme, Renderer> MouseArea<'a, Message, Theme, Renderer> { @@ -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: FnMut(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 +    mouse_in_area: bool,  }  impl<'a, Message, Theme, Renderer> MouseArea<'a, Message, Theme, Renderer> { @@ -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,          }      }  } @@ -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( @@ -246,11 +278,19 @@ where  /// accordingly.  fn update<Message: Clone, Theme, Renderer>(      widget: &mut MouseArea<'_, Message, Theme, Renderer>, +    tree: &mut Tree,      event: &Event,      layout: Layout<'_>,      cursor: mouse::Cursor,      shell: &mut Shell<'_, Message>,  ) -> event::Status { +    if let Event::Mouse(mouse::Event::CursorMoved { position }) +    | Event::Touch(touch::Event::FingerMoved { id: _, position }) = event +    { +        let state: &mut State = tree.state.downcast_mut(); +        handle_mouse_move(widget, state, shell, *position, layout.bounds()) +    } +      if !cursor.is_over(layout.bounds()) {          return event::Status::Ignored;      } @@ -320,3 +360,34 @@ fn update<Message: Clone, Theme, Renderer>(      event::Status::Ignored  } + +fn handle_mouse_move<Message: Clone, Theme, Renderer>( +    widget: &mut MouseArea<'_, Message, Theme, Renderer>, +    state: &mut State, +    shell: &mut Shell<'_, Message>, +    position: Point, +    area_bounds: Rectangle, +) { +    let mouse_in_area = area_bounds.contains(position); + +    match ( +        widget.on_mouse_enter.as_mut(), +        widget.on_mouse_move.as_mut(), +        widget.on_mouse_exit.as_mut(), +    ) { +        (Some(enter_msg), _, _) if mouse_in_area && !state.mouse_in_area => { +            shell.publish(enter_msg.clone()) +        } +        (_, Some(build_move_msg), _) +            if mouse_in_area && state.mouse_in_area => +        { +            shell.publish(build_move_msg(position)) +        } +        (_, _, Some(exit_msg)) if !mouse_in_area && state.mouse_in_area => { +            shell.publish(exit_msg.clone()) +        } +        _ => {} +    } + +    state.mouse_in_area = mouse_in_area; +} | 
