feat(color_picker): apply gradient shifting to hue slider
This also removes vertical line gap in the center of slider handle by adding current hue color to handle.
This commit is contained in:
parent
76bc13ff40
commit
417923fbaf
1 changed files with 66 additions and 89 deletions
|
|
@ -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<Vec<Color>> = 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<ColorStop> {
|
||||
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)))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue