mod state;
mod ui;
pub use state::{DialogData, DialogResult};
pub use ui::{render_dialog, DialogTheme};
use crate::focus::{FocusController, FocusIntent, FocusManager, OverlayFocus};
use crossterm::event::{KeyCode, KeyEvent};
impl<D> DialogData<D> {
pub fn show_intent<O>(self) -> FocusIntent<O, DialogData<D>> {
let buttons = self.buttons.len();
FocusIntent::ShowModal {
data: self,
count: buttons,
}
}
}
pub fn current_dialog<O, D>(focus: &FocusManager<O, DialogData<D>>) -> Option<&DialogData<D>> {
match focus.overlay() {
Some(OverlayFocus::Modal { data, .. }) => Some(data),
_ => None,
}
}
pub fn active_button<O, D>(focus: &FocusManager<O, DialogData<D>>) -> Option<usize> {
match focus.overlay() {
Some(OverlayFocus::Modal { index, .. }) => Some(*index),
_ => None,
}
}
pub fn selection<O, D: Clone>(focus: &FocusManager<O, DialogData<D>>) -> Option<DialogResult<D>> {
match focus.overlay() {
Some(OverlayFocus::Modal { data, index, .. }) => Some(DialogResult::Selected {
purpose: data.purpose.clone(),
index: *index,
}),
_ => None,
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DialogKey<D> {
Ignored,
Consumed,
Resolved(DialogResult<D>),
}
pub fn handle_key<O: Clone + PartialEq, D: Clone>(
focus: &mut FocusManager<O, DialogData<D>>,
key: KeyEvent,
) -> DialogKey<D> {
if current_dialog(focus).is_none() {
return DialogKey::Ignored;
}
match key.code {
KeyCode::Tab | KeyCode::Right => {
focus.apply_focus_intent(FocusIntent::Next);
DialogKey::Consumed
}
KeyCode::BackTab | KeyCode::Left => {
focus.apply_focus_intent(FocusIntent::Prev);
DialogKey::Consumed
}
KeyCode::Enter => {
let result = selection(focus).unwrap_or(DialogResult::Dismissed);
focus.apply_focus_intent(FocusIntent::ClearOverlay);
DialogKey::Resolved(result)
}
KeyCode::Esc => {
focus.apply_focus_intent(FocusIntent::ClearOverlay);
DialogKey::Resolved(DialogResult::Dismissed)
}
_ => DialogKey::Consumed,
}
}