event_handler.rs

  1use crate::{
  2    geometry::vector::Vector2F, CursorRegion, DebugContext, Element, ElementBox, Event,
  3    EventContext, LayoutContext, MouseButton, MouseEvent, MouseRegion, NavigationDirection,
  4    PaintContext, SizeConstraint,
  5};
  6use pathfinder_geometry::rect::RectF;
  7use serde_json::json;
  8use std::{any::TypeId, rc::Rc};
  9
 10pub struct EventHandler {
 11    child: ElementBox,
 12    capture_all: Option<(TypeId, usize)>,
 13    mouse_down: Option<Box<dyn FnMut(&mut EventContext) -> bool>>,
 14    right_mouse_down: Option<Box<dyn FnMut(&mut EventContext) -> bool>>,
 15    navigate_mouse_down: Option<Box<dyn FnMut(NavigationDirection, &mut EventContext) -> bool>>,
 16}
 17
 18impl EventHandler {
 19    pub fn new(child: ElementBox) -> Self {
 20        Self {
 21            child,
 22            capture_all: None,
 23            mouse_down: None,
 24            right_mouse_down: None,
 25            navigate_mouse_down: None,
 26        }
 27    }
 28
 29    pub fn on_mouse_down<F>(mut self, callback: F) -> Self
 30    where
 31        F: 'static + FnMut(&mut EventContext) -> bool,
 32    {
 33        self.mouse_down = Some(Box::new(callback));
 34        self
 35    }
 36
 37    pub fn on_right_mouse_down<F>(mut self, callback: F) -> Self
 38    where
 39        F: 'static + FnMut(&mut EventContext) -> bool,
 40    {
 41        self.right_mouse_down = Some(Box::new(callback));
 42        self
 43    }
 44
 45    pub fn on_navigate_mouse_down<F>(mut self, callback: F) -> Self
 46    where
 47        F: 'static + FnMut(NavigationDirection, &mut EventContext) -> bool,
 48    {
 49        self.navigate_mouse_down = Some(Box::new(callback));
 50        self
 51    }
 52
 53    pub fn capture_all<T: 'static>(mut self, id: usize) -> Self {
 54        self.capture_all = Some((TypeId::of::<T>(), id));
 55        self
 56    }
 57}
 58
 59impl Element for EventHandler {
 60    type LayoutState = ();
 61    type PaintState = ();
 62
 63    fn layout(
 64        &mut self,
 65        constraint: SizeConstraint,
 66        cx: &mut LayoutContext,
 67    ) -> (Vector2F, Self::LayoutState) {
 68        let size = self.child.layout(constraint, cx);
 69        (size, ())
 70    }
 71
 72    fn paint(
 73        &mut self,
 74        bounds: RectF,
 75        visible_bounds: RectF,
 76        _: &mut Self::LayoutState,
 77        cx: &mut PaintContext,
 78    ) -> Self::PaintState {
 79        if let Some(discriminant) = self.capture_all {
 80            cx.scene.push_stacking_context(None);
 81            cx.scene.push_cursor_region(CursorRegion {
 82                bounds: visible_bounds,
 83                style: Default::default(),
 84            });
 85            cx.scene.push_mouse_region(MouseRegion {
 86                view_id: cx.current_view_id(),
 87                discriminant: Some(discriminant),
 88                bounds: visible_bounds,
 89                hover: Some(Rc::new(|_, _, _| {})),
 90                mouse_down: Some(Rc::new(|_, _| {})),
 91                click: Some(Rc::new(|_, _, _| {})),
 92                right_mouse_down: Some(Rc::new(|_, _| {})),
 93                right_click: Some(Rc::new(|_, _, _| {})),
 94                drag: Some(Rc::new(|_, _, _| {})),
 95                mouse_down_out: Some(Rc::new(|_, _| {})),
 96                right_mouse_down_out: Some(Rc::new(|_, _| {})),
 97            });
 98            cx.scene.pop_stacking_context();
 99        }
100        self.child.paint(bounds.origin(), visible_bounds, cx);
101    }
102
103    fn dispatch_event(
104        &mut self,
105        event: &Event,
106        _: RectF,
107        visible_bounds: RectF,
108        _: &mut Self::LayoutState,
109        _: &mut Self::PaintState,
110        cx: &mut EventContext,
111    ) -> bool {
112        if self.capture_all.is_some() {
113            return true;
114        }
115
116        if self.child.dispatch_event(event, cx) {
117            true
118        } else {
119            match event {
120                Event::MouseDown(MouseEvent {
121                    button: MouseButton::Left,
122                    position,
123                    ..
124                }) => {
125                    if let Some(callback) = self.mouse_down.as_mut() {
126                        if visible_bounds.contains_point(*position) {
127                            return callback(cx);
128                        }
129                    }
130                    false
131                }
132                Event::MouseDown(MouseEvent {
133                    button: MouseButton::Right,
134                    position,
135                    ..
136                }) => {
137                    if let Some(callback) = self.right_mouse_down.as_mut() {
138                        if visible_bounds.contains_point(*position) {
139                            return callback(cx);
140                        }
141                    }
142                    false
143                }
144                Event::MouseDown(MouseEvent {
145                    button: MouseButton::Navigate(direction),
146                    position,
147                    ..
148                }) => {
149                    if let Some(callback) = self.navigate_mouse_down.as_mut() {
150                        if visible_bounds.contains_point(*position) {
151                            return callback(*direction, cx);
152                        }
153                    }
154                    false
155                }
156                _ => false,
157            }
158        }
159    }
160
161    fn debug(
162        &self,
163        _: RectF,
164        _: &Self::LayoutState,
165        _: &Self::PaintState,
166        cx: &DebugContext,
167    ) -> serde_json::Value {
168        json!({
169            "type": "EventHandler",
170            "child": self.child.debug(cx),
171        })
172    }
173}