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        bounds: RectF,
 88        _: RectF,
 89        visible_bounds: RectF,
 90        _: &mut Self::LayoutState,
 91        _: &mut Self::PaintState,
 92        cx: &mut EventContext,
 93    ) -> bool {
 94        if let Some(capture) = self.capture.as_mut() {
 95            if capture(event, bounds, cx) {
 96                return true;
 97            }
 98        }
 99
100        if self.child.dispatch_event(event, cx) {
101            true
102        } else {
103            match event {
104                Event::LeftMouseDown { position, .. } => {
105                    if let Some(callback) = self.mouse_down.as_mut() {
106                        if bounds.contains_point(*position) {
107                            return callback(cx);
108                        }
109                    }
110                    false
111                }
112                Event::RightMouseDown { position, .. } => {
113                    if let Some(callback) = self.right_mouse_down.as_mut() {
114                        if bounds.contains_point(*position) {
115                            return callback(cx);
116                        }
117                    }
118                    false
119                }
120                Event::NavigateMouseDown {
121                    position,
122                    direction,
123                    ..
124                } => {
125                    if let Some(callback) = self.navigate_mouse_down.as_mut() {
126                        if bounds.contains_point(*position) {
127                            return callback(*direction, cx);
128                        }
129                    }
130                    false
131                }
132                _ => false,
133            }
134        }
135    }
136
137    fn debug(
138        &self,
139        _: RectF,
140        _: &Self::LayoutState,
141        _: &Self::PaintState,
142        cx: &DebugContext,
143    ) -> serde_json::Value {
144        json!({
145            "type": "EventHandler",
146            "child": self.child.debug(cx),
147        })
148    }
149}