event_handler.rs

  1use pathfinder_geometry::rect::RectF;
  2use serde_json::json;
  3
  4use crate::{
  5    geometry::vector::Vector2F, DebugContext, Element, ElementBox, Event, EventContext,
  6    LayoutContext, NavigationDirection, PaintContext, SizeConstraint,
  7};
  8
  9pub struct EventHandler {
 10    child: ElementBox,
 11    capture: Option<Box<dyn FnMut(&Event, RectF, &mut EventContext) -> bool>>,
 12    mouse_down: Option<Box<dyn FnMut(&mut EventContext) -> bool>>,
 13    right_mouse_down: Option<Box<dyn FnMut(&mut EventContext) -> bool>>,
 14    navigate_mouse_down: Option<Box<dyn FnMut(NavigationDirection, &mut EventContext) -> bool>>,
 15}
 16
 17impl EventHandler {
 18    pub fn new(child: ElementBox) -> Self {
 19        Self {
 20            child,
 21            capture: None,
 22            mouse_down: None,
 23            right_mouse_down: None,
 24            navigate_mouse_down: None,
 25        }
 26    }
 27
 28    pub fn on_mouse_down<F>(mut self, callback: F) -> Self
 29    where
 30        F: 'static + FnMut(&mut EventContext) -> bool,
 31    {
 32        self.mouse_down = Some(Box::new(callback));
 33        self
 34    }
 35
 36    pub fn on_right_mouse_down<F>(mut self, callback: F) -> Self
 37    where
 38        F: 'static + FnMut(&mut EventContext) -> bool,
 39    {
 40        self.right_mouse_down = Some(Box::new(callback));
 41        self
 42    }
 43
 44    pub fn on_navigate_mouse_down<F>(mut self, callback: F) -> Self
 45    where
 46        F: 'static + FnMut(NavigationDirection, &mut EventContext) -> bool,
 47    {
 48        self.navigate_mouse_down = Some(Box::new(callback));
 49        self
 50    }
 51
 52    pub fn capture<F>(mut self, callback: F) -> Self
 53    where
 54        F: 'static + FnMut(&Event, RectF, &mut EventContext) -> bool,
 55    {
 56        self.capture = Some(Box::new(callback));
 57        self
 58    }
 59}
 60
 61impl Element for EventHandler {
 62    type LayoutState = ();
 63    type PaintState = ();
 64
 65    fn layout(
 66        &mut self,
 67        constraint: SizeConstraint,
 68        cx: &mut LayoutContext,
 69    ) -> (Vector2F, Self::LayoutState) {
 70        let size = self.child.layout(constraint, cx);
 71        (size, ())
 72    }
 73
 74    fn paint(
 75        &mut self,
 76        bounds: RectF,
 77        visible_bounds: RectF,
 78        _: &mut Self::LayoutState,
 79        cx: &mut PaintContext,
 80    ) -> Self::PaintState {
 81        self.child.paint(bounds.origin(), visible_bounds, cx);
 82    }
 83
 84    fn dispatch_event(
 85        &mut self,
 86        event: &Event,
 87        _: RectF,
 88        visible_bounds: RectF,
 89        _: &mut Self::LayoutState,
 90        _: &mut Self::PaintState,
 91        cx: &mut EventContext,
 92    ) -> bool {
 93        if let Some(capture) = self.capture.as_mut() {
 94            if capture(event, visible_bounds, cx) {
 95                return true;
 96            }
 97        }
 98
 99        if self.child.dispatch_event(event, cx) {
100            true
101        } else {
102            match event {
103                Event::LeftMouseDown { position, .. } => {
104                    if let Some(callback) = self.mouse_down.as_mut() {
105                        if visible_bounds.contains_point(*position) {
106                            return callback(cx);
107                        }
108                    }
109                    false
110                }
111                Event::RightMouseDown { position, .. } => {
112                    if let Some(callback) = self.right_mouse_down.as_mut() {
113                        if visible_bounds.contains_point(*position) {
114                            return callback(cx);
115                        }
116                    }
117                    false
118                }
119                Event::NavigateMouseDown {
120                    position,
121                    direction,
122                    ..
123                } => {
124                    if let Some(callback) = self.navigate_mouse_down.as_mut() {
125                        if visible_bounds.contains_point(*position) {
126                            return callback(*direction, cx);
127                        }
128                    }
129                    false
130                }
131                _ => false,
132            }
133        }
134    }
135
136    fn debug(
137        &self,
138        _: RectF,
139        _: &Self::LayoutState,
140        _: &Self::PaintState,
141        cx: &DebugContext,
142    ) -> serde_json::Value {
143        json!({
144            "type": "EventHandler",
145            "child": self.child.debug(cx),
146        })
147    }
148}