Skip to content

Commit

Permalink
Allow a vector of colors in visualizer_gradient
Browse files Browse the repository at this point in the history
Previously, you had to specify exactly two colors, now any number of
colors is accepted.
  • Loading branch information
LeoRiether committed Feb 10, 2024
1 parent c380b28 commit 8293563
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 63 deletions.
4 changes: 2 additions & 2 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ Here's the default configuration file:
```yaml
playlists_dir: {audio_dir described in the above table}
visualizer_gradient:
- [46, 20, 66]
- [16, 30, 71]
- "#2e1442"
- "#101e47"
keybindings:
'?': OpenHelpModal
C-c: Quit
Expand Down
2 changes: 1 addition & 1 deletion tori/src/app/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crossterm::{
event::{DisableMouseCapture, EnableMouseCapture, Event as CrosstermEvent, KeyEventKind},
event::{DisableMouseCapture, EnableMouseCapture},
execute,
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
Expand Down
66 changes: 66 additions & 0 deletions tori/src/color.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Color {
Rgb(u8, u8, u8),
Str(String),
}

impl Color {
pub fn to_rgb(&self) -> Option<(u8, u8, u8)> {
match self {
Color::Rgb(r, g, b) => Some((*r, *g, *b)),
Color::Str(s) => {
let s = s.trim_start_matches('#');
if s.len() != 6 {
return None;
}
let r = u8::from_str_radix(&s[0..2], 16).ok()?;
let g = u8::from_str_radix(&s[2..4], 16).ok()?;
let b = u8::from_str_radix(&s[4..6], 16).ok()?;
Some((r, g, b))
}
}
}

pub fn precalculate_as_rgb(&mut self) {
let (r, g, b) = self.to_rgb().unwrap();
*self = Color::Rgb(r, g, b);
}

/// Linearly interpolates between two colors
pub fn lerp(from: &Color, to: &Color, percent: f64) -> Color {
let lerp = |from: u8, to: u8, perc: f64| {
(from as f64 + perc * (to as f64 - from as f64)).round() as u8
};

let (r0, g0, b0) = from.to_rgb().unwrap();
let (r1, g1, b1) = to.to_rgb().unwrap();
Color::Rgb(
lerp(r0, r1, percent),
lerp(g0, g1, percent),
lerp(b0, b1, percent),
)
}

/// Linearly interpolates between a slice of colors
pub fn lerp_many(colors: &[Color], percent: f64) -> Color {
match colors.len() {
0 => Color::Rgb(0, 0, 0),
1 => colors[0].clone(),
_ => {
let index = (percent * (colors.len() - 1) as f64).floor() as usize;
let p = percent * (colors.len() - 1) as f64 - index as f64;
Color::lerp(&colors[index], &colors[index + 1], p)
}
}
}
}

impl From<Color> for tui::style::Color {
fn from(value: Color) -> Self {
let (r, g, b) = value.to_rgb().unwrap();
tui::style::Color::Rgb(r, g, b)
}
}
24 changes: 4 additions & 20 deletions tori/src/component/visualizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,9 @@ use std::{
};

use rand::{thread_rng, Rng};
use tui::{
layout::Rect,
prelude::*,
style::{Color, Style},
};
use tui::{layout::Rect, prelude::*, style::Style};

use crate::{config::Config, error::Result};
use crate::{color::Color, config::Config, error::Result};

macro_rules! cava_config {
() => {
Expand Down Expand Up @@ -101,25 +97,13 @@ impl Visualizer {

let state = self.0.as_ref().unwrap();

let lerp = |from: u8, to: u8, perc: f64| {
(from as f64 + perc * (to as f64 - from as f64)).round() as u8
};
let lerp_grad = |gradient: [(u8, u8, u8); 2], perc| {
Color::Rgb(
lerp(gradient[0].0, gradient[1].0, perc),
lerp(gradient[0].1, gradient[1].1, perc),
lerp(gradient[0].2, gradient[1].2, perc),
)
};

let gradient = Config::global().visualizer_gradient;

let gradient = &Config::global().visualizer_gradient[..];
let data = state.data.lock().unwrap();
let columns = std::cmp::min(data.len(), buffer.area().width as usize / 2);
let size = *buffer.area();
for i in 0..columns {
let perc = i as f64 / columns as f64;
let style = Style::default().bg(lerp_grad(gradient, perc));
let style = Style::default().bg(Color::lerp_many(gradient, perc).into());
let height = (data[i] as u64 * size.height as u64 / MAX_BAR_VALUE as u64) as u16;

let area = Rect {
Expand Down
47 changes: 8 additions & 39 deletions tori/src/config/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::error::Result;
use crate::{color::Color, error::Result};
use once_cell::sync::OnceCell;
use serde::{Deserialize, Serialize};
use std::{io, path::PathBuf};
Expand All @@ -9,7 +9,7 @@ use shortcuts::Shortcuts;
#[derive(Debug, Serialize, Deserialize)]
pub struct Config {
pub playlists_dir: String,
pub visualizer_gradient: [(u8, u8, u8); 2],
pub visualizer_gradient: Vec<Color>,
pub keybindings: Shortcuts,
pub mpv_ao: Option<String>,
}
Expand Down Expand Up @@ -40,17 +40,11 @@ impl Config {
}
}

if let Some(visualizer_gradient) = other.visualizer_gradient {
let color_at = |i: usize| {
visualizer_gradient[i].to_rgb().unwrap_or_else(|| {
eprintln!(
"Your tori.yaml configuration file has an invalid color in visualizer_gradient: {:?}",
visualizer_gradient[i]
);
std::process::exit(1);
})
};
self.visualizer_gradient = [color_at(0), color_at(1)];
if let Some(mut visualizer_gradient) = other.visualizer_gradient {
for color in &mut visualizer_gradient {
color.precalculate_as_rgb();
}
self.visualizer_gradient = visualizer_gradient;
}

self.mpv_ao = other.mpv_ao;
Expand Down Expand Up @@ -79,35 +73,10 @@ impl Default for Config {
}
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Color {
Rgb(u8, u8, u8),
Str(String),
}

impl Color {
pub fn to_rgb(&self) -> Option<(u8, u8, u8)> {
match self {
Color::Rgb(r, g, b) => Some((*r, *g, *b)),
Color::Str(s) => {
let s = s.trim_start_matches('#');
if s.len() != 6 {
return None;
}
let r = u8::from_str_radix(&s[0..2], 16).ok()?;
let g = u8::from_str_radix(&s[2..4], 16).ok()?;
let b = u8::from_str_radix(&s[4..6], 16).ok()?;
Some((r, g, b))
}
}
}
}

#[derive(Debug, Default, Serialize, Deserialize)]
pub struct OptionalConfig {
pub playlists_dir: Option<String>,
pub visualizer_gradient: Option<[Color; 2]>,
pub visualizer_gradient: Option<Vec<Color>>,
pub keybindings: Option<Shortcuts>,
pub mpv_ao: Option<String>,
}
Expand Down
1 change: 0 additions & 1 deletion tori/src/events/action.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use super::Command;
use crate::config::Config;
use crossterm::event::KeyEvent;

#[derive(Debug, Clone)]
Expand Down
1 change: 1 addition & 0 deletions tori/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ mod dbglog;
mod events;
mod rect_ops;
mod util;
mod color;

0 comments on commit 8293563

Please sign in to comment.