diff --git a/src/widget/color_picker/mod.rs b/src/widget/color_picker/mod.rs index 66ffd847..e5aeedfa 100644 --- a/src/widget/color_picker/mod.rs +++ b/src/widget/color_picker/mod.rs @@ -5,13 +5,11 @@ use std::borrow::Cow; use std::rc::Rc; -use std::sync::LazyLock; use std::sync::atomic::{AtomicBool, Ordering}; use std::time::{Duration, Instant}; use crate::Element; -use crate::theme::iced::Slider; -use crate::theme::{Button, THEME}; +use crate::theme::{Button, THEME, Theme, iced::Slider}; use crate::widget::button::Catalog; use crate::widget::segmented_button::Entity; use crate::widget::{container, slider}; @@ -39,37 +37,6 @@ use super::{Icon, button, segmented_control, text, text_input, tooltip}; #[doc(inline)] pub use ColorPickerModel as Model; -// TODO is this going to look correct enough? -pub static HSV_RAINBOW: LazyLock> = LazyLock::new(|| { - (0u16..8) - .map(|h| { - Color::from(palette::Srgba::from_color(palette::Hsv::new_srgb_const( - RgbHue::new(f32::from(h) * 360.0 / 7.0), - 1.0, - 1.0, - ))) - }) - .collect() -}); - -fn hsv_rainbow(low_hue: f32, high_hue: f32) -> Vec { - let mut colors = Vec::new(); - let steps: u8 = 7; - let step_size = (high_hue - low_hue) / f32::from(steps); - for i in 0..=steps { - let hue = low_hue + step_size * f32::from(i); - colors.push(ColorStop { - color: Color::from(palette::Srgba::from_color(palette::Hsv::new_srgb_const( - RgbHue::new(hue), - 1.0, - 1.0, - ))), - offset: f32::from(i) / f32::from(steps), - }); - } - colors -} - const MAX_RECENT: usize = 20; #[derive(Debug, Clone)] @@ -301,23 +268,67 @@ where copy_to_clipboard_label: T, copied_to_clipboard_label: T, ) -> ColorPicker<'a, Message> { - fn rail_backgrounds(hue: f32) -> (Background, Background) { - let low_range = hsv_rainbow(0., hue); - let high_range = hsv_rainbow(hue, 360.); - - ( - Background::Gradient(iced::Gradient::Linear( - Linear::new(Radians(90.0)).add_stops(low_range), - )), - Background::Gradient(iced::Gradient::Linear( - Linear::new(Radians(90.0)).add_stops(high_range), - )), - ) - } - let on_update = self.on_update; let spacing = THEME.lock().unwrap().cosmic().spacing; + let color_slider_style = Rc::new(move |t: &Theme| { + let cosmic = t.cosmic(); + let mut a = slider::Catalog::style(t, &Slider::default(), slider::Status::Active); + a.rail.backgrounds = ( + // active track + Background::Gradient(iced::Gradient::Linear( + Linear::new(Radians(90.0)).add_stops((0..8_u8).map(|index| { + let offset; + let hue = self.active_color.hue.into_positive_degrees(); + let new_hue: f32; + if hue <= f32::from(index) * 360.0 / 7.0 { + offset = 1.0; + new_hue = hue; + } else { + offset = (f32::from(index) / 7.0) * (360.0 / hue); + new_hue = f32::from(index) * 360.0 / 7.0; + } + ColorStop { + color: Color::from(palette::Srgba::from_color( + palette::Hsv::new_srgb_const(RgbHue::new(new_hue), 1.0, 1.0), + )), + offset, + } + })), + )), + // inactive track + Background::Gradient(iced::Gradient::Linear( + Linear::new(Radians(90.0)).add_stops((0..8_u8).map(|index| { + let offset; + let hue = self.active_color.hue.into_positive_degrees(); + let new_hue: f32; + if hue >= f32::from(index) * 360.0 / 7.0 { + offset = 0.0; + new_hue = hue; + } else { + offset = + ((f32::from(index) / 7.0) - (hue / 360.0)) / (1.0 - (hue / 360.0)); + new_hue = f32::from(index) * 360.0 / 7.0; + } + ColorStop { + color: Color::from(palette::Srgba::from_color( + palette::Hsv::new_srgb_const(RgbHue::new(new_hue), 1.0, 1.0), + )), + offset, + } + })), + )), + ); + a.rail.width = 8.0; + a.handle.background = Background::Color(Color::from(palette::Srgba::from_color( + palette::Hsv::new_srgb_const(self.active_color.hue, 1.0, 1.0), + ))); + a.handle.shape = HandleShape::Circle { radius: 8.0 }; + a.handle.border_color = cosmic.palette.neutral_10.into(); + a.handle.border_width = 4.0; + a + }); + let mut inner = column![ // segmented buttons segmented_control::horizontal(self.model) @@ -332,56 +343,22 @@ where .width(self.width) .height(self.height), slider( - 0.001..=359.99, + 0.0..=359.99, self.active_color.hue.into_positive_degrees(), move |v| { let mut new = self.active_color; new.hue = v.into(); on_update(ColorPickerUpdate::ActiveColor(new)) - } + }, ) .on_release(on_update(ColorPickerUpdate::ActionFinished)) .class(Slider::Custom { - active: Rc::new(move |t| { - let cosmic = t.cosmic(); - let mut a = - slider::Catalog::style(t, &Slider::default(), slider::Status::Active); - let hue = self.active_color.hue.into_positive_degrees(); - a.rail.backgrounds = rail_backgrounds(hue); - a.rail.width = 8.0; - a.handle.background = Color::TRANSPARENT.into(); - a.handle.shape = HandleShape::Circle { radius: 8.0 }; - a.handle.border_color = cosmic.palette.neutral_10.into(); - a.handle.border_width = 4.0; - a - }), - hovered: Rc::new(move |t| { - let cosmic = t.cosmic(); - let mut a = - slider::Catalog::style(t, &Slider::default(), slider::Status::Active); - let hue = self.active_color.hue.into_positive_degrees(); - a.rail.backgrounds = rail_backgrounds(hue); - a.rail.width = 8.0; - a.handle.background = Color::TRANSPARENT.into(); - a.handle.shape = HandleShape::Circle { radius: 8.0 }; - a.handle.border_color = cosmic.palette.neutral_10.into(); - a.handle.border_width = 4.0; - a - }), - dragging: Rc::new(move |t| { - let cosmic = t.cosmic(); - let mut a = - slider::Catalog::style(t, &Slider::default(), slider::Status::Active); - let hue = self.active_color.hue.into_positive_degrees(); - a.rail.backgrounds = rail_backgrounds(hue); - a.rail.width = 8.0; - a.handle.background = Color::TRANSPARENT.into(); - a.handle.shape = HandleShape::Circle { radius: 8.0 }; - a.handle.border_color = cosmic.palette.neutral_10.into(); - a.handle.border_width = 4.0; - a - }), + active: color_slider_style.clone(), + hovered: color_slider_style.clone(), + dragging: color_slider_style, }) + .step(4.0 / 17.0) + .shift_step(64.0 / 17.0) .width(self.width), text_input("", self.input_color) .on_input(move |s| on_update(ColorPickerUpdate::Input(s)))