Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow a vector of colors in visualizer_gradient #40

Merged
merged 1 commit into from
Feb 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
Loading