mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
75 lines
3.1 KiB
Rust
75 lines
3.1 KiB
Rust
use crate::{*, tui::*};
|
|
use ratatui::prelude::Size;
|
|
use std::time::Duration;
|
|
use std::thread::{spawn, JoinHandle};
|
|
|
|
pub trait TuiRun<R: Render<Tui> + Handle<Tui> + Sized + 'static> {
|
|
/// Run an app in the main loop.
|
|
fn run (&self, state: &Arc<RwLock<R>>) -> Usually<()>;
|
|
/// Spawn the input thread.
|
|
fn run_input (&self, state: &Arc<RwLock<R>>, poll: Duration) -> JoinHandle<()>;
|
|
/// Spawn the output thread.
|
|
fn run_output (&self, state: &Arc<RwLock<R>>, sleep: Duration) -> JoinHandle<()>;
|
|
}
|
|
|
|
impl<T: Render<Tui> + Handle<Tui> + Sized + 'static> TuiRun<T> for Arc<RwLock<Tui>> {
|
|
fn run (&self, state: &Arc<RwLock<T>>) -> Usually<()> {
|
|
let _input_thread = self.run_input(state, Duration::from_millis(100));
|
|
self.write().unwrap().setup()?;
|
|
let render_thread = self.run_output(state, Duration::from_millis(10));
|
|
render_thread.join().expect("main thread failed");
|
|
self.write().unwrap().teardown()?;
|
|
Ok(())
|
|
}
|
|
fn run_input (&self, state: &Arc<RwLock<T>>, poll: Duration) -> JoinHandle<()> {
|
|
let exited = self.read().unwrap().exited.clone();
|
|
let state = state.clone();
|
|
spawn(move || loop {
|
|
if exited.fetch_and(true, Relaxed) {
|
|
break
|
|
}
|
|
if ::crossterm::event::poll(poll).is_ok() {
|
|
let event = ::crossterm::event::read().unwrap();
|
|
match event {
|
|
kpat!(Ctrl-KeyCode::Char('c')) => {
|
|
exited.store(true, Relaxed);
|
|
},
|
|
_ => {
|
|
let exited = exited.clone();
|
|
if let Err(e) = state.write().unwrap().handle(&TuiIn(exited, event)) {
|
|
panic!("{e}")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
fn run_output (&self, state: &Arc<RwLock<T>>, sleep: Duration) -> JoinHandle<()> {
|
|
let exited = self.read().unwrap().exited.clone();
|
|
let engine = self.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 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);
|
|
}
|
|
std::thread::sleep(sleep);
|
|
})
|
|
}
|
|
}
|
|
|