libcosmic/cosmic-theme/src/model/selection.rs

99 lines
3.5 KiB
Rust

use palette::{named, IntoColor, Lch, Srgba};
use std::convert::TryFrom;
/// A Selection is a group of colors from which a cosmic palette can be derived
#[derive(Copy, Clone, Debug, Default)]
pub struct Selection<C> {
/// base background container color
pub background: C,
/// base primary container color
pub primary_container: C,
/// base secondary container color
pub secondary_container: C,
/// base accent color
pub accent: C,
/// custom accent color (overrides base)
pub accent_fg: Option<C>,
/// custom accent nav handle text color (overrides base)
pub accent_nav_handle_fg: Option<C>,
/// base destructive element color
pub destructive: C,
/// base destructive element color
pub warning: C,
/// base destructive element color
pub success: C,
}
// vector should be in order of most common
impl<C> TryFrom<Vec<Srgba>> for Selection<C>
where
C: Clone + From<Srgba>,
{
type Error = anyhow::Error;
fn try_from(mut colors: Vec<Srgba>) -> Result<Self, Self::Error> {
if colors.len() < 8 {
anyhow::bail!("length of inputted vector must be at least 8.")
} else {
let lch_colors: Vec<Lch> = colors
.iter()
.map(|x| {
let srgba: Srgba = x.clone().into();
srgba.color.into_format().into_color()
})
.collect();
let red_lch: Lch = named::CRIMSON.into_format().into_color();
let mut reddest_i = 1;
for (i, c) in lch_colors[1..].iter().enumerate() {
let d_cur = (c.hue.to_degrees() - red_lch.hue.to_degrees()).abs();
let reddest_d = (lch_colors[reddest_i].hue.to_degrees().abs()
- red_lch.hue.to_degrees().abs())
.abs();
if d_cur < reddest_d {
reddest_i = i;
}
}
let yellow_lch: Lch = named::YELLOW.into_format().into_color();
let mut yellow_i = 1;
for (i, c) in lch_colors[1..].iter().enumerate() {
let d_cur = (c.hue.to_degrees() - yellow_lch.hue.to_degrees()).abs();
let reddest_d = (lch_colors[yellow_i].hue.to_degrees().abs()
- yellow_lch.hue.to_degrees().abs())
.abs();
if d_cur < reddest_d {
yellow_i = i;
}
}
let green_lch: Lch = named::GREEN.into_format().into_color();
let mut green_i = 1;
for (i, c) in lch_colors[1..].iter().enumerate() {
let d_cur = (c.hue.to_degrees() - green_lch.hue.to_degrees()).abs();
let reddest_d = (lch_colors[green_i].hue.to_degrees().abs()
- green_lch.hue.to_degrees().abs())
.abs();
if d_cur < reddest_d {
green_i = i;
}
}
let red = colors.remove(reddest_i);
let green = colors.remove(green_i);
let yellow = colors.remove(yellow_i);
Ok(Self {
background: colors[0].into(),
primary_container: colors[1].into(),
secondary_container: colors[3].into(),
accent: colors[2].into(),
accent_fg: Some(colors[2].into()),
accent_nav_handle_fg: Some(colors[2].into()),
destructive: red.into(),
warning: yellow.into(),
success: green.into(),
})
}
}
}