Don't measure widths while presenting
This commit is contained in:
parent
fae12a4b9f
commit
ba6ee45110
5 changed files with 56 additions and 49 deletions
|
|
@ -12,13 +12,12 @@ fn draw(f: &mut Frame) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_frame(term: &mut Terminal) {
|
fn render_frame(term: &mut Terminal) {
|
||||||
// Must be called before rendering, otherwise the terminal has out-of-date
|
let mut dirty = true;
|
||||||
// size information and will present garbage.
|
while dirty {
|
||||||
term.autoresize().unwrap();
|
dirty = term.measure_widths().unwrap();
|
||||||
draw(term.frame());
|
|
||||||
while term.present().unwrap() {
|
|
||||||
term.autoresize().unwrap();
|
term.autoresize().unwrap();
|
||||||
draw(term.frame());
|
draw(term.frame());
|
||||||
|
term.present().unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,11 @@ fn widget() -> impl Widget<io::Error> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_frame(term: &mut Terminal) {
|
fn render_frame(term: &mut Terminal) {
|
||||||
while term.present_widget(widget()).unwrap() {}
|
let mut dirty = true;
|
||||||
|
while dirty {
|
||||||
|
dirty = term.measure_widths().unwrap();
|
||||||
|
term.present_widget(widget()).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
||||||
|
|
@ -49,13 +49,12 @@ fn draw(f: &mut Frame) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_frame(term: &mut Terminal) {
|
fn render_frame(term: &mut Terminal) {
|
||||||
// Must be called before rendering, otherwise the terminal has out-of-date
|
let mut dirty = true;
|
||||||
// size information and will present garbage.
|
while dirty {
|
||||||
term.autoresize().unwrap();
|
dirty = term.measure_widths().unwrap();
|
||||||
draw(term.frame());
|
|
||||||
while term.present().unwrap() {
|
|
||||||
term.autoresize().unwrap();
|
term.autoresize().unwrap();
|
||||||
draw(term.frame());
|
draw(term.frame());
|
||||||
|
term.present().unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,13 +38,12 @@ fn draw(f: &mut Frame) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_frame(term: &mut Terminal) {
|
fn render_frame(term: &mut Terminal) {
|
||||||
// Must be called before rendering, otherwise the terminal has out-of-date
|
let mut dirty = true;
|
||||||
// size information and will present garbage.
|
while dirty {
|
||||||
term.autoresize().unwrap();
|
dirty = term.measure_widths().unwrap();
|
||||||
draw(term.frame());
|
|
||||||
while term.present().unwrap() {
|
|
||||||
term.autoresize().unwrap();
|
term.autoresize().unwrap();
|
||||||
draw(term.frame());
|
draw(term.frame());
|
||||||
|
term.present().unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -121,11 +121,12 @@ impl Terminal {
|
||||||
/// Handling of wide characters is inconsistent from terminal emulator to
|
/// Handling of wide characters is inconsistent from terminal emulator to
|
||||||
/// terminal emulator, and may even depend on the font the user is using.
|
/// terminal emulator, and may even depend on the font the user is using.
|
||||||
///
|
///
|
||||||
/// When enabled, any newly encountered graphemes are measured whenever a
|
/// When enabled, any newly encountered graphemes are measured whenever
|
||||||
/// new frame is presented. This is done by clearing the screen, printing
|
/// [`Self::measure_widths`] is called. This is done by clearing the screen,
|
||||||
/// the grapheme and measuring the resulting cursor position. Because of
|
/// printing the grapheme and measuring the resulting cursor position.
|
||||||
/// this, the screen will flicker occasionally. However, grapheme widths
|
/// Because of this, the screen will flicker occasionally. However, grapheme
|
||||||
/// will always be accurate independent of the terminal configuration.
|
/// widths will always be accurate independent of the terminal
|
||||||
|
/// configuration.
|
||||||
///
|
///
|
||||||
/// When disabled, the width of graphemes is estimated using the Unicode
|
/// When disabled, the width of graphemes is estimated using the Unicode
|
||||||
/// Standard Annex #11. This usually works fine, but may break on some emoji
|
/// Standard Annex #11. This usually works fine, but may break on some emoji
|
||||||
|
|
@ -134,6 +135,25 @@ impl Terminal {
|
||||||
self.frame.widthdb.active
|
self.frame.widthdb.active
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Measure widths of newly encountered graphemes.
|
||||||
|
///
|
||||||
|
/// If width measurements are disabled, this function does nothing. For more
|
||||||
|
/// info, see [`Self::measuring`].
|
||||||
|
///
|
||||||
|
/// Returns `true` if graphemes were measured and the screen must be
|
||||||
|
/// redrawn. Keep in mind that after redrawing the screen, new graphemes may
|
||||||
|
/// have become visible that have not yet been measured. You should keep
|
||||||
|
/// re-measuring and re-drawing until this function returns `false`.
|
||||||
|
pub fn measure_widths(&mut self) -> io::Result<bool> {
|
||||||
|
if self.frame.widthdb.measuring_required() {
|
||||||
|
self.full_redraw = true;
|
||||||
|
self.frame.widthdb.measure_widths(&mut self.out)?;
|
||||||
|
Ok(true)
|
||||||
|
} else {
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 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.
|
||||||
///
|
///
|
||||||
|
|
@ -164,26 +184,12 @@ 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.
|
||||||
///
|
///
|
||||||
/// Before drawing and presenting a frame, [`Self::autoresize`] should be
|
/// Before drawing and presenting a frame, [`Self::measure_widths`] and
|
||||||
/// called. [`Self::present`] does **not** call it automatically.
|
/// [`Self::autoresize`] should be called.
|
||||||
///
|
|
||||||
/// 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<bool> {
|
pub fn present(&mut self) -> io::Result<()> {
|
||||||
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
|
||||||
|
|
@ -197,37 +203,37 @@ 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(measure)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Display a [`Widget`] on the screen.
|
/// Display a [`Widget`] on the screen.
|
||||||
///
|
///
|
||||||
/// Internally calls [`Self::autoresize`] and [`Self::present`], and passes
|
/// Before creating and presenting a widget, [`Self::masure_widths`] should
|
||||||
/// on the value returned by [`Self::present`].
|
/// be called. There is no need to call [`Self::autoresize`].
|
||||||
pub fn present_widget<E, W>(&mut self, widget: W) -> Result<bool, E>
|
pub fn present_widget<E, W>(&mut self, widget: W) -> Result<(), E>
|
||||||
where
|
where
|
||||||
E: From<io::Error>,
|
E: From<io::Error>,
|
||||||
W: Widget<E>,
|
W: Widget<E>,
|
||||||
{
|
{
|
||||||
self.autoresize()?;
|
self.autoresize()?;
|
||||||
widget.draw(self.frame())?;
|
widget.draw(self.frame())?;
|
||||||
let dirty = self.present()?;
|
self.present()?;
|
||||||
Ok(dirty)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Display an [`AsyncWidget`] on the screen.
|
/// Display an [`AsyncWidget`] on the screen.
|
||||||
///
|
///
|
||||||
/// Internally calls [`Self::autoresize`] and [`Self::present`], and passes
|
/// Before creating and presenting a widget, [`Self::masure_widths`] should
|
||||||
/// on the value returned by [`Self::present`].
|
/// be called. There is no need to call [`Self::autoresize`].
|
||||||
pub async fn present_async_widget<E, W>(&mut self, widget: W) -> Result<bool, E>
|
pub async fn present_async_widget<E, W>(&mut self, widget: W) -> Result<(), E>
|
||||||
where
|
where
|
||||||
E: From<io::Error>,
|
E: From<io::Error>,
|
||||||
W: AsyncWidget<E>,
|
W: AsyncWidget<E>,
|
||||||
{
|
{
|
||||||
self.autoresize()?;
|
self.autoresize()?;
|
||||||
widget.draw(self.frame()).await?;
|
widget.draw(self.frame()).await?;
|
||||||
let dirty = self.present()?;
|
self.present()?;
|
||||||
Ok(dirty)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_differences(&mut self) -> io::Result<()> {
|
fn draw_differences(&mut self) -> io::Result<()> {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue