tabula rasa

This commit is contained in:
🪞👃🪞 2025-03-02 14:31:04 +02:00
commit 47b3413d7d
76 changed files with 7000 additions and 0 deletions

104
tui/src/tui_output.rs Normal file
View file

@ -0,0 +1,104 @@
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<TuiOut>) {
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 <T: Render<TuiOut> + Send + Sync + 'static> (
engine: &Arc<RwLock<Tui>>,
state: &Arc<RwLock<T>>,
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<str>, x: u16, y: u16, style: Option<Style>
) {
let text = text.as_ref();
let buf = &mut self.buffer;
if x < buf.area.width && y < buf.area.height {
buf.set_string(x, y, text, style.unwrap_or(Style::default()));
}
}
#[inline]
pub fn with_rect (&mut self, area: [u16;4]) -> &mut Self {
self.area = area;
self
}
}