Measure automatically in Terminal::present

This commit is contained in:
Joscha 2023-02-17 13:59:04 +01:00
parent e3365fdc02
commit ed14ea9023
5 changed files with 41 additions and 59 deletions

View file

@ -12,19 +12,13 @@ fn draw(f: &mut Frame) {
} }
fn render_frame(term: &mut Terminal) { fn render_frame(term: &mut Terminal) {
loop {
// Must be called before rendering, otherwise the terminal has out-of-date // Must be called before rendering, otherwise the terminal has out-of-date
// size information and will present garbage. // size information and will present garbage.
term.autoresize().unwrap(); term.autoresize().unwrap();
draw(term.frame()); draw(term.frame());
term.present().unwrap(); while term.present().unwrap() {
term.autoresize().unwrap();
if term.measuring_required() { draw(term.frame());
term.measure_widths().unwrap();
} else {
break;
}
} }
} }

View file

@ -1,11 +1,11 @@
use std::convert::Infallible; use std::io;
use crossterm::event::Event; use crossterm::event::Event;
use crossterm::style::Stylize; use crossterm::style::Stylize;
use toss::widgets::{BorderLook, Text}; use toss::widgets::{BorderLook, Text};
use toss::{Style, Styled, Terminal, Widget, WidgetExt}; use toss::{Style, Styled, Terminal, Widget, WidgetExt};
fn widget() -> impl Widget<Infallible> { fn widget() -> impl Widget<io::Error> {
let styled = Styled::new("Hello world!", Style::new().dark_green()) let styled = Styled::new("Hello world!", Style::new().dark_green())
.then_plain("\n") .then_plain("\n")
.then("Press any key to exit", Style::new().on_dark_blue()); .then("Press any key to exit", Style::new().on_dark_blue());
@ -22,19 +22,13 @@ fn widget() -> impl Widget<Infallible> {
} }
fn render_frame(term: &mut Terminal) { fn render_frame(term: &mut Terminal) {
loop {
// Must be called before rendering, otherwise the terminal has out-of-date // Must be called before rendering, otherwise the terminal has out-of-date
// size information and will present garbage. // size information and will present garbage.
term.autoresize().unwrap(); term.autoresize().unwrap();
widget().draw(term.frame()).unwrap(); widget().draw(term.frame()).unwrap();
term.present().unwrap(); while term.present().unwrap() {
term.autoresize().unwrap();
if term.measuring_required() { widget().draw(term.frame()).unwrap();
term.measure_widths().unwrap();
} else {
break;
}
} }
} }

View file

@ -49,19 +49,13 @@ fn draw(f: &mut Frame) {
} }
fn render_frame(term: &mut Terminal) { fn render_frame(term: &mut Terminal) {
loop {
// Must be called before rendering, otherwise the terminal has out-of-date // Must be called before rendering, otherwise the terminal has out-of-date
// size information and will present garbage. // size information and will present garbage.
term.autoresize().unwrap(); term.autoresize().unwrap();
draw(term.frame()); draw(term.frame());
term.present().unwrap(); while term.present().unwrap() {
term.autoresize().unwrap();
if term.measuring_required() { draw(term.frame());
term.measure_widths().unwrap();
} else {
break;
}
} }
} }

View file

@ -38,19 +38,13 @@ fn draw(f: &mut Frame) {
} }
fn render_frame(term: &mut Terminal) { fn render_frame(term: &mut Terminal) {
loop {
// Must be called before rendering, otherwise the terminal has out-of-date // Must be called before rendering, otherwise the terminal has out-of-date
// size information and will present garbage. // size information and will present garbage.
term.autoresize().unwrap(); term.autoresize().unwrap();
draw(term.frame()); draw(term.frame());
term.present().unwrap(); while term.present().unwrap() {
term.autoresize().unwrap();
if term.measuring_required() { draw(term.frame());
term.measure_widths().unwrap();
} else {
break;
}
} }
} }

View file

@ -91,16 +91,6 @@ impl Terminal {
self.frame.widthdb.active self.frame.widthdb.active
} }
pub fn measuring_required(&self) -> bool {
self.frame.widthdb.measuring_required()
}
pub fn measure_widths(&mut self) -> io::Result<()> {
self.frame.widthdb.measure_widths(&mut self.out)?;
self.full_redraw = true;
Ok(())
}
/// Resize the frame and other internal buffers if the terminal size has /// Resize the frame and other internal buffers if the terminal size has
/// changed. /// changed.
pub fn autoresize(&mut self) -> io::Result<()> { pub fn autoresize(&mut self) -> io::Result<()> {
@ -124,11 +114,27 @@ impl Terminal {
} }
/// Display the current frame on the screen and prepare the next frame. /// Display the current frame on the screen and prepare the next frame.
/// Returns `true` if an immediate redraw is required. ///
/// Before drawing and presenting a frame, [`Self::autoresize`] should be
/// called. [`Self::present`] does **not** call it automatically.
///
/// If width measurements are turned on, any new graphemes encountered since
/// the last [`Self::present`] call will be measured. This can lead to the
/// screen flickering or being mostly blank until measurements complete.
///
/// Returns `true` if any new graphemes were measured. Since their widths
/// may have changed because of the measurements, the application using this
/// [`Terminal`] should re-draw and re-present the current frame.
/// ///
/// After calling this function, the frame returned by [`Self::frame`] will /// After calling this function, the frame returned by [`Self::frame`] will
/// be empty again and have no cursor position. /// be empty again and have no cursor position.
pub fn present(&mut self) -> io::Result<()> { pub fn present(&mut self) -> io::Result<bool> {
let measure = self.frame.widthdb.measuring_required();
if measure {
self.frame.widthdb.measure_widths(&mut self.out)?;
self.full_redraw = true;
}
if self.full_redraw { if self.full_redraw {
io::stdout().queue(Clear(ClearType::All))?; io::stdout().queue(Clear(ClearType::All))?;
self.prev_frame_buffer.reset(); // Because the screen is now empty self.prev_frame_buffer.reset(); // Because the screen is now empty
@ -142,7 +148,7 @@ impl Terminal {
mem::swap(&mut self.prev_frame_buffer, &mut self.frame.buffer); mem::swap(&mut self.prev_frame_buffer, &mut self.frame.buffer);
self.frame.reset(); self.frame.reset();
Ok(()) Ok(measure)
} }
fn draw_differences(&mut self) -> io::Result<()> { fn draw_differences(&mut self) -> io::Result<()> {