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::borrow::Cow;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::LazyLock;
|
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use crate::Element;
|
use crate::Element;
|
||||||
use crate::theme::iced::Slider;
|
use crate::theme::{Button, THEME, Theme, iced::Slider};
|
||||||
use crate::theme::{Button, THEME};
|
|
||||||
use crate::widget::button::Catalog;
|
use crate::widget::button::Catalog;
|
||||||
use crate::widget::segmented_button::Entity;
|
use crate::widget::segmented_button::Entity;
|
||||||
use crate::widget::{container, slider};
|
use crate::widget::{container, slider};
|
||||||
|
|
@ -39,37 +37,6 @@ use super::{Icon, button, segmented_control, text, text_input, tooltip};
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use ColorPickerModel as Model;
|
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;
|
const MAX_RECENT: usize = 20;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
@ -301,23 +268,67 @@ where
|
||||||
copy_to_clipboard_label: T,
|
copy_to_clipboard_label: T,
|
||||||
copied_to_clipboard_label: T,
|
copied_to_clipboard_label: T,
|
||||||
) -> ColorPicker<'a, Message> {
|
) -> 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 on_update = self.on_update;
|
||||||
let spacing = THEME.lock().unwrap().cosmic().spacing;
|
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![
|
let mut inner = column![
|
||||||
// segmented buttons
|
// segmented buttons
|
||||||
segmented_control::horizontal(self.model)
|
segmented_control::horizontal(self.model)
|
||||||
|
|
@ -332,56 +343,22 @@ where
|
||||||
.width(self.width)
|
.width(self.width)
|
||||||
.height(self.height),
|
.height(self.height),
|
||||||
slider(
|
slider(
|
||||||
0.001..=359.99,
|
0.0..=359.99,
|
||||||
self.active_color.hue.into_positive_degrees(),
|
self.active_color.hue.into_positive_degrees(),
|
||||||
move |v| {
|
move |v| {
|
||||||
let mut new = self.active_color;
|
let mut new = self.active_color;
|
||||||
new.hue = v.into();
|
new.hue = v.into();
|
||||||
on_update(ColorPickerUpdate::ActiveColor(new))
|
on_update(ColorPickerUpdate::ActiveColor(new))
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
.on_release(on_update(ColorPickerUpdate::ActionFinished))
|
.on_release(on_update(ColorPickerUpdate::ActionFinished))
|
||||||
.class(Slider::Custom {
|
.class(Slider::Custom {
|
||||||
active: Rc::new(move |t| {
|
active: color_slider_style.clone(),
|
||||||
let cosmic = t.cosmic();
|
hovered: color_slider_style.clone(),
|
||||||
let mut a =
|
dragging: color_slider_style,
|
||||||
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
|
|
||||||
}),
|
|
||||||
})
|
})
|
||||||
|
.step(4.0 / 17.0)
|
||||||
|
.shift_step(64.0 / 17.0)
|
||||||
.width(self.width),
|
.width(self.width),
|
||||||
text_input("", self.input_color)
|
text_input("", self.input_color)
|
||||||
.on_input(move |s| on_update(ColorPickerUpdate::Input(s)))
|
.on_input(move |s| on_update(ColorPickerUpdate::Input(s)))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue