event_handler.rs

  1use crate::{
  2    geometry::vector::Vector2F, CursorRegion, DebugContext, Element, ElementBox, Event,
  3    EventContext, LayoutContext, MouseRegion, NavigationDirection, PaintContext, SizeConstraint,
  4};
  5use pathfinder_geometry::rect::RectF;
  6use serde_json::json;
  7use std::{any::TypeId, rc::Rc};
  8
  9pub struct EventHandler {
 10    child: ElementBox,
 11    capture_all: Option<(TypeId, usize)>,
 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_all: 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_all<T: 'static>(mut self, id: usize) -> Self {
 53        self.capture_all = Some((TypeId::of::<T>(), id));
 54        self
 55    }
 56}
 57
 58impl Element for EventHandler {
 59    type LayoutState = ();
 60    type PaintState = ();
 61
 62    fn layout(
 63        &mut self,
 64        constraint: SizeConstraint,
 65        cx: &mut LayoutContext,
 66    ) -> (Vector2F, Self::LayoutState) {
 67        let size = self.child.layout(constraint, cx);
 68        (size, ())
 69    }
 70
 71    fn paint(
 72        &mut self,
 73        bounds: RectF,
 74        visible_bounds: RectF,
 75        _: &mut Self::LayoutState,
 76        cx: &mut PaintContext,
 77    ) -> Self::PaintState {
 78        if let Some(discriminant) = self.capture_all {
 79            cx.scene.push_stacking_context(None);
 80            cx.scene.push_cursor_region(CursorRegion {
 81                bounds,
 82                style: Default::default(),
 83            });
 84            cx.scene.push_mouse_region(MouseRegion {
 85                view_id: cx.current_view_id(),
 86                discriminant: Some(discriminant),
 87                bounds,
 88                hover: Some(Rc::new(|_, _, _| {})),
 89                mouse_down: Some(Rc::new(|_, _| {})),
 90                click: Some(Rc::new(|_, _, _| {})),
 91                right_mouse_down: Some(Rc::new(|_, _| {})),
 92                right_click: Some(Rc::new(|_, _, _| {})),
 93                drag: Some(Rc::new(|_, _| {})),
 94                mouse_down_out: Some(Rc::new(|_, _| {})),
 95                right_mouse_down_out: Some(Rc::new(|_, _| {})),
 96            });
 97            cx.scene.pop_stacking_context();
 98        }
 99        self.child.paint(bounds.origin(), visible_bounds, cx);
100    }
101
102    fn dispatch_event(
103        &mut self,
104        event: &Event,
105        _: RectF,
106        visible_bounds: RectF,
107        _: &mut Self::LayoutState,
108        _: &mut Self::PaintState,
109        cx: &mut EventContext,
110    ) -> bool {
111        if self.capture_all.is_some() {
112            return true;
113        }
114
115        if self.child.dispatch_event(event, cx) {
116            true
117        } else {
118            match event {
119                Event::LeftMouseDown { position, .. } => {
120                    if let Some(callback) = self.mouse_down.as_mut() {
121                        if visible_bounds.contains_point(*position) {
122                            return callback(cx);
123                        }
124                    }
125                    false
126                }
127                Event::RightMouseDown { position, .. } => {
128                    if let Some(callback) = self.right_mouse_down.as_mut() {
129                        if visible_bounds.contains_point(*position) {
130                            return callback(cx);
131                        }
132                    }
133                    false
134                }
135                Event::NavigateMouseDown {
136                    position,
137                    direction,
138                    ..
139                } => {
140                    if let Some(callback) = self.navigate_mouse_down.as_mut() {
141                        if visible_bounds.contains_point(*position) {
142                            return callback(*direction, cx);
143                        }
144                    }
145                    false
146                }
147                _ => false,
148            }
149        }
150    }
151
152    fn debug(
153        &self,
154        _: RectF,
155        _: &Self::LayoutState,
156        _: &Self::PaintState,
157        cx: &DebugContext,
158    ) -> serde_json::Value {
159        json!({
160            "type": "EventHandler",
161            "child": self.child.debug(cx),
162        })
163    }
164}