feat: Add frame count (#766)

This commit is contained in:
Dheepak Krishnamurthy 2024-01-08 03:51:53 -05:00 committed by GitHub
parent 06141900b4
commit c50ff08a63
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 71 additions and 2 deletions

View File

@ -26,6 +26,9 @@ pub struct Frame<'a> {
/// The buffer that is used to draw the current frame
pub(crate) buffer: &'a mut Buffer,
/// The frame count indicating the sequence number of this frame.
pub(crate) count: usize,
}
/// `CompletedFrame` represents the state of the terminal after all changes performed in the last
@ -37,6 +40,8 @@ pub struct CompletedFrame<'a> {
pub buffer: &'a Buffer,
/// The size of the last frame.
pub area: Rect,
/// The frame count indicating the sequence number of this frame.
pub count: usize,
}
impl Frame<'_> {
@ -119,4 +124,32 @@ impl Frame<'_> {
pub fn buffer_mut(&mut self) -> &mut Buffer {
self.buffer
}
/// Returns the current frame count.
///
/// This method provides access to the frame count, which is a sequence number indicating
/// how many frames have been rendered up to (but not including) this one. It can be used
/// for purposes such as animation, performance tracking, or debugging.
///
/// Each time a frame has been rendered, this count is incremented,
/// providing a consistent way to reference the order and number of frames processed by the
/// terminal. When count reaches its maximum value (usize::MAX), it wraps around to zero.
///
/// This count is particularly useful when dealing with dynamic content or animations where the
/// state of the display changes over time. By tracking the frame count, developers can
/// synchronize updates or changes to the content with the rendering process.
///
/// # Examples
///
/// ```rust
/// # use ratatui::{backend::TestBackend, prelude::*, widgets::*};
/// # let backend = TestBackend::new(5, 5);
/// # let mut terminal = Terminal::new(backend).unwrap();
/// # let mut frame = terminal.get_frame();
/// let current_count = frame.count();
/// println!("Current frame count: {}", current_count);
/// ```
pub fn count(&self) -> usize {
self.count
}
}

View File

@ -71,6 +71,8 @@ where
/// Last known position of the cursor. Used to find the new area when the viewport is inlined
/// and the terminal resized.
last_known_cursor_pos: (u16, u16),
/// Number of frames rendered up until current time.
frame_count: usize,
}
/// Options to pass to [`Terminal::with_options`]
@ -149,15 +151,18 @@ where
viewport_area,
last_known_size: size,
last_known_cursor_pos: cursor_pos,
frame_count: 0,
})
}
/// Get a Frame object which provides a consistent view into the terminal state for rendering.
pub fn get_frame(&mut self) -> Frame {
let count = self.frame_count;
Frame {
cursor_position: None,
viewport_area: self.viewport_area,
buffer: self.current_buffer_mut(),
count,
}
}
@ -279,10 +284,16 @@ where
// Flush
self.backend.flush()?;
Ok(CompletedFrame {
let completed_frame = CompletedFrame {
buffer: &self.buffers[1 - self.current],
area: self.last_known_size,
})
count: self.frame_count,
};
// increment frame count before returning from draw
self.frame_count = self.frame_count.wrapping_add(1);
Ok(completed_frame)
}
/// Hides the cursor.

View File

@ -50,6 +50,31 @@ fn terminal_draw_returns_the_completed_frame() -> Result<(), Box<dyn Error>> {
Ok(())
}
#[test]
fn terminal_draw_increments_frame_count() -> Result<(), Box<dyn Error>> {
let backend = TestBackend::new(10, 10);
let mut terminal = Terminal::new(backend)?;
let frame = terminal.draw(|f| {
assert_eq!(f.count(), 0);
let paragraph = Paragraph::new("Test");
f.render_widget(paragraph, f.size());
})?;
assert_eq!(frame.count, 0);
let frame = terminal.draw(|f| {
assert_eq!(f.count(), 1);
let paragraph = Paragraph::new("test");
f.render_widget(paragraph, f.size());
})?;
assert_eq!(frame.count, 1);
let frame = terminal.draw(|f| {
assert_eq!(f.count(), 2);
let paragraph = Paragraph::new("test");
f.render_widget(paragraph, f.size());
})?;
assert_eq!(frame.count, 2);
Ok(())
}
#[test]
fn terminal_insert_before_moves_viewport() -> Result<(), Box<dyn Error>> {
// When we have a terminal with 5 lines, and a single line viewport, if we insert a