use std::io::Write;
use crossterm::{
queue,
style::{Color, Print, ResetColor, SetForegroundColor},
};
use crate::{Component, Renderer};
const ANSI_GRAYSCALE_START: u8 = 232;
const GRAYSCALE_RANGE: f64 = 15.0;
pub struct HintComponent {
pub text: &'static str,
pub fade: f64,
}
impl HintComponent {
pub fn new(text: &'static str) -> Self {
Self { text, fade: 0.0 }
}
}
#[cfg(not(tarpaulin_include))]
impl Component for HintComponent {
fn render<W: Write>(&self, renderer: &mut Renderer<W>) -> std::io::Result<u16> {
if self.fade <= 0.0 {
return Ok(0);
}
renderer.with_panel(|writer, _panel, _rng| {
let color = fade_color(self.fade);
queue!(
writer,
SetForegroundColor(color),
Print(self.text),
ResetColor
)?;
Ok(1)
})
}
}
fn fade_color(fade: f64) -> Color {
if fade >= 1.0 {
return Color::DarkGrey;
}
Color::AnsiValue(ANSI_GRAYSCALE_START + (fade * GRAYSCALE_RANGE).round() as u8)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::LayoutPanel;
use crate::test_helpers::test_renderer;
#[test]
fn new_starts_invisible() {
let hint = HintComponent::new("(hit enter)");
assert_eq!(hint.fade, 0.0);
assert_eq!(hint.text, "(hit enter)");
}
#[test]
fn fade_color_returns_dark_grey_at_full() {
assert_eq!(fade_color(1.0), Color::DarkGrey);
assert_eq!(fade_color(1.5), Color::DarkGrey);
}
#[test]
fn fade_color_returns_ansi_gradient_below_one() {
let color = fade_color(0.5);
match color {
Color::AnsiValue(v) => {
assert!(v >= 232);
assert!(v <= 247);
}
_ => panic!("expected AnsiValue"),
}
}
#[test]
fn fade_color_at_zero_is_darkest() {
assert_eq!(fade_color(0.0), Color::AnsiValue(ANSI_GRAYSCALE_START));
}
#[test]
fn render_skips_when_invisible() {
let hint = HintComponent::new("test");
let panel = LayoutPanel::centered(80, 4, 10);
let mut renderer = test_renderer();
renderer.draw(&hint, panel).unwrap();
assert!(renderer.writer.is_empty());
}
#[test]
fn render_writes_when_visible() {
let mut hint = HintComponent::new("hello");
hint.fade = 1.0;
let panel = LayoutPanel::centered(80, 5, 10);
let mut renderer = test_renderer();
renderer.draw(&hint, panel).unwrap();
assert!(!renderer.writer.is_empty());
let output = String::from_utf8(renderer.writer).unwrap();
assert!(output.contains("hello"));
}
}