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}