Abstract into ColorPicker and ColorSpace trait
Each color type implements ColorSpace to define its own representation and update methods. View sliders are implemented on the ColorPicker struct.
This commit is contained in:
parent
3e71eaee37
commit
430f78a693
@ -3,6 +3,8 @@ use iced::{
|
||||
Settings, Slider, Text,
|
||||
};
|
||||
use palette::{self, Limited};
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::RangeInclusive;
|
||||
|
||||
pub fn main() {
|
||||
ColorPalette::run(Settings {
|
||||
@ -51,20 +53,288 @@ fn generate_theme(base_color: &Color) -> Vec<Color> {
|
||||
theme
|
||||
}
|
||||
|
||||
struct ColorPicker<C: ColorSpace> {
|
||||
sliders: [slider::State; 3],
|
||||
color_space: PhantomData<C>,
|
||||
}
|
||||
|
||||
trait ColorSpace: Sized {
|
||||
const LABEL: &'static str;
|
||||
const COMPONENT_RANGES: [RangeInclusive<f32>; 3];
|
||||
|
||||
fn new(a: f32, b: f32, c: f32) -> Self;
|
||||
|
||||
fn components(&self) -> [f32; 3];
|
||||
|
||||
fn update_component(c: Self, i: usize, val: f32) -> Self;
|
||||
|
||||
fn to_string(&self) -> String;
|
||||
}
|
||||
|
||||
impl<C: 'static + ColorSpace + Copy> ColorPicker<C> {
|
||||
fn view(&mut self, color: C) -> Element<C> {
|
||||
let [c1, c2, c3] = color.components();
|
||||
let [s1, s2, s3] = &mut self.sliders;
|
||||
let [cr1, cr2, cr3] = C::COMPONENT_RANGES;
|
||||
Row::new()
|
||||
.spacing(10)
|
||||
.push(Text::new(C::LABEL).width(Length::Units(50)))
|
||||
.push(Slider::new(s1, cr1, c1, move |v| {
|
||||
C::update_component(color, 0, v)
|
||||
}))
|
||||
.push(Slider::new(s2, cr2, c2, move |v| {
|
||||
C::update_component(color, 1, v)
|
||||
}))
|
||||
.push(Slider::new(s3, cr3, c3, move |v| {
|
||||
C::update_component(color, 2, v)
|
||||
}))
|
||||
.push(
|
||||
Text::new(color.to_string())
|
||||
.width(Length::Units(185))
|
||||
.size(16),
|
||||
)
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl ColorSpace for Color {
|
||||
const LABEL: &'static str = "RGB";
|
||||
const COMPONENT_RANGES: [RangeInclusive<f32>; 3] =
|
||||
[0.0..=1.0, 0.0..=1.0, 0.0..=1.0];
|
||||
|
||||
fn new(r: f32, g: f32, b: f32) -> Self {
|
||||
Color::from_rgb(r, g, b)
|
||||
}
|
||||
|
||||
fn components(&self) -> [f32; 3] {
|
||||
[self.r, self.g, self.b]
|
||||
}
|
||||
|
||||
fn update_component(c: Color, i: usize, val: f32) -> Self {
|
||||
match i {
|
||||
0 => Color { r: val, ..c },
|
||||
1 => Color { g: val, ..c },
|
||||
2 => Color { b: val, ..c },
|
||||
_ => panic!("Invalid component index: {:?}", i),
|
||||
}
|
||||
}
|
||||
|
||||
fn to_string(&self) -> String {
|
||||
format!(
|
||||
"rgb({:.0}, {:.0}, {:.0})",
|
||||
255.0 * self.r,
|
||||
255.0 * self.g,
|
||||
255.0 * self.b
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl ColorSpace for palette::Hsl {
|
||||
const LABEL: &'static str = "HSL";
|
||||
const COMPONENT_RANGES: [RangeInclusive<f32>; 3] =
|
||||
[0.0..=360.0, 0.0..=1.0, 0.0..=1.0];
|
||||
|
||||
fn new(hue: f32, saturation: f32, lightness: f32) -> Self {
|
||||
palette::Hsl::new(
|
||||
palette::RgbHue::from_degrees(hue),
|
||||
saturation,
|
||||
lightness,
|
||||
)
|
||||
}
|
||||
|
||||
fn components(&self) -> [f32; 3] {
|
||||
[
|
||||
self.hue.to_positive_degrees(),
|
||||
self.saturation,
|
||||
self.lightness,
|
||||
]
|
||||
}
|
||||
|
||||
fn update_component(c: palette::Hsl, i: usize, val: f32) -> Self {
|
||||
match i {
|
||||
0 => palette::Hsl {
|
||||
hue: palette::RgbHue::from_degrees(val),
|
||||
..c
|
||||
},
|
||||
1 => palette::Hsl {
|
||||
saturation: val,
|
||||
..c
|
||||
},
|
||||
2 => palette::Hsl {
|
||||
lightness: val,
|
||||
..c
|
||||
},
|
||||
_ => panic!("Invalid component index: {:?}", i),
|
||||
}
|
||||
}
|
||||
|
||||
fn to_string(&self) -> String {
|
||||
format!(
|
||||
"hsl({:.1}, {:.1}%, {:.1}%)",
|
||||
self.hue.to_positive_degrees(),
|
||||
100.0 * self.saturation,
|
||||
100.0 * self.lightness
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl ColorSpace for palette::Hsv {
|
||||
const LABEL: &'static str = "HSV";
|
||||
const COMPONENT_RANGES: [RangeInclusive<f32>; 3] =
|
||||
[0.0..=360.0, 0.0..=1.0, 0.0..=1.0];
|
||||
|
||||
fn new(hue: f32, saturation: f32, value: f32) -> Self {
|
||||
palette::Hsv::new(palette::RgbHue::from_degrees(hue), saturation, value)
|
||||
}
|
||||
|
||||
fn components(&self) -> [f32; 3] {
|
||||
[self.hue.to_positive_degrees(), self.saturation, self.value]
|
||||
}
|
||||
|
||||
fn update_component(c: palette::Hsv, i: usize, val: f32) -> Self {
|
||||
match i {
|
||||
0 => palette::Hsv {
|
||||
hue: palette::RgbHue::from_degrees(val),
|
||||
..c
|
||||
},
|
||||
1 => palette::Hsv {
|
||||
saturation: val,
|
||||
..c
|
||||
},
|
||||
2 => palette::Hsv { value: val, ..c },
|
||||
_ => panic!("Invalid component index: {:?}", i),
|
||||
}
|
||||
}
|
||||
|
||||
fn to_string(&self) -> String {
|
||||
format!(
|
||||
"hsv({:.1}, {:.1}%, {:.1}%)",
|
||||
self.hue.to_positive_degrees(),
|
||||
100.0 * self.saturation,
|
||||
100.0 * self.value
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl ColorSpace for palette::Hwb {
|
||||
const LABEL: &'static str = "HWB";
|
||||
const COMPONENT_RANGES: [RangeInclusive<f32>; 3] =
|
||||
[0.0..=360.0, 0.0..=1.0, 0.0..=1.0];
|
||||
|
||||
fn new(hue: f32, whiteness: f32, blackness: f32) -> Self {
|
||||
palette::Hwb::new(
|
||||
palette::RgbHue::from_degrees(hue),
|
||||
whiteness,
|
||||
blackness,
|
||||
)
|
||||
}
|
||||
|
||||
fn components(&self) -> [f32; 3] {
|
||||
[
|
||||
self.hue.to_positive_degrees(),
|
||||
self.whiteness,
|
||||
self.blackness,
|
||||
]
|
||||
}
|
||||
|
||||
fn update_component(c: palette::Hwb, i: usize, val: f32) -> Self {
|
||||
match i {
|
||||
0 => palette::Hwb {
|
||||
hue: palette::RgbHue::from_degrees(val),
|
||||
..c
|
||||
},
|
||||
1 => palette::Hwb {
|
||||
whiteness: val,
|
||||
..c
|
||||
},
|
||||
2 => palette::Hwb {
|
||||
blackness: val,
|
||||
..c
|
||||
},
|
||||
_ => panic!("Invalid component index: {:?}", i),
|
||||
}
|
||||
}
|
||||
|
||||
fn to_string(&self) -> String {
|
||||
format!(
|
||||
"hwb({:.1}, {:.1}%, {:.1}%)",
|
||||
self.hue.to_positive_degrees(),
|
||||
100.0 * self.whiteness,
|
||||
100.0 * self.blackness
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl ColorSpace for palette::Lab {
|
||||
const LABEL: &'static str = "Lab";
|
||||
const COMPONENT_RANGES: [RangeInclusive<f32>; 3] =
|
||||
[0.0..=100.0, -128.0..=127.0, -128.0..=127.0];
|
||||
|
||||
fn new(l: f32, a: f32, b: f32) -> Self {
|
||||
palette::Lab::new(l, a, b)
|
||||
}
|
||||
|
||||
fn components(&self) -> [f32; 3] {
|
||||
[self.l, self.a, self.b]
|
||||
}
|
||||
|
||||
fn update_component(c: palette::Lab, i: usize, val: f32) -> Self {
|
||||
match i {
|
||||
0 => palette::Lab { l: val, ..c },
|
||||
1 => palette::Lab { a: val, ..c },
|
||||
2 => palette::Lab { b: val, ..c },
|
||||
_ => panic!("Invalid component index: {:?}", i),
|
||||
}
|
||||
}
|
||||
|
||||
fn to_string(&self) -> String {
|
||||
format!("Lab({:.1}, {:.1}, {:.1})", self.l, self.a, self.b)
|
||||
}
|
||||
}
|
||||
|
||||
impl ColorSpace for palette::Lch {
|
||||
const LABEL: &'static str = "Lch";
|
||||
const COMPONENT_RANGES: [RangeInclusive<f32>; 3] =
|
||||
[0.0..=100.0, 0.0..=128.0, 0.0..=360.0];
|
||||
|
||||
fn new(l: f32, chroma: f32, hue: f32) -> Self {
|
||||
palette::Lch::new(l, chroma, palette::LabHue::from_degrees(hue))
|
||||
}
|
||||
|
||||
fn components(&self) -> [f32; 3] {
|
||||
[self.l, self.chroma, self.hue.to_positive_degrees()]
|
||||
}
|
||||
|
||||
fn update_component(c: palette::Lch, i: usize, val: f32) -> Self {
|
||||
match i {
|
||||
0 => palette::Lch { l: val, ..c },
|
||||
1 => palette::Lch { chroma: val, ..c },
|
||||
2 => palette::Lch {
|
||||
hue: palette::LabHue::from_degrees(val),
|
||||
..c
|
||||
},
|
||||
_ => panic!("Invalid component index: {:?}", i),
|
||||
}
|
||||
}
|
||||
|
||||
fn to_string(&self) -> String {
|
||||
format!(
|
||||
"Lch({:.1}, {:.1}, {:.1})",
|
||||
self.l,
|
||||
self.chroma,
|
||||
self.hue.to_positive_degrees()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ColorPalette {
|
||||
state: State,
|
||||
rgb_sliders: [slider::State; 3],
|
||||
hsl_sliders: [slider::State; 3],
|
||||
hsv_sliders: [slider::State; 3],
|
||||
hwb_sliders: [slider::State; 3],
|
||||
lab_sliders: [slider::State; 3],
|
||||
lch_sliders: [slider::State; 3],
|
||||
rgb_text_value: String,
|
||||
hsl_text_value: String,
|
||||
hsv_text_value: String,
|
||||
hwb_text_value: String,
|
||||
lab_text_value: String,
|
||||
lch_text_value: String,
|
||||
rgb: ColorPicker<Color>,
|
||||
hsl: ColorPicker<palette::Hsl>,
|
||||
hsv: ColorPicker<palette::Hsv>,
|
||||
hwb: ColorPicker<palette::Hwb>,
|
||||
lab: ColorPicker<palette::Lab>,
|
||||
lch: ColorPicker<palette::Lch>,
|
||||
canvas_layer: canvas::layer::Cache<State>,
|
||||
}
|
||||
|
||||
@ -90,28 +360,33 @@ impl Sandbox for ColorPalette {
|
||||
]
|
||||
}
|
||||
|
||||
let state = State::new();
|
||||
let rgb_text_value = color_str(&state.color, ColorFormat::Rgb);
|
||||
let hsl_text_value = color_str(&state.color, ColorFormat::Hsl);
|
||||
let hsv_text_value = color_str(&state.color, ColorFormat::Hsv);
|
||||
let hwb_text_value = color_str(&state.color, ColorFormat::Hwb);
|
||||
let lab_text_value = color_str(&state.color, ColorFormat::Lab);
|
||||
let lch_text_value = color_str(&state.color, ColorFormat::Lch);
|
||||
|
||||
ColorPalette {
|
||||
state,
|
||||
rgb_sliders: triple_slider(),
|
||||
hsl_sliders: triple_slider(),
|
||||
hsv_sliders: triple_slider(),
|
||||
hwb_sliders: triple_slider(),
|
||||
lab_sliders: triple_slider(),
|
||||
lch_sliders: triple_slider(),
|
||||
rgb_text_value,
|
||||
hsl_text_value,
|
||||
hsv_text_value,
|
||||
hwb_text_value,
|
||||
lab_text_value,
|
||||
lch_text_value,
|
||||
state: State::new(),
|
||||
rgb: ColorPicker {
|
||||
sliders: triple_slider(),
|
||||
color_space: PhantomData::<Color>,
|
||||
},
|
||||
hsl: ColorPicker {
|
||||
sliders: triple_slider(),
|
||||
color_space: PhantomData::<palette::Hsl>,
|
||||
},
|
||||
hsv: ColorPicker {
|
||||
sliders: triple_slider(),
|
||||
color_space: PhantomData::<palette::Hsv>,
|
||||
},
|
||||
|
||||
hwb: ColorPicker {
|
||||
sliders: triple_slider(),
|
||||
color_space: PhantomData::<palette::Hwb>,
|
||||
},
|
||||
lab: ColorPicker {
|
||||
sliders: triple_slider(),
|
||||
color_space: PhantomData::<palette::Lab>,
|
||||
},
|
||||
lch: ColorPicker {
|
||||
sliders: triple_slider(),
|
||||
color_space: PhantomData::<palette::Lch>,
|
||||
},
|
||||
canvas_layer: canvas::layer::Cache::new(),
|
||||
}
|
||||
}
|
||||
@ -135,24 +410,9 @@ impl Sandbox for ColorPalette {
|
||||
|
||||
// Set theme colors
|
||||
self.state.theme = generate_theme(&self.state.color);
|
||||
|
||||
// Set text
|
||||
self.rgb_text_value = color_str(&self.state.color, ColorFormat::Rgb);
|
||||
self.hsl_text_value = color_str(&self.state.color, ColorFormat::Hsl);
|
||||
self.hsv_text_value = color_str(&self.state.color, ColorFormat::Hsv);
|
||||
self.hwb_text_value = color_str(&self.state.color, ColorFormat::Hwb);
|
||||
self.lab_text_value = color_str(&self.state.color, ColorFormat::Lab);
|
||||
self.lch_text_value = color_str(&self.state.color, ColorFormat::Lch);
|
||||
}
|
||||
|
||||
fn view(&mut self) -> Element<Message> {
|
||||
let [rgb1, rgb2, rgb3] = &mut self.rgb_sliders;
|
||||
let [hsl1, hsl2, hsl3] = &mut self.hsl_sliders;
|
||||
let [hsv1, hsv2, hsv3] = &mut self.hsv_sliders;
|
||||
let [hwb1, hwb2, hwb3] = &mut self.hwb_sliders;
|
||||
let [lab1, lab2, lab3] = &mut self.lab_sliders;
|
||||
let [lch1, lch2, lch3] = &mut self.lch_sliders;
|
||||
|
||||
let color = self.state.color;
|
||||
let srgb = palette::Srgb::from(self.state.color);
|
||||
let hsl = palette::Hsl::from(srgb);
|
||||
@ -164,208 +424,12 @@ impl Sandbox for ColorPalette {
|
||||
Column::new()
|
||||
.padding(10)
|
||||
.spacing(10)
|
||||
.push(
|
||||
Row::new()
|
||||
.spacing(10)
|
||||
.push(Text::new("RGB").width(Length::Units(50)))
|
||||
.push(Slider::new(rgb1, 0.0..=1.0, color.r, move |r| {
|
||||
Message::RgbColorChanged(Color { r, ..color })
|
||||
}))
|
||||
.push(Slider::new(rgb2, 0.0..=1.0, color.g, move |g| {
|
||||
Message::RgbColorChanged(Color { g, ..color })
|
||||
}))
|
||||
.push(Slider::new(rgb3, 0.0..=1.0, color.b, move |b| {
|
||||
Message::RgbColorChanged(Color { b, ..color })
|
||||
}))
|
||||
.push(
|
||||
Text::new(&self.rgb_text_value)
|
||||
.width(Length::Units(185))
|
||||
.size(16),
|
||||
),
|
||||
)
|
||||
.push(
|
||||
Row::new()
|
||||
.spacing(10)
|
||||
.push(Text::new("HSL").width(Length::Units(50)))
|
||||
.push(Slider::new(
|
||||
hsl1,
|
||||
0.0..=360.0,
|
||||
hsl.hue.to_positive_degrees(),
|
||||
move |hue| {
|
||||
Message::HslColorChanged(palette::Hsl {
|
||||
hue: palette::RgbHue::from_degrees(hue),
|
||||
..hsl
|
||||
})
|
||||
},
|
||||
))
|
||||
.push(Slider::new(
|
||||
hsl2,
|
||||
0.0..=1.0,
|
||||
hsl.saturation,
|
||||
move |saturation| {
|
||||
Message::HslColorChanged(palette::Hsl {
|
||||
saturation,
|
||||
..hsl
|
||||
})
|
||||
},
|
||||
))
|
||||
.push(Slider::new(
|
||||
hsl3,
|
||||
0.0..=1.0,
|
||||
hsl.lightness,
|
||||
move |lightness| {
|
||||
Message::HslColorChanged(palette::Hsl {
|
||||
lightness,
|
||||
..hsl
|
||||
})
|
||||
},
|
||||
))
|
||||
.push(
|
||||
Text::new(&self.hsl_text_value)
|
||||
.width(Length::Units(185))
|
||||
.size(16),
|
||||
),
|
||||
)
|
||||
.push(
|
||||
Row::new()
|
||||
.spacing(10)
|
||||
.push(Text::new("HSV").width(Length::Units(50)))
|
||||
.push(Slider::new(
|
||||
hsv1,
|
||||
0.0..=360.0,
|
||||
hsv.hue.to_positive_degrees(),
|
||||
move |hue| {
|
||||
Message::HsvColorChanged(palette::Hsv {
|
||||
hue: palette::RgbHue::from_degrees(hue),
|
||||
..hsv
|
||||
})
|
||||
},
|
||||
))
|
||||
.push(Slider::new(
|
||||
hsv2,
|
||||
0.0..=1.0,
|
||||
hsv.saturation,
|
||||
move |saturation| {
|
||||
Message::HsvColorChanged(palette::Hsv {
|
||||
saturation,
|
||||
..hsv
|
||||
})
|
||||
},
|
||||
))
|
||||
.push(Slider::new(
|
||||
hsv3,
|
||||
0.0..=1.0,
|
||||
hsv.value,
|
||||
move |value| {
|
||||
Message::HsvColorChanged(palette::Hsv {
|
||||
value,
|
||||
..hsv
|
||||
})
|
||||
},
|
||||
))
|
||||
.push(
|
||||
Text::new(&self.hsv_text_value)
|
||||
.width(Length::Units(185))
|
||||
.size(16),
|
||||
),
|
||||
)
|
||||
.push(
|
||||
Row::new()
|
||||
.spacing(10)
|
||||
.push(Text::new("HWB").width(Length::Units(50)))
|
||||
.push(Slider::new(
|
||||
hwb1,
|
||||
0.0..=360.0,
|
||||
hwb.hue.to_positive_degrees(),
|
||||
move |hue| {
|
||||
Message::HwbColorChanged(palette::Hwb {
|
||||
hue: palette::RgbHue::from_degrees(hue),
|
||||
..hwb
|
||||
})
|
||||
},
|
||||
))
|
||||
.push(Slider::new(
|
||||
hwb2,
|
||||
0.0..=1.0,
|
||||
hwb.whiteness,
|
||||
move |whiteness| {
|
||||
Message::HwbColorChanged(palette::Hwb {
|
||||
whiteness,
|
||||
..hwb
|
||||
})
|
||||
},
|
||||
))
|
||||
.push(Slider::new(
|
||||
hwb3,
|
||||
0.0..=1.0,
|
||||
hwb.blackness,
|
||||
move |blackness| {
|
||||
Message::HwbColorChanged(palette::Hwb {
|
||||
blackness,
|
||||
..hwb
|
||||
})
|
||||
},
|
||||
))
|
||||
.push(
|
||||
Text::new(&self.hwb_text_value)
|
||||
.width(Length::Units(185))
|
||||
.size(16),
|
||||
),
|
||||
)
|
||||
.push(
|
||||
Row::new()
|
||||
.spacing(10)
|
||||
.push(Text::new("Lab").width(Length::Units(50)))
|
||||
.push(Slider::new(lab1, 0.0..=100.0, lab.l, move |l| {
|
||||
Message::LabColorChanged(palette::Lab { l, ..lab })
|
||||
}))
|
||||
.push(Slider::new(lab2, -128.0..=127.0, lab.a, move |a| {
|
||||
Message::LabColorChanged(palette::Lab { a, ..lab })
|
||||
}))
|
||||
.push(Slider::new(lab3, -128.0..=127.0, lab.b, move |b| {
|
||||
Message::LabColorChanged(palette::Lab { b, ..lab })
|
||||
}))
|
||||
.push(
|
||||
Text::new(&self.lab_text_value)
|
||||
.width(Length::Units(185))
|
||||
.size(16),
|
||||
),
|
||||
)
|
||||
.push(
|
||||
Row::new()
|
||||
.spacing(10)
|
||||
.push(Text::new("Lch").width(Length::Units(50)))
|
||||
.push(Slider::new(lch1, 0.0..=100.0, lch.l, move |l| {
|
||||
Message::LchColorChanged(palette::Lch { l, ..lch })
|
||||
}))
|
||||
.push(Slider::new(
|
||||
lch2,
|
||||
0.0..=128.0,
|
||||
lch.chroma,
|
||||
move |chroma| {
|
||||
Message::LchColorChanged(palette::Lch {
|
||||
chroma,
|
||||
..lch
|
||||
})
|
||||
},
|
||||
))
|
||||
.push(Slider::new(
|
||||
lch3,
|
||||
0.0..=360.0,
|
||||
lch.hue.to_positive_degrees(),
|
||||
move |hue| {
|
||||
Message::LchColorChanged(palette::Lch {
|
||||
hue: palette::LabHue::from_degrees(hue),
|
||||
..lch
|
||||
})
|
||||
},
|
||||
))
|
||||
.push(
|
||||
Text::new(&self.lch_text_value)
|
||||
.width(Length::Units(185))
|
||||
.size(16),
|
||||
),
|
||||
)
|
||||
.push(self.rgb.view(color).map(Message::RgbColorChanged))
|
||||
.push(self.hsl.view(hsl).map(Message::HslColorChanged))
|
||||
.push(self.hsv.view(hsv).map(Message::HsvColorChanged))
|
||||
.push(self.hwb.view(hwb).map(Message::HwbColorChanged))
|
||||
.push(self.lab.view(lab).map(Message::LabColorChanged))
|
||||
.push(self.lch.view(lch).map(Message::LchColorChanged))
|
||||
.push(
|
||||
Canvas::new()
|
||||
.width(Length::Fill)
|
||||
@ -395,7 +459,6 @@ impl canvas::Drawable for State {
|
||||
use palette::{Hsl, Srgb};
|
||||
|
||||
if self.theme.len() == 0 {
|
||||
println!("Zero len");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -464,7 +527,7 @@ impl canvas::Drawable for State {
|
||||
}
|
||||
|
||||
frame.fill_text(canvas::Text {
|
||||
content: color_str(&self.theme[i], ColorFormat::Hex),
|
||||
content: color_hex_str(&self.theme[i]),
|
||||
position: Point {
|
||||
x: anchor.x + box_size.width / 2.0,
|
||||
y: box_size.height,
|
||||
@ -494,7 +557,7 @@ impl canvas::Drawable for State {
|
||||
frame.fill(&rect, Fill::Color(color));
|
||||
|
||||
frame.fill_text(canvas::Text {
|
||||
content: color_str(&color, ColorFormat::Hex),
|
||||
content: color_hex_str(&color),
|
||||
position: Point {
|
||||
x: anchor.x + box_size.width / 2.0,
|
||||
y: box_size.height + 2.0 * pad,
|
||||
@ -505,63 +568,11 @@ impl canvas::Drawable for State {
|
||||
}
|
||||
}
|
||||
|
||||
enum ColorFormat {
|
||||
Hex,
|
||||
Rgb,
|
||||
Hsl,
|
||||
Hsv,
|
||||
Hwb,
|
||||
Lab,
|
||||
Lch,
|
||||
}
|
||||
|
||||
fn color_str(color: &Color, color_format: ColorFormat) -> String {
|
||||
let srgb = palette::Srgb::from(*color);
|
||||
let hsl = palette::Hsl::from(srgb);
|
||||
let hsv = palette::Hsv::from(srgb);
|
||||
let hwb = palette::Hwb::from(srgb);
|
||||
let lab = palette::Lab::from(srgb);
|
||||
let lch = palette::Lch::from(srgb);
|
||||
|
||||
match color_format {
|
||||
ColorFormat::Hex => format!(
|
||||
"#{:x}{:x}{:x}",
|
||||
(255.0 * color.r).round() as u8,
|
||||
(255.0 * color.g).round() as u8,
|
||||
(255.0 * color.b).round() as u8
|
||||
),
|
||||
ColorFormat::Rgb => format!(
|
||||
"rgb({:.0}, {:.0}, {:.0})",
|
||||
255.0 * color.r,
|
||||
255.0 * color.g,
|
||||
255.0 * color.b
|
||||
),
|
||||
ColorFormat::Hsl => format!(
|
||||
"hsl({:.1}, {:.1}%, {:.1}%)",
|
||||
hsl.hue.to_positive_degrees(),
|
||||
100.0 * hsl.saturation,
|
||||
100.0 * hsl.lightness
|
||||
),
|
||||
ColorFormat::Hsv => format!(
|
||||
"hsv({:.1}, {:.1}%, {:.1}%)",
|
||||
hsv.hue.to_positive_degrees(),
|
||||
100.0 * hsv.saturation,
|
||||
100.0 * hsv.value
|
||||
),
|
||||
ColorFormat::Hwb => format!(
|
||||
"hwb({:.1}, {:.1}%, {:.1}%)",
|
||||
hwb.hue.to_positive_degrees(),
|
||||
100.0 * hwb.whiteness,
|
||||
100.0 * hwb.blackness
|
||||
),
|
||||
ColorFormat::Lab => {
|
||||
format!("Lab({:.1}, {:.1}, {:.1})", lab.l, lab.a, lab.b)
|
||||
}
|
||||
ColorFormat::Lch => format!(
|
||||
"Lch({:.1}, {:.1}, {:.1})",
|
||||
lch.l,
|
||||
lch.chroma,
|
||||
lch.hue.to_positive_degrees()
|
||||
),
|
||||
}
|
||||
fn color_hex_str(color: &Color) -> String {
|
||||
format!(
|
||||
"#{:x}{:x}{:x}",
|
||||
(255.0 * color.r).round() as u8,
|
||||
(255.0 * color.g).round() as u8,
|
||||
(255.0 * color.b).round() as u8
|
||||
)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user