use crate::*; use std::time::Duration; use std::thread::{spawn, JoinHandle}; #[derive(Default)] pub struct TuiOut { pub buffer: Buffer, pub area: [u16;4] } impl Output for TuiOut { type Unit = u16; type Size = [Self::Unit;2]; type Area = [Self::Unit;4]; #[inline] fn area (&self) -> [u16;4] { self.area } #[inline] fn area_mut (&mut self) -> &mut [u16;4] { &mut self.area } #[inline] fn place (&mut self, area: [u16;4], content: &impl Render) { let last = self.area(); *self.area_mut() = area; content.render(self); *self.area_mut() = last; } } impl TuiOut { /// Spawn the output thread. pub fn run_output + Send + Sync + 'static> ( engine: &Arc>, state: &Arc>, timer: Duration ) -> JoinHandle<()> { let exited = engine.read().unwrap().exited.clone(); let engine = engine.clone(); let state = state.clone(); let Size { width, height } = engine.read().unwrap().backend.size().expect("get size failed"); let mut buffer = Buffer::empty(Rect { x: 0, y: 0, width, height }); spawn(move || loop { if exited.fetch_and(true, Relaxed) { break } let t0 = engine.read().unwrap().perf.get_t0(); let Size { width, height } = engine.read().unwrap().backend.size() .expect("get size failed"); if let Ok(state) = state.try_read() { let size = Rect { x: 0, y: 0, width, height }; if buffer.area != size { engine.write().unwrap().backend.clear_region(ClearType::All) .expect("clear failed"); buffer.resize(size); buffer.reset(); } let mut output = TuiOut { buffer, area: [0, 0, width, height] }; state.render(&mut output); buffer = engine.write().unwrap().flip(output.buffer, size); } let t1 = engine.read().unwrap().perf.get_t1(t0).unwrap(); //buffer.set_string(0, 0, &format!("{:>3}.{:>3}ms", t1.as_millis(), t1.as_micros() % 1000), Style::default()); std::thread::sleep(timer); }) } pub fn buffer_update (&mut self, area: [u16;4], callback: &impl Fn(&mut Cell, u16, u16)) { buffer_update(&mut self.buffer, area, callback); } pub fn fill_bold (&mut self, area: [u16;4], on: bool) { if on { self.buffer_update(area, &|cell,_,_|cell.modifier.insert(Modifier::BOLD)) } else { self.buffer_update(area, &|cell,_,_|cell.modifier.remove(Modifier::BOLD)) } } pub fn fill_bg (&mut self, area: [u16;4], color: Color) { self.buffer_update(area, &|cell,_,_|{cell.set_bg(color);}) } pub fn fill_fg (&mut self, area: [u16;4], color: Color) { self.buffer_update(area, &|cell,_,_|{cell.set_fg(color);}) } pub fn fill_ul (&mut self, area: [u16;4], color: Color) { self.buffer_update(area, &|cell,_,_|{ cell.modifier = ratatui::prelude::Modifier::UNDERLINED; cell.underline_color = color; }) } pub fn fill_char (&mut self, area: [u16;4], c: char) { self.buffer_update(area, &|cell,_,_|{cell.set_char(c);}) } pub fn make_dim (&mut self) { for cell in self.buffer.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 blit ( &mut self, text: &impl AsRef, x: u16, y: u16, style: Option