intuitive/event/
mod.rs

1//! Primitives for handling and sending events.
2
3mod channel;
4pub mod handler;
5
6pub use crossterm::event::{KeyCode, KeyEvent, KeyModifiers, MouseEvent, MouseEventKind};
7
8pub use self::channel::{quit, re_render};
9pub(crate) use self::channel::{read, start_crossterm_events};
10use self::handler::Handler;
11#[cfg(doc)]
12use self::handler::Propagate;
13use crate::terminal::Rect;
14
15pub(crate) enum Event {
16  Mouse(MouseEvent),
17  Key(KeyEvent),
18  Render,
19  Quit,
20}
21
22/// A handler for [`KeyEvent`]s.
23///
24/// # Creating a `KeyHandler`
25///
26/// A `KeyHandler` is used to manipulate closures or functions that take in a
27/// [`KeyEvent`] as a parameter, and return a [`Propagate`]. `KeyHandler`s are often
28/// created using the [`on_key!`] macro. For example,
29/// ```rust
30/// # use intuitive::{component, components::Text, render, on_key, state::use_state};
31/// #
32/// #[component(Root)]
33/// fn render() {
34///   let text = use_state(|| String::new());
35///
36///   let on_key = on_key! { [text]
37///     KeyEvent { code: Char(c), .. } => text.mutate(|text| text.push(c)),
38///   };
39///
40///   render! {
41///     Text(text: format!("Hi There {}", text.get()), on_key)
42///   }
43/// }
44/// ```
45///
46/// # Using a `KeyHandler`
47///
48/// A [`KeyEvent`] can be handled by a `KeyHandler` through the [`Handler::handle`]
49/// method. `KeyHandler` implements [`Default`], and the default handler ignores the
50/// `KeyEvent`, and always returns [`Propagate`]`::Next`.
51///
52/// Typically, components want to take some default action when implementing
53/// `on_key`, but allow the user of this component to override this handler. This can
54/// be done using the [`KeyHandler::handle_or`] method:
55/// ```rust
56/// # use intuitive::{element::Element, event::{KeyHandler, KeyEvent}};
57/// #
58/// struct Frozen {
59///   on_key: KeyHandler,
60/// }
61///
62/// impl Element for Frozen {
63///   fn on_key(&self, event: KeyEvent) {
64///     self.on_key.handle_or(event, |event| { /* default functionality here */ })
65///   }
66/// }
67/// ```
68/// Here, `Frozen::on_key` calls the handler that was provided if one was. If no
69/// `KeyHandler` was provided, then `self.on_key` is the default handler,
70/// which always returns [`Propagate`]`::Next`. This causes the closure above to
71/// be executed.
72///
73/// # Propagation
74///
75/// A user of a component can control when the default key handler is run by
76/// returning one of [`Propagate`]`::{Next, Stop}`. For example, to create an
77/// input box that receives input keys, but quits on the escape key:
78/// ```rust
79/// # use intuitive::{component, components::experimental::input::Input, render, on_key, state::use_state};
80/// #
81/// #[component(Root)]
82/// fn render() {
83///   let text = use_state(|| String::new);
84///
85///   let on_key = on_key! { [text]
86///     KeyEvent { code: Esc, .. } => event::quit(),
87///
88///     _ => return Propagate::Next,
89///   };
90///
91///   render! {
92///     Input(on_key)
93///   }
94/// }
95/// ```
96/// This will cause all key events other than `Esc` to be handled by `Input`'s
97/// default key handler.
98///
99/// [`on_key!`]: ../macro.on_key.html
100/// [`Handler::handle_or`]: handler/struct.Handler.html#method.handle_or
101/// [`State`]: ../state/struct.State.html
102/// [`Default`]: https://doc.rust-lang.org/std/default/trait.Default.html
103pub type KeyHandler = Handler<KeyEvent>;
104
105/// A handler for [`MouseEvent`]s.
106pub type MouseHandler = Handler<MouseEvent>;
107
108/// Check if a mouse event is within a [`Rect`].
109pub fn is_within(event: &MouseEvent, rect: Rect) -> bool {
110  let (x, y) = (event.column, event.row);
111
112  let x_within = rect.x <= x && x <= rect.x + rect.width;
113  let y_within = rect.y <= y && y <= rect.y + rect.height;
114
115  x_within && y_within
116}