332 lines · 9.4 KB · Rust
RawDownload
use super::Padding;use crate::{    geometry::{        rect::RectF,        vector::{vec2f, Vector2F},    },    platform::CursorStyle,    platform::MouseButton,    scene::{        CursorRegion, HandlerSet, MouseClick, MouseClickOut, MouseDown, MouseDownOut, MouseDrag,        MouseHover, MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut,    },    AnyElement, Element, EventContext, LayoutContext, MouseRegion, MouseState, PaintContext,    SceneBuilder, SizeConstraint, TypeTag, ViewContext,};use serde_json::json;use std::ops::Range; pub struct MouseEventHandler<V: 'static> {    child: AnyElement<V>,    region_id: usize,    cursor_style: Option<CursorStyle>,    handlers: HandlerSet,    hoverable: bool,    notify_on_hover: bool,    notify_on_click: bool,    above: bool,    padding: Padding,    tag: TypeTag,} /// Element which provides a render_child callback with a MouseState and paints a mouse/// region under (or above) it for easy mouse event handling.impl<V: 'static> MouseEventHandler<V> {    pub fn for_child<Tag: 'static>(child: impl Element<V>, region_id: usize) -> Self {        Self {            child: child.into_any(),            region_id,            cursor_style: None,            handlers: Default::default(),            notify_on_hover: false,            notify_on_click: false,            hoverable: false,            above: false,            padding: Default::default(),            tag: TypeTag::new::<Tag>(),        }    }     pub fn new<Tag: 'static, E>(        region_id: usize,        cx: &mut ViewContext<V>,        render_child: impl FnOnce(&mut MouseState, &mut ViewContext<V>) -> E,    ) -> Self    where        E: Element<V>,    {        let mut mouse_state = cx.mouse_state_dynamic(TypeTag::new::<Tag>(), region_id);        let child = render_child(&mut mouse_state, cx).into_any();        let notify_on_hover = mouse_state.accessed_hovered();        let notify_on_click = mouse_state.accessed_clicked();        Self {            child,            region_id,            cursor_style: None,            handlers: Default::default(),            notify_on_hover,            notify_on_click,            hoverable: true,            above: false,            padding: Default::default(),            tag: TypeTag::new::<Tag>(),        }    }     pub fn new_dynamic(        tag: TypeTag,        region_id: usize,        cx: &mut ViewContext<V>,        render_child: impl FnOnce(&mut MouseState, &mut ViewContext<V>) -> AnyElement<V>,    ) -> Self {        let mut mouse_state = cx.mouse_state_dynamic(tag, region_id);        let child = render_child(&mut mouse_state, cx);        let notify_on_hover = mouse_state.accessed_hovered();        let notify_on_click = mouse_state.accessed_clicked();        Self {            child,            region_id,            cursor_style: None,            handlers: Default::default(),            notify_on_hover,            notify_on_click,            hoverable: true,            above: false,            padding: Default::default(),            tag,        }    }     /// Modifies the MouseEventHandler to render the MouseRegion above the child element. Useful    /// for drag and drop handling and similar events which should be captured before the child    /// gets the opportunity    pub fn above<Tag: 'static, D>(        region_id: usize,        cx: &mut ViewContext<V>,        render_child: impl FnOnce(&mut MouseState, &mut ViewContext<V>) -> D,    ) -> Self    where        D: Element<V>,    {        let mut handler = Self::new::<Tag, _>(region_id, cx, render_child);        handler.above = true;        handler    }     pub fn with_cursor_style(mut self, cursor: CursorStyle) -> Self {        self.cursor_style = Some(cursor);        self    }     pub fn capture_all(mut self) -> Self {        self.handlers = HandlerSet::capture_all();        self    }     pub fn on_move(        mut self,        handler: impl Fn(MouseMove, &mut V, &mut EventContext<V>) + 'static,    ) -> Self {        self.handlers = self.handlers.on_move(handler);        self    }     pub fn on_move_out(        mut self,        handler: impl Fn(MouseMoveOut, &mut V, &mut EventContext<V>) + 'static,    ) -> Self {        self.handlers = self.handlers.on_move_out(handler);        self    }     pub fn on_down(        mut self,        button: MouseButton,        handler: impl Fn(MouseDown, &mut V, &mut EventContext<V>) + 'static,    ) -> Self {        self.handlers = self.handlers.on_down(button, handler);        self    }     pub fn on_up(        mut self,        button: MouseButton,        handler: impl Fn(MouseUp, &mut V, &mut EventContext<V>) + 'static,    ) -> Self {        self.handlers = self.handlers.on_up(button, handler);        self    }     pub fn on_click(        mut self,        button: MouseButton,        handler: impl Fn(MouseClick, &mut V, &mut EventContext<V>) + 'static,    ) -> Self {        self.handlers = self.handlers.on_click(button, handler);        self    }     pub fn on_click_out(        mut self,        button: MouseButton,        handler: impl Fn(MouseClickOut, &mut V, &mut EventContext<V>) + 'static,    ) -> Self {        self.handlers = self.handlers.on_click_out(button, handler);        self    }     pub fn on_down_out(        mut self,        button: MouseButton,        handler: impl Fn(MouseDownOut, &mut V, &mut EventContext<V>) + 'static,    ) -> Self {        self.handlers = self.handlers.on_down_out(button, handler);        self    }     pub fn on_up_out(        mut self,        button: MouseButton,        handler: impl Fn(MouseUpOut, &mut V, &mut EventContext<V>) + 'static,    ) -> Self {        self.handlers = self.handlers.on_up_out(button, handler);        self    }     pub fn on_drag(        mut self,        button: MouseButton,        handler: impl Fn(MouseDrag, &mut V, &mut EventContext<V>) + 'static,    ) -> Self {        self.handlers = self.handlers.on_drag(button, handler);        self    }     pub fn on_hover(        mut self,        handler: impl Fn(MouseHover, &mut V, &mut EventContext<V>) + 'static,    ) -> Self {        self.handlers = self.handlers.on_hover(handler);        self    }     pub fn on_scroll(        mut self,        handler: impl Fn(MouseScrollWheel, &mut V, &mut EventContext<V>) + 'static,    ) -> Self {        self.handlers = self.handlers.on_scroll(handler);        self    }     pub fn with_hoverable(mut self, is_hoverable: bool) -> Self {        self.hoverable = is_hoverable;        self    }     pub fn with_padding(mut self, padding: Padding) -> Self {        self.padding = padding;        self    }     fn hit_bounds(&self, bounds: RectF) -> RectF {        RectF::from_points(            bounds.origin() - vec2f(self.padding.left, self.padding.top),            bounds.lower_right() + vec2f(self.padding.right, self.padding.bottom),        )        .round_out()    }     fn paint_regions(        &self,        scene: &mut SceneBuilder,        bounds: RectF,        visible_bounds: RectF,        cx: &mut ViewContext<V>,    ) {        let visible_bounds = visible_bounds.intersection(bounds).unwrap_or_default();        let hit_bounds = self.hit_bounds(visible_bounds);         if let Some(style) = self.cursor_style {            scene.push_cursor_region(CursorRegion {                bounds: hit_bounds,                style,            });        }        scene.push_mouse_region(            MouseRegion::from_handlers(                self.tag,                cx.view_id(),                self.region_id,                hit_bounds,                self.handlers.clone(),            )            .with_hoverable(self.hoverable)            .with_notify_on_hover(self.notify_on_hover)            .with_notify_on_click(self.notify_on_click),        );    }} impl<V: 'static> Element<V> for MouseEventHandler<V> {    type LayoutState = ();    type PaintState = ();     fn layout(        &mut self,        constraint: SizeConstraint,        view: &mut V,        cx: &mut LayoutContext<V>,    ) -> (Vector2F, Self::LayoutState) {        (self.child.layout(constraint, view, cx), ())    }     fn paint(        &mut self,        scene: &mut SceneBuilder,        bounds: RectF,        visible_bounds: RectF,        _: &mut Self::LayoutState,        view: &mut V,        cx: &mut PaintContext<V>,    ) -> Self::PaintState {        if self.above {            self.child                .paint(scene, bounds.origin(), visible_bounds, view, cx);             scene.paint_layer(None, |scene| {                self.paint_regions(scene, bounds, visible_bounds, cx);            });        } else {            self.paint_regions(scene, bounds, visible_bounds, cx);            self.child                .paint(scene, bounds.origin(), visible_bounds, view, cx);        }    }     fn rect_for_text_range(        &self,        range_utf16: Range<usize>,        _: RectF,        _: RectF,        _: &Self::LayoutState,        _: &Self::PaintState,        view: &V,        cx: &ViewContext<V>,    ) -> Option<RectF> {        self.child.rect_for_text_range(range_utf16, view, cx)    }     fn debug(        &self,        _: RectF,        _: &Self::LayoutState,        _: &Self::PaintState,        view: &V,        cx: &ViewContext<V>,    ) -> serde_json::Value {        json!({            "type": "MouseEventHandler",            "child": self.child.debug(view, cx),        })    }}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t