use std::any::Any;
use std::time::Instant;
use crossterm::event::KeyEvent;
use ratatui::layout::Rect;
use ratatui::Frame;
use crate::app::App;
use crate::config::{Config, Theme};
pub use crate::ui::ModalKind;
pub fn esc_rect_hit(esc_rect: Option<ratatui::layout::Rect>, col: u16, row: u16) -> bool {
match esc_rect {
Some(r) => col >= r.x && col < r.x + r.width && row >= r.y && row < r.y + r.height,
None => false,
}
}
pub fn close_if_esc_clicked(
esc_rect: Option<ratatui::layout::Rect>,
col: u16,
row: u16,
) -> ModalOutcome {
if esc_rect_hit(esc_rect, col, row) {
ModalOutcome::Close
} else {
ModalOutcome::Continue
}
}
pub struct ModalRenderCtx<'a> {
pub theme: &'a Theme,
pub config: &'a Config,
pub cursor_visible: bool,
}
pub enum ModalOutcome {
Continue,
ContinueAnd(Box<dyn FnOnce(&mut App)>),
Close,
CloseAnd(Box<dyn FnOnce(&mut App)>),
}
pub trait Modal {
fn render(&mut self, frame: &mut Frame<'_>, area: Rect, ctx: &ModalRenderCtx<'_>);
fn handle_key(
&mut self,
key: KeyEvent,
app: &mut App,
doc_height: usize,
doc_width: usize,
) -> ModalOutcome;
fn handle_paste(&mut self, _text: &str) -> ModalOutcome {
ModalOutcome::Continue
}
fn handle_wheel(&mut self, _delta: i32) {}
fn handle_click(&mut self, _col: u16, _row: u16, _app: &mut App) -> ModalOutcome {
ModalOutcome::Continue
}
#[allow(dead_code)]
fn kind(&self) -> ModalKind {
ModalKind::Normal
}
#[allow(dead_code)]
fn dismissable(&self) -> bool {
true
}
fn next_deadline(&self) -> Option<Instant> {
None
}
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
}