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) {
|
||||
// Must be called before rendering, otherwise the terminal has out-of-date
|
||||
// size information and will present garbage.
|
||||
term.autoresize().unwrap();
|
||||
draw(term.frame());
|
||||
while term.present().unwrap() {
|
||||
let mut dirty = true;
|
||||
while dirty {
|
||||
dirty = term.measure_widths().unwrap();
|
||||
term.autoresize().unwrap();
|
||||
draw(term.frame());
|
||||
term.present().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,11 @@ fn widget() -> impl Widget<io::Error> {
|
|||
}
|
||||
|
||||
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() {
|
||||
|
|
|
|||
|
|
@ -49,13 +49,12 @@ fn draw(f: &mut Frame) {
|
|||
}
|
||||
|
||||
fn render_frame(term: &mut Terminal) {
|
||||
// Must be called before rendering, otherwise the terminal has out-of-date
|
||||
// size information and will present garbage.
|
||||
term.autoresize().unwrap();
|
||||
draw(term.frame());
|
||||
while term.present().unwrap() {
|
||||
let mut dirty = true;
|
||||
while dirty {
|
||||
dirty = term.measure_widths().unwrap();
|
||||
term.autoresize().unwrap();
|
||||
draw(term.frame());
|
||||
term.present().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,13 +38,12 @@ fn draw(f: &mut Frame) {
|
|||
}
|
||||
|
||||
fn render_frame(term: &mut Terminal) {
|
||||
// Must be called before rendering, otherwise the terminal has out-of-date
|
||||
// size information and will present garbage.
|
||||
term.autoresize().unwrap();
|
||||
draw(term.frame());
|
||||
while term.present().unwrap() {
|
||||
let mut dirty = true;
|
||||
while dirty {
|
||||
dirty = term.measure_widths().unwrap();
|
||||
term.autoresize().unwrap();
|
||||
draw(term.frame());
|
||||
term.present().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -121,11 +121,12 @@ impl Terminal {
|
|||
/// Handling of wide characters is inconsistent from terminal emulator to
|
||||
/// terminal emulator, and may even depend on the font the user is using.
|
||||
///
|
||||
/// When enabled, any newly encountered graphemes are measured whenever a
|
||||
/// new frame is presented. This is done by clearing the screen, printing
|
||||
/// the grapheme and measuring the resulting cursor position. Because of
|
||||
/// this, the screen will flicker occasionally. However, grapheme widths
|
||||
/// will always be accurate independent of the terminal configuration.
|
||||
/// When enabled, any newly encountered graphemes are measured whenever
|
||||
/// [`Self::measure_widths`] is called. This is done by clearing the screen,
|
||||
/// printing the grapheme and measuring the resulting cursor position.
|
||||
/// Because of this, the screen will flicker occasionally. However, grapheme
|
||||
/// widths will always be accurate independent of the terminal
|
||||
/// configuration.
|
||||
///
|
||||
/// When disabled, the width of graphemes is estimated using the Unicode
|
||||
/// Standard Annex #11. This usually works fine, but may break on some emoji
|
||||
|
|
@ -134,6 +135,25 @@ impl Terminal {
|
|||
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
|
||||
/// changed.
|
||||
///
|
||||
|
|
@ -164,26 +184,12 @@ impl Terminal {
|
|||
|
||||
/// Display the current frame on the screen and prepare the next frame.
|
||||
///
|
||||
/// 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.
|
||||
/// Before drawing and presenting a frame, [`Self::measure_widths`] and
|
||||
/// [`Self::autoresize`] should be called.
|
||||
///
|
||||
/// After calling this function, the frame returned by [`Self::frame`] will
|
||||
/// be empty again and have no cursor position.
|
||||
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;
|
||||
}
|
||||
|
||||
pub fn present(&mut self) -> io::Result<()> {
|
||||
if self.full_redraw {
|
||||
io::stdout().queue(Clear(ClearType::All))?;
|
||||
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);
|
||||
self.frame.reset();
|
||||
|
||||
Ok(measure)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Display a [`Widget`] on the screen.
|
||||
///
|
||||
/// Internally calls [`Self::autoresize`] and [`Self::present`], and passes
|
||||
/// on the value returned by [`Self::present`].
|
||||
pub fn present_widget<E, W>(&mut self, widget: W) -> Result<bool, E>
|
||||
/// Before creating and presenting a widget, [`Self::masure_widths`] should
|
||||
/// be called. There is no need to call [`Self::autoresize`].
|
||||
pub fn present_widget<E, W>(&mut self, widget: W) -> Result<(), E>
|
||||
where
|
||||
E: From<io::Error>,
|
||||
W: Widget<E>,
|
||||
{
|
||||
self.autoresize()?;
|
||||
widget.draw(self.frame())?;
|
||||
let dirty = self.present()?;
|
||||
Ok(dirty)
|
||||
self.present()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Display an [`AsyncWidget`] on the screen.
|
||||
///
|
||||
/// Internally calls [`Self::autoresize`] and [`Self::present`], and passes
|
||||
/// on the value returned by [`Self::present`].
|
||||
pub async fn present_async_widget<E, W>(&mut self, widget: W) -> Result<bool, E>
|
||||
/// Before creating and presenting a widget, [`Self::masure_widths`] should
|
||||
/// be called. There is no need to call [`Self::autoresize`].
|
||||
pub async fn present_async_widget<E, W>(&mut self, widget: W) -> Result<(), E>
|
||||
where
|
||||
E: From<io::Error>,
|
||||
W: AsyncWidget<E>,
|
||||
{
|
||||
self.autoresize()?;
|
||||
widget.draw(self.frame()).await?;
|
||||
let dirty = self.present()?;
|
||||
Ok(dirty)
|
||||
self.present()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn draw_differences(&mut self) -> io::Result<()> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue