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: visible_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: visible_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}