use crate::{*, lang::*, draw::*, space::{*, Split::*}, color::*, text::*, task::*}; //use unicode_width::{UnicodeWidthStr, UnicodeWidthChar}; //use rand::distributions::uniform::UniformSampler; use ::{ std::{ io::{stdout, Write}, time::Duration, ops::{Deref, DerefMut}, }, better_panic::{Settings, Verbosity}, ratatui::{ prelude::{Style, Buffer as ScreenBuffer, Position, Backend, Color}, style::{Modifier, Color::*}, backend::{CrosstermBackend, ClearType}, layout::{Size, Rect}, buffer::{Buffer, Cell}, }, crossterm::{ ExecutableCommand, terminal::{EnterAlternateScreen, LeaveAlternateScreen, enable_raw_mode, disable_raw_mode}, //event::{poll, read, Event, KeyEvent, KeyCode, KeyModifiers, KeyEventKind, KeyEventState}, } }; #[macro_export] macro_rules! tui_main { ($state:expr) => { pub fn main () -> Usually<()> { tengri::exit::Exit::run(|exit|{ let state = Arc::new(RwLock::new($state)); let input = ::tengri::keys::tui_input( exit.as_ref(), &state, ::std::time::Duration::from_millis(100) )?; let output = ::tengri::term::tui_output( stdout(), exit.as_ref(), &state, ::std::time::Duration::from_millis(10) )?; Ok(()) }) } } } #[macro_export] macro_rules! tui_keys { (|$self:ident:$State:ty,$input:ident|$body:block) => { impl Apply> for $State { fn apply (&mut $self, $input: &TuiEvent) -> Usually $body } }; } #[macro_export] macro_rules! tui_view { (|$self:ident: $State:ty|$body:block) => { impl View for $State { fn view (&$self) -> impl Draw $body } } } /// Spawn the TUI output thread which writes colored characters to the terminal. pub fn tui_output + Send + Sync + 'static> ( output: W, exited: &Arc, state: &Arc>, sleep: Duration ) -> Usually { let state = state.clone(); tui_setup()?; let mut backend = CrosstermBackend::new(output); let Size { width, height } = backend.size().expect("get size failed"); let mut buffer_a = Buffer::empty(Rect { x: 0, y: 0, width, height }); let mut buffer_b = Buffer::empty(Rect { x: 0, y: 0, width, height }); Ok(Task::new_sleep(exited.clone(), sleep, move |perf| { let Size { width, height } = backend.size().expect("get size failed"); if let Ok(state) = state.try_read() { tui_resize(&mut backend, &mut buffer_a, Rect { x: 0, y: 0, width, height }); tui_redraw(&mut backend, &mut buffer_a, &mut buffer_b); } let timer = format!("{:>3.3}ms", perf.used.load(Relaxed)); buffer_a.set_string(0, 0, &timer, Style::default()); })?) } pub struct Tui(pub Buffer, pub XYWH); impl Screen for Tui { type Unit = u16; } impl Deref for Tui { type Target = Buffer; fn deref (&self) -> &Buffer { &self.0 } } impl DerefMut for Tui { fn deref_mut (&mut self) -> &mut Buffer { &mut self.0 } } impl HasOrigin for Tui { fn origin (&self) -> Origin { Origin::NW } } impl X for Tui { fn x (&self) -> u16 { self.1.0 } fn w (&self) -> u16 { self.1.2 } } impl Y for Tui { fn y (&self) -> u16 { self.1.1 } fn h (&self) -> u16 { self.1.3 } } impl Tui { pub fn update (&mut self, callback: &impl Fn(&mut Cell, u16, u16)) -> XYWH { for row in 0..self.h() { let y = self.y() + row; for col in 0..self.w() { let x = self.x() + col; if x < self.0.area.width && y < self.0.area.height { if let Some(cell) = self.0.cell_mut(Position { x, y }) { callback(cell, col, row); } } } } self.xywh() } pub fn tint_all (&mut self, fg: Color, bg: Color, modifier: Modifier) { for cell in self.0.content.iter_mut() { cell.fg = fg; cell.bg = bg; cell.modifier = modifier; } } pub fn blit (&mut self, text: &impl AsRef, x: u16, y: u16, style: Option