event_handler.rs

  1use crate::{
  2    geometry::vector::Vector2F, presenter::MeasurementContext, CursorRegion, DebugContext, Element,
  3    ElementBox, Event, EventContext, LayoutContext, MouseButton, MouseButtonEvent, MouseRegion,
  4    NavigationDirection, PaintContext, SizeConstraint,
  5};
  6use pathfinder_geometry::rect::RectF;
  7use serde_json::json;
  8use std::{any::TypeId, ops::Range};
  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::handle_all(
 86                cx.current_view_id(),
 87                Some(discriminant),
 88                visible_bounds,
 89            ));
 90            cx.scene.pop_stacking_context();
 91        }
 92        self.child.paint(bounds.origin(), visible_bounds, cx);
 93    }
 94
 95    fn dispatch_event(
 96        &mut self,
 97        event: &Event,
 98        _: RectF,
 99        visible_bounds: RectF,
100        _: &mut Self::LayoutState,
101        _: &mut Self::PaintState,
102        cx: &mut EventContext,
103    ) -> bool {
104        if self.capture_all.is_some() {
105            return true;
106        }
107
108        if self.child.dispatch_event(event, cx) {
109            true
110        } else {
111            match event {
112                Event::MouseDown(MouseButtonEvent {
113                    button: MouseButton::Left,
114                    position,
115                    ..
116                }) => {
117                    if let Some(callback) = self.mouse_down.as_mut() {
118                        if visible_bounds.contains_point(*position) {
119                            return callback(cx);
120                        }
121                    }
122                    false
123                }
124                Event::MouseDown(MouseButtonEvent {
125                    button: MouseButton::Right,
126                    position,
127                    ..
128                }) => {
129                    if let Some(callback) = self.right_mouse_down.as_mut() {
130                        if visible_bounds.contains_point(*position) {
131                            return callback(cx);
132                        }
133                    }
134                    false
135                }
136                Event::MouseDown(MouseButtonEvent {
137                    button: MouseButton::Navigate(direction),
138                    position,
139                    ..
140                }) => {
141                    if let Some(callback) = self.navigate_mouse_down.as_mut() {
142                        if visible_bounds.contains_point(*position) {
143                            return callback(*direction, cx);
144                        }
145                    }
146                    false
147                }
148                _ => false,
149            }
150        }
151    }
152
153    fn rect_for_text_range(
154        &self,
155        range_utf16: Range<usize>,
156        _: RectF,
157        _: RectF,
158        _: &Self::LayoutState,
159        _: &Self::PaintState,
160        cx: &MeasurementContext,
161    ) -> Option<RectF> {
162        self.child.rect_for_text_range(range_utf16, cx)
163    }
164
165    fn debug(
166        &self,
167        _: RectF,
168        _: &Self::LayoutState,
169        _: &Self::PaintState,
170        cx: &DebugContext,
171    ) -> serde_json::Value {
172        json!({
173            "type": "EventHandler",
174            "child": self.child.debug(cx),
175        })
176    }
177}