tui: semi-fix resize

This commit is contained in:
facile pop culture reference 2026-10-01 15:28:39 +03:00
parent 614b8ee5d9
commit 0a868c9e6c

View file

@ -135,6 +135,13 @@ impl Screen for Tui {
} }
impl Tui { impl Tui {
pub fn new (width: u16, height: u16) -> Self {
Self(
XYWH(0, 0, width, height),
Some(Buffer::empty(Rect { x: 0, y: 0, width, height }))
)
}
pub fn setup_panic () { pub fn setup_panic () {
use ::std::panic::{set_hook, PanicHookInfo}; use ::std::panic::{set_hook, PanicHookInfo};
use ::better_panic::{Settings, Verbosity}; use ::better_panic::{Settings, Verbosity};
@ -146,6 +153,7 @@ impl Tui {
panic(info); panic(info);
})); }));
} }
pub fn run_main <T> (exit: Exit, state: Arc<RwLock<T>>) -> Usually<()> where pub fn run_main <T> (exit: Exit, state: Arc<RwLock<T>>) -> Usually<()> where
T: Draw<Tui> + Apply<TuiEvent, Usually<()>> + Send + Sync + 'static T: Draw<Tui> + Apply<TuiEvent, Usually<()>> + Send + Sync + 'static
{ {
@ -155,6 +163,7 @@ impl Tui {
let _ = output.join(); let _ = output.join();
Tui::teardown(&mut stdout()) Tui::teardown(&mut stdout())
} }
/// Spawn the TUI input and output threadsl. /// Spawn the TUI input and output threadsl.
pub fn io < pub fn io <
T: Draw<Tui> + Apply<TuiEvent, Usually<()>> + Send + Sync + 'static, T: Draw<Tui> + Apply<TuiEvent, Usually<()>> + Send + Sync + 'static,
@ -171,6 +180,7 @@ impl Tui {
Tui::output(exited, state, sleep, output)?, Tui::output(exited, state, sleep, output)?,
)) ))
} }
/// Spawn the TUI input thread which reads keys from the terminal. /// Spawn the TUI input thread which reads keys from the terminal.
pub fn input <T: Apply<TuiEvent, Usually<()>> + Send + Sync + 'static> ( pub fn input <T: Apply<TuiEvent, Usually<()>> + Send + Sync + 'static> (
exited: &Arc<AtomicBool>, state: &Arc<RwLock<T>>, poll: Duration exited: &Arc<AtomicBool>, state: &Arc<RwLock<T>>, poll: Duration
@ -186,19 +196,17 @@ impl Tui {
} }
}) })
} }
pub fn teardown <W: Write> (backend: &mut W) -> Usually<()> { pub fn teardown <W: Write> (backend: &mut W) -> Usually<()> {
use ::ratatui::backend::Backend; use ::ratatui::backend::Backend;
stdout().execute(LeaveAlternateScreen)?; stdout().execute(LeaveAlternateScreen)?;
CrosstermBackend::new(backend).show_cursor()?; CrosstermBackend::new(backend).show_cursor()?;
disable_raw_mode().map_err(Into::into) disable_raw_mode().map_err(Into::into)
} }
pub fn new (width: u16, height: u16) -> Self {
Self( pub fn resize <W: Write> (
XYWH(0, 0, width, height), &mut self, back: &mut CrosstermBackend<W>, width: u16, height: u16
Some(Buffer::empty(Rect { x: 0, y: 0, width, height })) ) {
)
}
pub fn resize <W: Write> (&mut self, back: &mut CrosstermBackend<W>, width: u16, height: u16) {
let size = Rect { x: 0, y: 0, width, height }; let size = Rect { x: 0, y: 0, width, height };
self.buffer().map(|buffer|{ self.buffer().map(|buffer|{
if buffer.area != size { if buffer.area != size {
@ -208,13 +216,11 @@ impl Tui {
} }
}); });
} }
pub fn redraw <'b, W: Write> ( pub fn redraw <'b, W: Write> (
&'b mut self, &'b mut self, back: &mut CrosstermBackend<W>, next: &'b mut Self
back: &mut CrosstermBackend<W>,
next: &'b mut Self
) { ) {
if let Some(prev) = self.buffer() if let Some(prev) = self.buffer() && let Some(next) = next.buffer() {
&& let Some(next) = next.buffer() {
let updates = prev.diff(&next); let updates = prev.diff(&next);
back.draw(updates.into_iter()).expect("failed to render"); back.draw(updates.into_iter()).expect("failed to render");
Backend::flush(back).expect("failed to flush output new"); Backend::flush(back).expect("failed to flush output new");
@ -222,6 +228,7 @@ impl Tui {
next.reset(); next.reset();
} }
} }
pub fn update (&mut self, callback: &impl Fn(&mut Cell, u16, u16)) -> XYWH<u16> { pub fn update (&mut self, callback: &impl Fn(&mut Cell, u16, u16)) -> XYWH<u16> {
let XYWH(x0, y0, w, h) = self.area(); let XYWH(x0, y0, w, h) = self.area();
if let Some(buffer) = self.buffer() { if let Some(buffer) = self.buffer() {
@ -239,6 +246,7 @@ impl Tui {
} }
self.xywh() self.xywh()
} }
pub fn blit (&mut self, text: &impl AsRef<str>, x: u16, y: u16, style: Option<Style>) { pub fn blit (&mut self, text: &impl AsRef<str>, x: u16, y: u16, style: Option<Style>) {
if let Some(buffer) = self.buffer() { if let Some(buffer) = self.buffer() {
let text = text.as_ref(); let text = text.as_ref();
@ -248,6 +256,7 @@ impl Tui {
} }
} }
} }
pub fn tint_all (&mut self, fg: Color, bg: Color, modifier: Modifier) { pub fn tint_all (&mut self, fg: Color, bg: Color, modifier: Modifier) {
if let Some(buffer) = self.buffer() { if let Some(buffer) = self.buffer() {
for cell in buffer.content.iter_mut() { for cell in buffer.content.iter_mut() {
@ -257,6 +266,7 @@ impl Tui {
} }
} }
} }
/// Spawn the TUI output thread which writes colored characters to the terminal. /// Spawn the TUI output thread which writes colored characters to the terminal.
/// ///
/// ``` /// ```
@ -292,6 +302,7 @@ impl Tui {
if let Some(state) = state.try_read() { if let Some(state) = state.try_read() {
prev.resize(&mut backend, width, height); prev.resize(&mut backend, width, height);
next.resize(&mut backend, width, height); next.resize(&mut backend, width, height);
next.buffer().map(|buffer|buffer.reset());
state.draw(&mut next).expect("draw failed"); // TODO draw error state.draw(&mut next).expect("draw failed"); // TODO draw error
prev.redraw(&mut backend, &mut next); prev.redraw(&mut backend, &mut next);
} }
@ -299,6 +310,7 @@ impl Tui {
//prev.blit(&timer, 0, 0, Some(Style::default())); //prev.blit(&timer, 0, 0, Some(Style::default()));
})?) })?)
} }
/// Draw TUI content or its error message. /// Draw TUI content or its error message.
/// ///
/// ``` /// ```