use ratatui::{buffer::Buffer, layout::Rect, style::Color};
use std::f32::consts::TAU;
use super::state::InteractiveState;
pub(super) fn color_to_rgb(color: Color) -> Option<(u8, u8, u8)> {
match color {
Color::Rgb(r, g, b) => Some((r, g, b)),
_ => None,
}
}
pub(super) fn interpolate_rgb(rgb1: (u8, u8, u8), rgb2: (u8, u8, u8), factor: f32) -> Color {
let r = (rgb1.0 as f32 * (1.0 - factor) + rgb2.0 as f32 * factor) as u8;
let g = (rgb1.1 as f32 * (1.0 - factor) + rgb2.1 as f32 * factor) as u8;
let b = (rgb1.2 as f32 * (1.0 - factor) + rgb2.2 as f32 * factor) as u8;
Color::Rgb(r, g, b)
}
pub(super) fn animation_factor(x: u16, elapsed_ms: u128) -> f32 {
let wavelength = 100.0;
let speed = 0.125;
let position = x as f32 - (elapsed_ms as f32 * speed);
((position / wavelength) * TAU).sin() * 0.5 + 0.5
}
pub(super) fn animated_background(x: u16, elapsed_ms: u128, bg1: Color, bg2: Color) -> Color {
match (color_to_rgb(bg1), color_to_rgb(bg2)) {
(Some(rgb1), Some(rgb2)) => {
let factor = animation_factor(x, elapsed_ms);
interpolate_rgb(rgb1, rgb2, factor)
}
_ => {
hard_stripe_bg(x, elapsed_ms, bg1, bg2)
}
}
}
fn animated_foreground(x: u16, elapsed_ms: u128, fg1: Color, fg2: Color) -> Color {
match (color_to_rgb(fg1), color_to_rgb(fg2)) {
(Some(rgb1), Some(rgb2)) => {
let factor = animation_factor(x, elapsed_ms);
interpolate_rgb(rgb1, rgb2, factor)
}
_ => fg1, }
}
fn hard_stripe_bg(x: u16, elapsed_ms: u128, bg1: Color, bg2: Color) -> Color {
const STRIPE_WIDTH: u16 = 8;
const STRIPE_ON_WIDTH: u16 = 4;
let offset = (elapsed_ms / 40) as u16;
let position = (x + offset) % STRIPE_WIDTH;
if position < STRIPE_ON_WIDTH { bg2 } else { bg1 }
}
impl<'a> InteractiveState<'a> {
pub(super) fn render_loading_bar(&mut self, buf: &mut Buffer, area: Rect) {
let elapsed_ms = self.loading.started_at.elapsed().as_millis();
let status_bg = self.theme.status_style.bg.unwrap_or(Color::Reset);
let loading_bg = self.theme.status_loading_bg;
let doc_bg = self.theme.document_bg_style.bg.unwrap_or(Color::Reset);
const LINE_CHAR: char = '▂';
for x in 0..area.width {
let fg = animated_background(x, elapsed_ms, status_bg, loading_bg);
let cell = buf.cell_mut((x, area.y)).unwrap();
cell.reset();
cell.set_char(LINE_CHAR);
cell.set_fg(fg);
cell.set_bg(doc_bg);
}
}
}