use crossterm::event::{Event, KeyCode, KeyEvent, MouseButton, MouseEventKind};
use ratatui::prelude::*;
use super::widgets::{
ButtonDef, KeyResult, button_click_index, paragraph_height, render_buttons, render_help,
render_question, wizard_layout,
};
pub type ButtonKeyResult<State, FullScreen, Result> = KeyResult<(State, FullScreen), Result>;
pub trait ButtonScreen: Sized {
type State;
type Result;
type FullScreen;
fn question(&self) -> String;
const QUESTION_COLOR: Color = Color::Yellow;
fn buttons(&self) -> Vec<ButtonDef>;
fn next(self) -> Self;
fn prev(self) -> Self;
fn with_index(self, index: usize) -> Self;
fn into_continue(self, state: Self::State) -> (Self::State, Self::FullScreen);
fn on_confirm(
self,
state: Self::State,
) -> anyhow::Result<ButtonKeyResult<Self::State, Self::FullScreen, Self::Result>>;
fn handle_event(
self,
state: Self::State,
event: Event,
content_area: Rect,
) -> anyhow::Result<ButtonKeyResult<Self::State, Self::FullScreen, Self::Result>> {
let question = self.question();
match event {
Event::Key(KeyEvent { code, .. }) => match code {
KeyCode::Left | KeyCode::Char('h') => {
Ok(KeyResult::Continue(self.prev().into_continue(state)))
}
KeyCode::Right | KeyCode::Tab | KeyCode::Char('l') => {
Ok(KeyResult::Continue(self.next().into_continue(state)))
}
KeyCode::Enter => self.on_confirm(state),
KeyCode::Esc | KeyCode::Char('q') => Ok(KeyResult::Cancelled),
_ => Ok(KeyResult::Continue(self.into_continue(state))),
},
Event::Mouse(me) if matches!(me.kind, MouseEventKind::Down(MouseButton::Left)) => {
let Ok(n) = u16::try_from(self.buttons().len()) else {
return Ok(KeyResult::Continue(self.into_continue(state)));
};
if let Some(idx) = button_click_index(content_area, &question, n, me.column, me.row)
{
self.with_index(idx).on_confirm(state)
} else {
Ok(KeyResult::Continue(self.into_continue(state)))
}
}
_ => Ok(KeyResult::Continue(self.into_continue(state))),
}
}
fn render(&self, frame: &mut Frame, area: Rect) {
let question = self.question();
let chunks = wizard_layout(
area,
&[
Constraint::Length(paragraph_height(&question, area.width, 2)),
Constraint::Length(3),
Constraint::Length(1),
Constraint::Min(1),
],
);
render_question(frame, chunks[0], &question, Self::QUESTION_COLOR);
render_buttons(frame, chunks[1], &self.buttons());
render_help(frame, chunks[3], &crate::t!("button-screen-help"));
}
}