//! Rendering of application to display. use crate::*; pub(crate) use ratatui::prelude::CrosstermBackend; pub(crate) use ratatui::style::{Stylize, Style, Color}; pub(crate) use ratatui::layout::Rect; pub(crate) use ratatui::buffer::{Buffer, Cell}; use ratatui::widgets::WidgetRef; /// Main thread render loop pub fn render_thread ( exited: &Arc, device: &Arc> ) -> Usually> { let exited = exited.clone(); let device = device.clone(); let mut terminal = ratatui::Terminal::new(CrosstermBackend::new(stdout()))?; let sleep = Duration::from_millis(20); Ok(spawn(move || loop { if let Ok(device) = device.try_read() { terminal.draw(|frame|{ let area = frame.size(); let buffer = frame.buffer_mut(); device .render(buffer, area) .expect("Failed to render content"); }) .expect("Failed to render frame"); } if exited.fetch_and(true, Ordering::Relaxed) { break } std::thread::sleep(sleep); })) } pub fn make_dim (buf: &mut Buffer) { for cell in buf.content.iter_mut() { cell.bg = ratatui::style::Color::Rgb(30,30,30); cell.fg = ratatui::style::Color::Rgb(100,100,100); cell.modifier = ratatui::style::Modifier::DIM; } } pub fn center_box (area: Rect, w: u16, h: u16) -> Rect { let width = w.min(area.width * 3 / 5); let height = h.min(area.width * 3 / 5); let x = area.x + (area.width - width) / 2; let y = area.y + (area.height - height) / 2; Rect { x, y, width, height } } pub fn buffer_update ( buf: &mut Buffer, area: Rect, callback: &impl Fn(&mut Cell, u16, u16) ) { for row in 0..area.height { let y = area.y + row; for col in 0..area.width { let x = area.x + col; if x < buf.area.width && y < buf.area.height { callback(buf.get_mut(x, y), col, row); } } } } pub fn fill_fg (buf: &mut Buffer, area: Rect, color: Color) { buffer_update(buf, area, &|cell,_,_|{cell.set_fg(color);}) } pub fn fill_bg (buf: &mut Buffer, area: Rect, color: Color) { buffer_update(buf, area, &|cell,_,_|{cell.set_bg(color);}) } pub fn to_fill_bg (color: Color) -> impl Render { move |buf: &mut Buffer, area: Rect|{ fill_bg(buf, area, color); Ok(area) } } pub fn fill_char (buf: &mut Buffer, area: Rect, c: char) { buffer_update(buf, area, &|cell,_,_|{cell.set_char(c);}) } pub fn half_block (lower: bool, upper: bool) -> Option { match (lower, upper) { (true, true) => Some('█'), (true, false) => Some('▄'), (false, true) => Some('▀'), _ => None } } pub trait Blit { // Render something to X, Y coordinates in a buffer, ignoring width/height. fn blit (&self, buf: &mut Buffer, x: u16, y: u16, style: Option