use ratatui::text::Line;
pub use scrolling_list::{ScrollingList, ScrollingListState};
pub use scrolling_table::{ScrollingTable, ScrollingTableState};
use std::borrow::Cow;
pub use tab_grid::TabGrid;
mod scrolling_list;
mod scrolling_table;
mod tab_grid;
fn get_scrolled_line<'a>(
text: impl Into<Cow<'a, str>>,
cur_tick: u64,
blank_chars: u16,
col_width: u16,
max_times_to_wrap: Option<u16>,
) -> Line<'a> {
let text = text.into();
let (chars_to_remove, blank_chars, times_wrapped) =
get_split_point_and_blanks_and_wrapped(cur_tick, blank_chars, text.len(), col_width);
if let Some(max_times_to_wrap) = max_times_to_wrap
&& times_wrapped >= max_times_to_wrap as u64
{
return Line::from(text);
}
match text {
Cow::Borrowed(b) => {
let safe_split_point = b.floor_char_boundary(chars_to_remove);
let (front, back) = b.split_at(safe_split_point);
Line::from_iter([
Cow::Borrowed(back),
Cow::Owned(" ".repeat(blank_chars as usize)),
Cow::Borrowed(front),
])
}
Cow::Owned(mut o) => {
let safe_split_point = o.floor_char_boundary(chars_to_remove);
let back_half = o.split_off(safe_split_point);
Line::from_iter([
Cow::Owned(back_half),
Cow::Owned(" ".repeat(blank_chars as usize)),
Cow::Owned(o),
])
}
}
}
fn get_split_point_and_blanks_and_wrapped(
cur_tick: u64,
gap_size: u16,
string_len: usize,
col_width: u16,
) -> (usize, u16, u64) {
if string_len <= col_width as usize {
return (0, 0, 0);
}
let n_frames_usize = string_len.saturating_add(gap_size as usize);
let n_frames_u64 = u64::try_from(n_frames_usize).unwrap_or(u64::MAX);
let frame_u64 = cur_tick % n_frames_u64;
let times_wrapped = cur_tick / n_frames_u64;
let frame = frame_u64 as usize;
let chars_to_remove = frame.min(string_len);
let blank_chars = (string_len + gap_size as usize)
.saturating_sub(frame)
.min(gap_size as usize);
debug_assert!(blank_chars <= gap_size as usize);
(chars_to_remove, blank_chars as u16, times_wrapped)
}
#[cfg(test)]
mod tests {
use crate::widgets::get_split_point_and_blanks_and_wrapped;
use pretty_assertions::assert_eq;
#[test]
fn test_split_point_in_middle() {
let example = get_split_point_and_blanks_and_wrapped(3, 4, 22, 16);
assert_eq!(example, (3, 4, 0));
}
#[test]
fn test_split_point_in_middle_wrapped() {
let example = get_split_point_and_blanks_and_wrapped(29, 4, 22, 16);
assert_eq!(example, (3, 4, 1));
}
#[test]
fn test_split_point_string_shorter_than_column() {
let no_adjustment_needed = get_split_point_and_blanks_and_wrapped(12, 4, 14, 16);
assert_eq!(no_adjustment_needed, (0, 0, 0));
}
#[test]
fn test_split_point_end_of_ticker_less_blanks() {
let only_some_blanks = get_split_point_and_blanks_and_wrapped(24, 4, 22, 16);
assert_eq!(only_some_blanks, (22, 2, 0));
}
}