diff options
| author | 2020-04-27 16:25:13 -0500 | |
|---|---|---|
| committer | 2020-04-27 16:25:13 -0500 | |
| commit | 430f78a693a87e9ba3ac4638cac96aab57dd3042 (patch) | |
| tree | 9a1dcb34ef72d7f5e82d0ddcbb8599b8bdd03942 /examples | |
| parent | 3e71eaee37bc3aea85feb0f643dcbd4ecc11d0c4 (diff) | |
| download | iced-430f78a693a87e9ba3ac4638cac96aab57dd3042.tar.gz iced-430f78a693a87e9ba3ac4638cac96aab57dd3042.tar.bz2 iced-430f78a693a87e9ba3ac4638cac96aab57dd3042.zip  | |
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.
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/color_palette/src/main.rs | 635 | 
1 files changed, 323 insertions, 312 deletions
diff --git a/examples/color_palette/src/main.rs b/examples/color_palette/src/main.rs index 76a6bf17..993b7fb0 100644 --- a/examples/color_palette/src/main.rs +++ b/examples/color_palette/src/main.rs @@ -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 +    )  }  | 
