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