1use pathfinder_geometry::rect::RectF;
2use serde_json::json;
3
4use crate::{
5 geometry::vector::Vector2F, DebugContext, Element, ElementBox, Event, EventContext,
6 LayoutContext, NavigationDirection, PaintContext, SizeConstraint,
7};
8
9pub struct EventHandler {
10 child: ElementBox,
11 capture: Option<Box<dyn FnMut(&Event, RectF, &mut EventContext) -> bool>>,
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: 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<F>(mut self, callback: F) -> Self
53 where
54 F: 'static + FnMut(&Event, RectF, &mut EventContext) -> bool,
55 {
56 self.capture = Some(Box::new(callback));
57 self
58 }
59}
60
61impl Element for EventHandler {
62 type LayoutState = ();
63 type PaintState = ();
64
65 fn layout(
66 &mut self,
67 constraint: SizeConstraint,
68 cx: &mut LayoutContext,
69 ) -> (Vector2F, Self::LayoutState) {
70 let size = self.child.layout(constraint, cx);
71 (size, ())
72 }
73
74 fn paint(
75 &mut self,
76 bounds: RectF,
77 visible_bounds: RectF,
78 _: &mut Self::LayoutState,
79 cx: &mut PaintContext,
80 ) -> Self::PaintState {
81 self.child.paint(bounds.origin(), visible_bounds, cx);
82 }
83
84 fn dispatch_event(
85 &mut self,
86 event: &Event,
87 bounds: RectF,
88 _: &mut Self::LayoutState,
89 _: &mut Self::PaintState,
90 cx: &mut EventContext,
91 ) -> bool {
92 if let Some(capture) = self.capture.as_mut() {
93 if capture(event, bounds, cx) {
94 return true;
95 }
96 }
97
98 if self.child.dispatch_event(event, cx) {
99 true
100 } else {
101 match event {
102 Event::LeftMouseDown { position, .. } => {
103 if let Some(callback) = self.mouse_down.as_mut() {
104 if bounds.contains_point(*position) {
105 return callback(cx);
106 }
107 }
108 false
109 }
110 Event::RightMouseDown { position, .. } => {
111 if let Some(callback) = self.right_mouse_down.as_mut() {
112 if bounds.contains_point(*position) {
113 return callback(cx);
114 }
115 }
116 false
117 }
118 Event::NavigateMouseDown {
119 position,
120 direction,
121 ..
122 } => {
123 if let Some(callback) = self.navigate_mouse_down.as_mut() {
124 if bounds.contains_point(*position) {
125 return callback(*direction, cx);
126 }
127 }
128 false
129 }
130 _ => false,
131 }
132 }
133 }
134
135 fn debug(
136 &self,
137 _: RectF,
138 _: &Self::LayoutState,
139 _: &Self::PaintState,
140 cx: &DebugContext,
141 ) -> serde_json::Value {
142 json!({
143 "type": "EventHandler",
144 "child": self.child.debug(cx),
145 })
146 }
147}