ratatui_kit/hooks/
use_events.rs1use std::{pin::pin, task::Poll};
2
3use crossterm::event::Event;
4use futures::Stream;
5use ratatui::layout::Rect;
6
7use crate::{Hook, Hooks, TerminalEvents};
8
9mod private {
10 pub trait Sealed {}
11 impl Sealed for crate::hooks::Hooks<'_, '_> {}
12}
13
14pub trait UseEvents: private::Sealed {
15 fn use_events<F>(&mut self, f: F)
16 where
17 F: FnMut(Event) + Send + 'static;
18
19 fn use_local_events<F>(&mut self, f: F)
20 where
21 F: FnMut(Event) + Send + 'static;
22}
23
24impl UseEvents for Hooks<'_, '_> {
25 fn use_events<F>(&mut self, f: F)
26 where
27 F: FnMut(Event) + Send + 'static,
28 {
29 let h = self.use_hook(move || UseEventsImpl {
30 events: None,
31 component_area: Default::default(),
32 in_component: false,
33 f: None,
34 });
35 h.f = Some(Box::new(f));
36 }
37
38 fn use_local_events<F>(&mut self, f: F)
39 where
40 F: FnMut(Event) + Send + 'static,
41 {
42 let h = self.use_hook(move || UseEventsImpl {
43 events: None,
44 component_area: Default::default(),
45 in_component: true,
46 f: None,
47 });
48 h.f = Some(Box::new(f));
49 }
50}
51
52struct UseEventsImpl {
53 f: Option<Box<dyn FnMut(Event) + Send>>,
54 events: Option<TerminalEvents<Event>>,
55 in_component: bool,
56 component_area: Rect,
57}
58
59impl Hook for UseEventsImpl {
60 fn poll_change(
61 mut self: std::pin::Pin<&mut Self>,
62 cx: &mut std::task::Context,
63 ) -> std::task::Poll<()> {
64 while let Some(Poll::Ready(Some(event))) = self
65 .events
66 .as_mut()
67 .map(|events| pin!(events).poll_next(cx))
68 {
69 let area = self.component_area;
70 let in_component = self.in_component;
71 if let Some(f) = &mut self.f {
72 if in_component {
73 match event {
74 Event::Mouse(mouse_event) => {
75 if mouse_event.row >= area.y && mouse_event.column >= area.x {
76 let row = mouse_event.row - area.y;
77 let column = mouse_event.column - area.x;
78
79 if row < area.height && column < area.width {
80 f(event);
81 }
82 }
83 }
84 _ => {
85 f(event);
86 }
87 }
88 } else {
89 f(event);
90 }
91 }
92 }
93 Poll::Pending
94 }
95
96 fn post_component_update(&mut self, updater: &mut crate::ComponentUpdater) {
97 if self.events.is_none() {
98 self.events = updater.terminal().events().ok();
99 }
100 }
101
102 fn pre_component_draw(&mut self, drawer: &mut crate::ComponentDrawer) {
103 self.component_area = drawer.area;
104 }
105}