1use pathfinder_geometry::rect::RectF;
2use serde_json::json;
3
4use crate::{
5 geometry::vector::Vector2F, AfterLayoutContext, DebugContext, Element, ElementBox, Event,
6 EventContext, LayoutContext, PaintContext, SizeConstraint,
7};
8
9pub struct EventHandler {
10 child: ElementBox,
11 mouse_down: Option<Box<dyn FnMut(&mut EventContext) -> bool>>,
12}
13
14impl EventHandler {
15 pub fn new(child: ElementBox) -> Self {
16 Self {
17 child,
18 mouse_down: None,
19 }
20 }
21
22 pub fn on_mouse_down<F>(mut self, callback: F) -> Self
23 where
24 F: 'static + FnMut(&mut EventContext) -> bool,
25 {
26 self.mouse_down = Some(Box::new(callback));
27 self
28 }
29}
30
31impl Element for EventHandler {
32 type LayoutState = ();
33 type PaintState = ();
34
35 fn layout(
36 &mut self,
37 constraint: SizeConstraint,
38 cx: &mut LayoutContext,
39 ) -> (Vector2F, Self::LayoutState) {
40 let size = self.child.layout(constraint, cx);
41 (size, ())
42 }
43
44 fn after_layout(
45 &mut self,
46 _: Vector2F,
47 _: &mut Self::LayoutState,
48 cx: &mut AfterLayoutContext,
49 ) {
50 self.child.after_layout(cx);
51 }
52
53 fn paint(
54 &mut self,
55 bounds: RectF,
56 _: &mut Self::LayoutState,
57 cx: &mut PaintContext,
58 ) -> Self::PaintState {
59 self.child.paint(bounds.origin(), cx);
60 }
61
62 fn dispatch_event(
63 &mut self,
64 event: &Event,
65 bounds: RectF,
66 _: &mut Self::LayoutState,
67 _: &mut Self::PaintState,
68 cx: &mut EventContext,
69 ) -> bool {
70 if self.child.dispatch_event(event, cx) {
71 true
72 } else {
73 match event {
74 Event::LeftMouseDown { position, .. } => {
75 if let Some(callback) = self.mouse_down.as_mut() {
76 if bounds.contains_point(*position) {
77 return callback(cx);
78 }
79 }
80 false
81 }
82 _ => false,
83 }
84 }
85 }
86
87 fn debug(
88 &self,
89 _: RectF,
90 _: &Self::LayoutState,
91 _: &Self::PaintState,
92 cx: &DebugContext,
93 ) -> serde_json::Value {
94 json!({
95 "type": "EventHandler",
96 "child": self.child.debug(cx),
97 })
98 }
99}