use std::cell::Cell;
use std::rc::Rc;
use teksilo_core::build_context::BuildContext;
use teksilo_core::signal::Signal;
use teksilo_tokens::Color;
#[allow(dead_code)]
pub(crate) struct ColorComponents {
pub value: Signal<Color>,
pub red: Signal<f32>,
pub green: Signal<f32>,
pub blue: Signal<f32>,
pub alpha: Signal<f32>,
pub hue: Signal<f32>, pub saturation: Signal<f32>, pub value_hsv: Signal<f32>,
pub set_red: Rc<dyn Fn(f32)>,
pub set_green: Rc<dyn Fn(f32)>,
pub set_blue: Rc<dyn Fn(f32)>,
pub set_alpha: Rc<dyn Fn(f32)>,
pub set_hue: Rc<dyn Fn(f32)>,
pub set_saturation: Rc<dyn Fn(f32)>,
pub set_value_hsv: Rc<dyn Fn(f32)>,
pub set_hsv: Rc<dyn Fn(f32, f32, f32)>,
pub dragging: Rc<Cell<bool>>,
last_hue_cell: Rc<Cell<f32>>,
}
impl ColorComponents {
pub(crate) fn new(ctx: &mut BuildContext, value: Signal<Color>) -> Self {
let initial = value.get();
let (init_h, init_s, _init_v) = initial.to_hsv();
let last_hue_cell = Rc::new(Cell::new(if init_s > 1e-6 { init_h } else { 0.0 }));
{
let cell = last_hue_cell.clone();
ctx.effect(&value, move |c| {
let (h, s, _v) = c.to_hsv();
if s > 1e-6 {
cell.set(h);
}
});
}
let red = value.map(|c| c.r());
let green = value.map(|c| c.g());
let blue = value.map(|c| c.b());
let alpha = value.map(|c| c.a());
let hue = {
let cell = last_hue_cell.clone();
value.map(move |c| {
let (h, s, _v) = c.to_hsv();
if s > 1e-6 { h } else { cell.get() }
})
};
let saturation = value.map(|c| c.to_hsv().1);
let value_hsv = value.map(|c| c.to_hsv().2);
let set_red = {
let v = value.clone();
Rc::new(move |r: f32| {
let c = v.get();
v.set(Color::from_rgba(r.clamp(0.0, 1.0), c.g(), c.b(), c.a()));
}) as Rc<dyn Fn(f32)>
};
let set_green = {
let v = value.clone();
Rc::new(move |g: f32| {
let c = v.get();
v.set(Color::from_rgba(c.r(), g.clamp(0.0, 1.0), c.b(), c.a()));
}) as Rc<dyn Fn(f32)>
};
let set_blue = {
let v = value.clone();
Rc::new(move |b: f32| {
let c = v.get();
v.set(Color::from_rgba(c.r(), c.g(), b.clamp(0.0, 1.0), c.a()));
}) as Rc<dyn Fn(f32)>
};
let set_alpha = {
let v = value.clone();
Rc::new(move |a: f32| {
let c = v.get();
v.set(Color::from_rgba(c.r(), c.g(), c.b(), a.clamp(0.0, 1.0)));
}) as Rc<dyn Fn(f32)>
};
let set_hue = {
let v = value.clone();
let cell = last_hue_cell.clone();
Rc::new(move |h: f32| {
let c = v.get();
let (_old_h, s, val) = c.to_hsv();
let h_norm = h.rem_euclid(360.0);
cell.set(h_norm);
v.set(Color::from_hsva(h_norm, s, val, c.a()));
}) as Rc<dyn Fn(f32)>
};
let set_saturation = {
let v = value.clone();
let cell = last_hue_cell.clone();
Rc::new(move |s: f32| {
let c = v.get();
let (cur_h, _s, val) = c.to_hsv();
let h = if c.to_hsv().1 > 1e-6 {
cur_h
} else {
cell.get()
};
v.set(Color::from_hsva(h, s.clamp(0.0, 1.0), val, c.a()));
}) as Rc<dyn Fn(f32)>
};
let set_value_hsv = {
let v = value.clone();
let cell = last_hue_cell.clone();
Rc::new(move |val: f32| {
let c = v.get();
let (cur_h, s, _v) = c.to_hsv();
let h = if s > 1e-6 { cur_h } else { cell.get() };
v.set(Color::from_hsva(h, s, val.clamp(0.0, 1.0), c.a()));
}) as Rc<dyn Fn(f32)>
};
let set_hsv = {
let v = value.clone();
let cell = last_hue_cell.clone();
Rc::new(move |h: f32, s: f32, val: f32| {
let c = v.get();
let h_norm = h.rem_euclid(360.0);
if s > 1e-6 {
cell.set(h_norm);
}
v.set(Color::from_hsva(
h_norm,
s.clamp(0.0, 1.0),
val.clamp(0.0, 1.0),
c.a(),
));
}) as Rc<dyn Fn(f32, f32, f32)>
};
Self {
value,
red,
green,
blue,
alpha,
hue,
saturation,
value_hsv,
set_red,
set_green,
set_blue,
set_alpha,
set_hue,
set_saturation,
set_value_hsv,
set_hsv,
dragging: Rc::new(Cell::new(false)),
last_hue_cell,
}
}
}