use crate::{*, lang::*}; mod border; pub use self::border::*; mod event; pub use self::event::*; mod keys; pub use self::keys::*; mod buffer; pub use self::buffer::*; mod input; pub use self::input::*; mod output; pub use self::output::*; //use unicode_width::{UnicodeWidthStr, UnicodeWidthChar}; //use rand::distributions::uniform::UniformSampler; pub(crate) use ::{ std::{ io::{stdout, Write}, time::Duration, ops::{Deref, DerefMut}, }, ratatui::{ prelude::{Style, 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}, } }, crossterm::event::{ read, Event, KeyEvent, KeyModifiers, KeyCode, KeyEventKind, KeyEventState }, }; /// Terminal output. pub struct Tui( /// Ratatui buffer; area is screen size pub Buffer, /// Current draw area pub XYWH ); 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 AsMut for Tui { fn as_mut (&mut self) -> &mut Buffer { &mut self.0 } } impl Wide for Tui { fn w (&self) -> u16 { self.1.2 } } impl Tall for Tui { fn h (&self) -> u16 { self.1.3 } } impl HasOrigin for Tui { fn origin (&self) -> Azimuth { Azimuth::NW } } impl Xy for Tui { fn x (&self) -> u16 { self.1.0 } fn y (&self) -> u16 { self.1.1 } } impl Tui { pub fn new (width: u16, height: u16) -> Self { Self(Buffer::empty(Rect { x: 0, y: 0, width, height }), XYWH(0, 0, width, height)) } pub fn resize (&mut self, back: &mut CrosstermBackend, width: u16, height: u16) { let size = Rect { x: 0, y: 0, width, height }; if self.0.area != size { back.clear_region(ClearType::All).unwrap(); self.0.resize(size); self.0.reset(); } } pub fn redraw <'b, W: Write> (&'b mut self, back: &mut CrosstermBackend, mut next: &'b mut Self) { let updates = self.0.diff(&next.0); back.draw(updates.into_iter()).expect("failed to render"); Backend::flush(back).expect("failed to flush output new"); std::mem::swap(self, &mut next); next.0.reset(); } } 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