use std::io::{Result, Write};
use crossterm::{cursor::{Hide, Show},
execute,
terminal::{disable_raw_mode, enable_raw_mode}};
use r3bl_ansi_color::{is_fully_uninteractive_terminal, TTYResult};
use crate::{CalculateResizeHint, FunctionComponent, KeyPress, KeyPressReader};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EventLoopResult {
Continue,
ContinueAndRerender,
ContinueAndRerenderAndClear,
ExitWithResult(Vec<String>),
ExitWithoutResult,
ExitWithError,
Select,
}
pub fn enter_event_loop<W: Write, S: CalculateResizeHint>(
state: &mut S,
function_component: &mut impl FunctionComponent<W, S>,
on_keypress: impl Fn(&mut S, KeyPress) -> EventLoopResult,
reader: &mut impl KeyPressReader,
) -> Result<EventLoopResult> {
if let TTYResult::IsNotInteractive = is_fully_uninteractive_terminal() {
return Ok(EventLoopResult::ExitWithError);
}
execute!(function_component.get_write(), Hide)?;
enable_raw_mode()?;
let return_this: EventLoopResult;
function_component.render(state)?;
loop {
let key_press = reader.read_key_press();
let result = on_keypress(state, key_press);
match result {
EventLoopResult::ContinueAndRerenderAndClear => {
function_component.clear_viewport_for_resize(state)?;
function_component.render(state)?;
}
EventLoopResult::ContinueAndRerender => {
function_component.render(state)?;
}
EventLoopResult::Continue | EventLoopResult::Select => {
}
EventLoopResult::ExitWithResult(it) => {
return_this = EventLoopResult::ExitWithResult(it);
function_component.clear_viewport(state)?;
break;
}
EventLoopResult::ExitWithoutResult => {
return_this = EventLoopResult::ExitWithoutResult;
function_component.clear_viewport(state)?;
break;
}
EventLoopResult::ExitWithError => {
return_this = EventLoopResult::ExitWithError;
function_component.clear_viewport(state)?;
break;
}
}
}
execute!(function_component.get_write(), Show)?;
disable_raw_mode()?;
Ok(return_this)
}