Skip to content

Commit

Permalink
feat: rework harmonized colors into custom colors
Browse files Browse the repository at this point in the history
  • Loading branch information
Theaninova committed Apr 29, 2024
1 parent 3040fe9 commit 6bbb7a6
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 116 deletions.
4 changes: 2 additions & 2 deletions example/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ test = "aaaa"
input_path = "example/colors.whatever-extension"
output_path = "example/a/colors-generated.whatever-extension"

[config.colors_to_harmonize]
[config.custom_colors]
green = "#00FF00"
red = "#FF0000"
blue = "#0000FF"
blue = { color = "#0000FF", blend = false }
113 changes: 59 additions & 54 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,16 @@ use crate::util::{

use indexmap::IndexMap;

use material_colors::{Hct, Scheme};
use material_colors::Scheme;

use clap::{Parser, ValueEnum};
use color_eyre::{eyre::Result, Report};
use log::LevelFilter;
use serde::{Deserialize, Serialize};
use std::io::Write;
use std::{collections::HashMap, io::Write};
use update_informer::{registry, Check};

use util::{arguments::SchemeTypes, color::harmonize_colors};

use material_colors::{
SchemeContent, SchemeExpressive, SchemeFidelity, SchemeFruitSalad, SchemeMonochrome,
SchemeNeutral, SchemeRainbow, SchemeTonalSpot,
};
use util::color::{generate_dynamic_scheme, make_custom_color};

pub struct Schemes {
pub light: IndexMap<String, [u8; 4], ahash::random_state::RandomState>,
Expand Down Expand Up @@ -62,32 +57,77 @@ fn main() -> Result<(), Report> {

let source_color = get_source_color(&args.source)?;

let scheme_dark = generate_scheme(&args.r#type, source_color, true, args.contrast);
let scheme_light = generate_scheme(&args.r#type, source_color, false, args.contrast);
let scheme_dark = Scheme::from(generate_dynamic_scheme(
&args.r#type,
source_color,
true,
args.contrast,
));
let scheme_light = Scheme::from(generate_dynamic_scheme(
&args.r#type,
source_color,
false,
args.contrast,
));

let config: ConfigFile = ConfigFile::read(&args)?;

let default_scheme = args
.mode
.expect("Something went wrong while parsing the mode");

let schemes: Schemes = Schemes {
dark: IndexMap::from_iter(scheme_dark),
light: IndexMap::from_iter(scheme_light),
};

let mut harmonized_colors = None;
let empty = HashMap::new();
let custom_colors = config
.config
.custom_colors
.as_ref()
.unwrap_or(&empty)
.iter()
.map(|(name, color)| {
make_custom_color(
color
.to_custom_color(name.to_string())
.expect("Failed to parse custom color"),
&args.r#type,
source_color,
args.contrast,
)
});
macro_rules! from_color {
($color: expr, $variant: ident) => {
[
(format!("{}_source", $color.color.name), $color.color.value),
(format!("{}_value", $color.color.name), $color.color.value),
(format!("{}", $color.color.name), $color.$variant.color),
(
format!("on_{}", $color.color.name),
$color.$variant.on_color,
),
(
format!("{}_container", $color.color.name),
$color.$variant.color_container,
),
(
format!("on_{}_container", $color.color.name),
$color.$variant.on_color_container,
),
]
};
}
let custom_colors_dark = custom_colors.clone().flat_map(|c| from_color!(c, dark));
let custom_colors_light = custom_colors.flat_map(|c| from_color!(c, light));

if let Some(colors) = &config.config.colors_to_harmonize {
harmonized_colors = Some(harmonize_colors(&source_color, colors));
let schemes: Schemes = Schemes {
dark: IndexMap::from_iter(scheme_dark.into_iter().chain(custom_colors_dark)),
light: IndexMap::from_iter(scheme_light.into_iter().chain(custom_colors_light)),
};

if args.show_colors == Some(true) {
show_color(&schemes, &source_color);
}

if let Some(ref format) = args.json {
dump_json(&schemes, &source_color, format, &harmonized_colors);
dump_json(&schemes, &source_color, format);
}

if args.dry_run == Some(false) {
Expand All @@ -99,7 +139,6 @@ fn main() -> Result<(), Report> {
&source_color,
&default_scheme,
&config.config.custom_keywords,
&harmonized_colors,
)?;

if config.config.reload_apps == Some(true) {
Expand Down Expand Up @@ -168,37 +207,3 @@ fn setup_logging(log_level: LevelFilter) -> Result<(), Report> {
.try_init()?;
Ok(())
}

fn generate_scheme(
scheme_type: &Option<SchemeTypes>,
source_color: [u8; 4],
is_dark: bool,
contrast_level: Option<f64>,
) -> Scheme {
match scheme_type.unwrap() {
SchemeTypes::SchemeContent => {
Scheme::from(SchemeContent::new(Hct::new(source_color), is_dark, contrast_level).scheme)
}
SchemeTypes::SchemeExpressive => Scheme::from(
SchemeExpressive::new(Hct::new(source_color), is_dark, contrast_level).scheme,
),
SchemeTypes::SchemeFidelity => Scheme::from(
SchemeFidelity::new(Hct::new(source_color), is_dark, contrast_level).scheme,
),
SchemeTypes::SchemeFruitSalad => Scheme::from(
SchemeFruitSalad::new(Hct::new(source_color), is_dark, contrast_level).scheme,
),
SchemeTypes::SchemeMonochrome => Scheme::from(
SchemeMonochrome::new(Hct::new(source_color), is_dark, contrast_level).scheme,
),
SchemeTypes::SchemeNeutral => {
Scheme::from(SchemeNeutral::new(Hct::new(source_color), is_dark, contrast_level).scheme)
}
SchemeTypes::SchemeRainbow => {
Scheme::from(SchemeRainbow::new(Hct::new(source_color), is_dark, contrast_level).scheme)
}
SchemeTypes::SchemeTonalSpot => Scheme::from(
SchemeTonalSpot::new(Hct::new(source_color), is_dark, contrast_level).scheme,
),
}
}
117 changes: 77 additions & 40 deletions src/util/color.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
use material_colors::dynamic_color::dynamic_scheme::DynamicScheme;
use material_colors::dynamic_color::material_dynamic_colors::MaterialDynamicColors;
use material_colors::utils::theme::{ColorGroup, CustomColor, CustomColorGroup};
use material_colors::{
Hct, SchemeContent, SchemeExpressive, SchemeFidelity, SchemeFruitSalad, SchemeMonochrome,
SchemeNeutral, SchemeRainbow, SchemeTonalSpot,
};
use owo_colors::{OwoColorize, Style};

use prettytable::{format, Cell, Row, Table};
Expand All @@ -9,7 +16,7 @@ use crate::util::image::fetch_image;
use image::imageops::{resize, FilterType};
use image::io::Reader as ImageReader;

use super::arguments::{ColorFormat, Format, Source};
use super::arguments::{ColorFormat, Format, SchemeTypes, Source};
use super::image::source_color_from_image;
use color_eyre::{eyre::Result, Report};
use colorsys::{ColorAlpha, Hsl, Rgb};
Expand Down Expand Up @@ -74,28 +81,76 @@ pub fn format_hsla(color: &Hsl) -> String {
)
}

pub fn harmonize_colors(
source_color: &[u8; 4],
colors: &HashMap<String, String>,
) -> HashMap<String, [u8; 4]> {
debug!("colors_to_harmonize: {:#?}", &colors);
let mut harmonized_colors: HashMap<String, [u8; 4]> = HashMap::default();

for (name, color) in colors {
let rgb = Rgb::from_hex_str(color)
.expect("Invalid hex color string provided for `harmonized_colors`");

let argb: [u8; 4] = [
rgb.alpha() as u8,
rgb.red() as u8,
rgb.green() as u8,
rgb.blue() as u8,
];
harmonized_colors.insert(name.to_string(), harmonize(argb, *source_color));
pub fn generate_dynamic_scheme(
scheme_type: &Option<SchemeTypes>,
source_color: [u8; 4],
is_dark: bool,
contrast_level: Option<f64>,
) -> DynamicScheme {
match scheme_type.unwrap() {
SchemeTypes::SchemeContent => {
SchemeContent::new(Hct::new(source_color), is_dark, contrast_level).scheme
}
SchemeTypes::SchemeExpressive => {
SchemeExpressive::new(Hct::new(source_color), is_dark, contrast_level).scheme
}
SchemeTypes::SchemeFidelity => {
SchemeFidelity::new(Hct::new(source_color), is_dark, contrast_level).scheme
}
SchemeTypes::SchemeFruitSalad => {
SchemeFruitSalad::new(Hct::new(source_color), is_dark, contrast_level).scheme
}
SchemeTypes::SchemeMonochrome => {
SchemeMonochrome::new(Hct::new(source_color), is_dark, contrast_level).scheme
}
SchemeTypes::SchemeNeutral => {
SchemeNeutral::new(Hct::new(source_color), is_dark, contrast_level).scheme
}
SchemeTypes::SchemeRainbow => {
SchemeRainbow::new(Hct::new(source_color), is_dark, contrast_level).scheme
}
SchemeTypes::SchemeTonalSpot => {
SchemeTonalSpot::new(Hct::new(source_color), is_dark, contrast_level).scheme
}
}
}

debug!("harmonized_colors: {:#?}", &harmonized_colors);
harmonized_colors
pub fn make_custom_color(
color: CustomColor,
scheme_type: &Option<SchemeTypes>,
source_color: [u8; 4],
contrast_level: Option<f64>,
) -> CustomColorGroup {
debug!("make_custom_color: {:#?}", &color);

let value = if color.blend {
harmonize(color.value, source_color)
} else {
color.value
};

let light = generate_dynamic_scheme(scheme_type, value, false, contrast_level);
let dark = generate_dynamic_scheme(scheme_type, value, true, contrast_level);

let custom_color = CustomColorGroup {
color,
value,
light: ColorGroup {
color: MaterialDynamicColors::primary().get_argb(&light),
on_color: MaterialDynamicColors::on_primary().get_argb(&light),
color_container: MaterialDynamicColors::primary_container().get_argb(&light),
on_color_container: MaterialDynamicColors::on_primary_container().get_argb(&light),
},
dark: ColorGroup {
color: MaterialDynamicColors::primary().get_argb(&dark),
on_color: MaterialDynamicColors::on_primary().get_argb(&dark),
color_container: MaterialDynamicColors::primary_container().get_argb(&dark),
on_color_container: MaterialDynamicColors::on_primary_container().get_argb(&dark),
},
};

debug!("custom_color: {:#?}", &custom_color);
custom_color
}

pub fn show_color(schemes: &Schemes, source_color: &[u8; 4]) {
Expand All @@ -118,12 +173,7 @@ pub fn show_color(schemes: &Schemes, source_color: &[u8; 4]) {
table.printstd();
}

pub fn dump_json(
schemes: &Schemes,
source_color: &[u8; 4],
format: &Format,
harmonized_colors: &Option<HashMap<String, [u8; 4]>>,
) {
pub fn dump_json(schemes: &Schemes, source_color: &[u8; 4], format: &Format) {
type F = Format;
let fmt = match format {
F::Rgb => |c: Rgb| format!("rgb({:?}, {:?}, {:?})", c.red(), c.green(), c.blue()),
Expand Down Expand Up @@ -152,18 +202,6 @@ pub fn dump_json(
colors_normal_light.insert(field, fmt(color_light));
colors_normal_dark.insert(field, fmt(color_dark));
}

let mut harmonized_colors_map: HashMap<&str, String> = HashMap::new();

match harmonized_colors {
Some(harmonized_colors) => {
for (name, color) in harmonized_colors {
let color: Rgb = rgb_from_argb(*color);
harmonized_colors_map.insert(name.as_str(), fmt(color));
}
}
None => {}
}

colors_normal_light.insert("source_color", fmt(rgb_from_argb(*source_color)));

Expand All @@ -174,7 +212,6 @@ harmonized_colors_map.insert(name.as_str(), fmt(color));
"light": colors_normal_light,
"dark": colors_normal_dark,
},
"harmonized_colors": harmonized_colors_map,
})
);
}
Expand Down
30 changes: 29 additions & 1 deletion src/util/config.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use directories::ProjectDirs;
use material_colors::{argb_from_hex, utils::string::ParseError};
use std::collections::HashMap;
use std::fs;
use std::path::PathBuf;
Expand All @@ -18,6 +19,33 @@ pub enum WallpaperTool {
Feh,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(untagged)]
pub enum CustomColor {
Color(String),
Options { color: String, blend: bool },
}

impl CustomColor {
pub fn to_custom_color(
&self,
name: String,
) -> Result<material_colors::utils::theme::CustomColor, ParseError> {
Ok(match self {
CustomColor::Color(color) => material_colors::utils::theme::CustomColor {
value: argb_from_hex(color)?,
blend: true,
name,
},
CustomColor::Options { color, blend } => material_colors::utils::theme::CustomColor {
value: argb_from_hex(color)?,
blend: *blend,
name,
},
})
}
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Config {
pub reload_apps: Option<bool>,
Expand All @@ -29,7 +57,7 @@ pub struct Config {
pub feh_options: Option<Vec<String>>,
pub prefix: Option<String>,
pub custom_keywords: Option<HashMap<String, String>>,
pub colors_to_harmonize: Option<HashMap<String, String>>,
pub custom_colors: Option<HashMap<String, CustomColor>>,
}

#[derive(Deserialize, Serialize, Debug)]
Expand Down
Loading

0 comments on commit 6bbb7a6

Please sign in to comment.