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