use ratatui::layout::{Constraint, Layout, Rect};
use ratatui::style::{Color, Modifier, Style};
use ratatui::text::{Line, Span};
use ratatui::widgets::{Paragraph, Sparkline};
use ratatui::Frame;
use crate::engine::metrics::Sampler;
use crate::tui::theme::Theme;
use crate::utils::format::{split_bps_unit, SpeedUnit};
use super::digits;
pub struct SpeedGaugeData<'a> {
pub label: &'a str,
pub bps: f64,
pub color: Color,
pub history: &'a Sampler,
pub speed_unit: SpeedUnit,
}
pub fn render(frame: &mut Frame, area: Rect, theme: &Theme, data: &SpeedGaugeData<'_>) {
if area.height == 0 {
return;
}
let colors = &theme.colors;
let (value, unit) = split_bps_unit(data.bps, data.speed_unit);
let [label_area, digits_area, spark_area] = Layout::vertical([
Constraint::Length(1),
Constraint::Length(digits::FONT_HEIGHT as u16 + 1),
Constraint::Min(0),
])
.areas(area);
frame.render_widget(
Paragraph::new(
Line::from(Span::styled(
data.label.to_uppercase(),
Style::default()
.fg(colors.subtext)
.add_modifier(Modifier::BOLD),
))
.centered(),
),
label_area,
);
if crate::tui::glyphs::current().fancy {
digits::render_value(frame, digits_area, &value, unit, data.color, colors.muted);
render_sparkline(frame, spark_area, data.history, data.color);
} else {
let line = Line::from(vec![
Span::styled(
value,
Style::default().fg(data.color).add_modifier(Modifier::BOLD),
),
Span::styled(format!(" {unit}"), Style::default().fg(colors.muted)),
])
.centered();
frame.render_widget(Paragraph::new(line), digits_area);
}
}
fn render_sparkline(frame: &mut Frame, area: Rect, history: &Sampler, color: Color) {
if area.height == 0 || area.width < 8 || history.len() < 2 {
return;
}
let max = history.max().unwrap_or(0.0).max(1.0);
let width = usize::from(area.width.saturating_sub(8));
let data: Vec<u64> = history
.iter()
.map(|sample| ((sample / max) * 100.0) as u64)
.collect();
let take = data.len().min(width);
let slice = &data[data.len() - take..];
let spark_area = Rect {
x: area.x + (area.width - take as u16) / 2,
y: area.y,
width: take as u16,
height: area.height.min(2),
};
frame.render_widget(
Sparkline::default()
.data(slice)
.max(100)
.style(Style::default().fg(color)),
spark_area,
);
}