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 _: RectF,
88 visible_bounds: RectF,
89 _: &mut Self::LayoutState,
90 _: &mut Self::PaintState,
91 cx: &mut EventContext,
92 ) -> bool {
93 if let Some(capture) = self.capture.as_mut() {
94 if capture(event, visible_bounds, cx) {
95 return true;
96 }
97 }
98
99 if self.child.dispatch_event(event, cx) {
100 true
101 } else {
102 match event {
103 Event::LeftMouseDown { position, .. } => {
104 if let Some(callback) = self.mouse_down.as_mut() {
105 if visible_bounds.contains_point(*position) {
106 return callback(cx);
107 }
108 }
109 false
110 }
111 Event::RightMouseDown { position, .. } => {
112 if let Some(callback) = self.right_mouse_down.as_mut() {
113 if visible_bounds.contains_point(*position) {
114 return callback(cx);
115 }
116 }
117 false
118 }
119 Event::NavigateMouseDown {
120 position,
121 direction,
122 ..
123 } => {
124 if let Some(callback) = self.navigate_mouse_down.as_mut() {
125 if visible_bounds.contains_point(*position) {
126 return callback(*direction, cx);
127 }
128 }
129 false
130 }
131 _ => false,
132 }
133 }
134 }
135
136 fn debug(
137 &self,
138 _: RectF,
139 _: &Self::LayoutState,
140 _: &Self::PaintState,
141 cx: &DebugContext,
142 ) -> serde_json::Value {
143 json!({
144 "type": "EventHandler",
145 "child": self.child.debug(cx),
146 })
147 }
148}