use std::{cell::Cell, rc::Rc};
use crossterm::event::Event;
use ratatui::layout::Rect;
use super::{Hook, Hooks};
use crate::{
SystemContext, UseContext,
input::{CurrentLayer, EventOptions, EventPriority, EventResult, EventScope, InputLayer},
};
mod private {
pub trait Sealed {}
impl Sealed for crate::hooks::Hooks<'_, '_> {}
}
pub trait UseInputLayer: private::Sealed {
fn use_input_layer(&mut self, open: bool, blocks_lower: bool) -> InputLayer;
}
pub trait UseEventHandler: private::Sealed {
fn use_event_handler<F>(&mut self, scope: EventScope, priority: EventPriority, f: F)
where
F: FnMut(Event) -> EventResult + 'static;
fn use_event_handler_with_options<F>(
&mut self,
scope: EventScope,
priority: EventPriority,
options: EventOptions,
f: F,
) where
F: FnMut(Event) -> EventResult + 'static;
}
struct UseInputLayerImpl;
impl Hook for UseInputLayerImpl {}
impl UseInputLayer for Hooks<'_, '_> {
fn use_input_layer(&mut self, open: bool, blocks_lower: bool) -> InputLayer {
self.use_hook(|| UseInputLayerImpl); let mut sys = self.use_context_mut::<SystemContext>();
sys.input.push_layer(open, blocks_lower)
}
}
struct UseEventHandlerImpl {
area: Rc<Cell<Rect>>,
}
impl Hook for UseEventHandlerImpl {
fn pre_component_draw(&mut self, drawer: &mut crate::ComponentDrawer) {
self.area.set(drawer.area);
}
}
impl UseEventHandler for Hooks<'_, '_> {
fn use_event_handler<F>(&mut self, scope: EventScope, priority: EventPriority, f: F)
where
F: FnMut(Event) -> EventResult + 'static,
{
self.use_event_handler_with_options(scope, priority, EventOptions::default(), f);
}
fn use_event_handler_with_options<F>(
&mut self,
scope: EventScope,
priority: EventPriority,
options: EventOptions,
f: F,
) where
F: FnMut(Event) -> EventResult + 'static,
{
let area = {
let hook = self.use_hook(|| UseEventHandlerImpl {
area: Rc::new(Cell::new(Rect::default())),
});
hook.area.clone()
};
let layer = match scope {
EventScope::Global => None,
EventScope::Layer(h) => Some(h.id),
EventScope::Current => {
let id = self
.try_use_context::<CurrentLayer>()
.map(|c| c.0)
.unwrap_or_else(|| self.use_context::<SystemContext>().input.root_layer());
Some(id)
}
};
let mut sys = self.use_context_mut::<SystemContext>();
sys.input
.register_handler(layer, priority, options, area, Box::new(f));
}
}