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