veloren_voxygen/ui/ice/widget/
mouse_detector.rs

1use iced::{
2    Clipboard, Element, Event, Hasher, Layout, Length, Point, Rectangle, Size, Widget, layout,
3    mouse,
4};
5use std::hash::Hash;
6
7#[derive(Debug, Default)]
8pub struct State {
9    mouse_over: bool,
10}
11impl State {
12    pub fn mouse_over(&self) -> bool { self.mouse_over }
13}
14
15#[derive(Debug)]
16pub struct MouseDetector<'a> {
17    width: Length,
18    height: Length,
19    state: &'a mut State,
20}
21
22impl<'a> MouseDetector<'a> {
23    pub fn new(state: &'a mut State, width: Length, height: Length) -> Self {
24        Self {
25            width,
26            height,
27            state,
28        }
29    }
30}
31
32impl<M, R> Widget<M, R> for MouseDetector<'_>
33where
34    R: Renderer,
35{
36    fn width(&self) -> Length { self.width }
37
38    fn height(&self) -> Length { self.height }
39
40    fn layout(&self, _renderer: &R, limits: &layout::Limits) -> layout::Node {
41        let limits = limits.width(self.width).height(self.height);
42
43        layout::Node::new(limits.resolve(Size::ZERO))
44    }
45
46    fn draw(
47        &self,
48        renderer: &mut R,
49        _defaults: &R::Defaults,
50        layout: Layout<'_>,
51        _cursor_position: Point,
52        _viewport: &Rectangle,
53    ) -> R::Output {
54        renderer.draw(layout.bounds())
55    }
56
57    fn hash_layout(&self, state: &mut Hasher) {
58        struct Marker;
59        std::any::TypeId::of::<Marker>().hash(state);
60
61        self.width.hash(state);
62        self.height.hash(state);
63    }
64
65    fn on_event(
66        &mut self,
67        event: Event,
68        layout: Layout<'_>,
69        _cursor_position: Point,
70        _renderer: &R,
71        _clipboard: &mut dyn Clipboard,
72        _messages: &mut Vec<M>,
73    ) -> iced::event::Status {
74        if let Event::Mouse(mouse::Event::CursorMoved {
75            position: Point { x, y },
76        }) = event
77        {
78            let bounds = layout.bounds();
79            let mouse_over = x > bounds.x
80                && x < bounds.x + bounds.width
81                && y > bounds.y
82                && y < bounds.y + bounds.height;
83            if mouse_over != self.state.mouse_over {
84                self.state.mouse_over = mouse_over;
85            }
86        }
87
88        iced::event::Status::Ignored
89    }
90}
91
92pub trait Renderer: iced::Renderer {
93    fn draw(&mut self, bounds: Rectangle) -> Self::Output;
94}
95
96impl<'a, M, R> From<MouseDetector<'a>> for Element<'a, M, R>
97where
98    R: Renderer,
99    M: 'a,
100{
101    fn from(mouse_detector: MouseDetector<'a>) -> Element<'a, M, R> { Element::new(mouse_detector) }
102}