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