teksilo_widgets/color_picker/
state.rs1use std::cell::Cell;
25use std::rc::Rc;
26
27use teksilo_core::build_context::BuildContext;
28use teksilo_core::signal::Signal;
29use teksilo_tokens::Color;
30
31#[allow(dead_code)]
34pub(crate) struct ColorComponents {
35 pub value: Signal<Color>,
36
37 pub red: Signal<f32>,
39 pub green: Signal<f32>,
40 pub blue: Signal<f32>,
41 pub alpha: Signal<f32>,
42
43 pub hue: Signal<f32>, pub saturation: Signal<f32>, pub value_hsv: Signal<f32>, pub set_red: Rc<dyn Fn(f32)>,
50 pub set_green: Rc<dyn Fn(f32)>,
51 pub set_blue: Rc<dyn Fn(f32)>,
52 pub set_alpha: Rc<dyn Fn(f32)>,
53 pub set_hue: Rc<dyn Fn(f32)>,
54 pub set_saturation: Rc<dyn Fn(f32)>,
55 pub set_value_hsv: Rc<dyn Fn(f32)>,
56 pub set_hsv: Rc<dyn Fn(f32, f32, f32)>,
60
61 pub dragging: Rc<Cell<bool>>,
66
67 last_hue_cell: Rc<Cell<f32>>,
71}
72
73impl ColorComponents {
74 pub(crate) fn new(ctx: &mut BuildContext, value: Signal<Color>) -> Self {
75 let initial = value.get();
76 let (init_h, init_s, _init_v) = initial.to_hsv();
77 let last_hue_cell = Rc::new(Cell::new(if init_s > 1e-6 { init_h } else { 0.0 }));
78
79 {
81 let cell = last_hue_cell.clone();
82 ctx.effect(&value, move |c| {
83 let (h, s, _v) = c.to_hsv();
84 if s > 1e-6 {
85 cell.set(h);
86 }
87 });
88 }
89
90 let red = value.map(|c| c.r());
92 let green = value.map(|c| c.g());
93 let blue = value.map(|c| c.b());
94 let alpha = value.map(|c| c.a());
95
96 let hue = {
99 let cell = last_hue_cell.clone();
100 value.map(move |c| {
101 let (h, s, _v) = c.to_hsv();
102 if s > 1e-6 { h } else { cell.get() }
103 })
104 };
105 let saturation = value.map(|c| c.to_hsv().1);
106 let value_hsv = value.map(|c| c.to_hsv().2);
107
108 let set_red = {
110 let v = value.clone();
111 Rc::new(move |r: f32| {
112 let c = v.get();
113 v.set(Color::from_rgba(r.clamp(0.0, 1.0), c.g(), c.b(), c.a()));
114 }) as Rc<dyn Fn(f32)>
115 };
116 let set_green = {
117 let v = value.clone();
118 Rc::new(move |g: f32| {
119 let c = v.get();
120 v.set(Color::from_rgba(c.r(), g.clamp(0.0, 1.0), c.b(), c.a()));
121 }) as Rc<dyn Fn(f32)>
122 };
123 let set_blue = {
124 let v = value.clone();
125 Rc::new(move |b: f32| {
126 let c = v.get();
127 v.set(Color::from_rgba(c.r(), c.g(), b.clamp(0.0, 1.0), c.a()));
128 }) as Rc<dyn Fn(f32)>
129 };
130 let set_alpha = {
131 let v = value.clone();
132 Rc::new(move |a: f32| {
133 let c = v.get();
134 v.set(Color::from_rgba(c.r(), c.g(), c.b(), a.clamp(0.0, 1.0)));
135 }) as Rc<dyn Fn(f32)>
136 };
137 let set_hue = {
138 let v = value.clone();
139 let cell = last_hue_cell.clone();
140 Rc::new(move |h: f32| {
141 let c = v.get();
142 let (_old_h, s, val) = c.to_hsv();
143 let h_norm = h.rem_euclid(360.0);
144 cell.set(h_norm);
145 v.set(Color::from_hsva(h_norm, s, val, c.a()));
146 }) as Rc<dyn Fn(f32)>
147 };
148 let set_saturation = {
149 let v = value.clone();
150 let cell = last_hue_cell.clone();
151 Rc::new(move |s: f32| {
152 let c = v.get();
153 let (cur_h, _s, val) = c.to_hsv();
154 let h = if c.to_hsv().1 > 1e-6 {
155 cur_h
156 } else {
157 cell.get()
158 };
159 v.set(Color::from_hsva(h, s.clamp(0.0, 1.0), val, c.a()));
160 }) as Rc<dyn Fn(f32)>
161 };
162 let set_value_hsv = {
163 let v = value.clone();
164 let cell = last_hue_cell.clone();
165 Rc::new(move |val: f32| {
166 let c = v.get();
167 let (cur_h, s, _v) = c.to_hsv();
168 let h = if s > 1e-6 { cur_h } else { cell.get() };
169 v.set(Color::from_hsva(h, s, val.clamp(0.0, 1.0), c.a()));
170 }) as Rc<dyn Fn(f32)>
171 };
172 let set_hsv = {
173 let v = value.clone();
174 let cell = last_hue_cell.clone();
175 Rc::new(move |h: f32, s: f32, val: f32| {
176 let c = v.get();
177 let h_norm = h.rem_euclid(360.0);
178 if s > 1e-6 {
179 cell.set(h_norm);
180 }
181 v.set(Color::from_hsva(
182 h_norm,
183 s.clamp(0.0, 1.0),
184 val.clamp(0.0, 1.0),
185 c.a(),
186 ));
187 }) as Rc<dyn Fn(f32, f32, f32)>
188 };
189
190 Self {
191 value,
192 red,
193 green,
194 blue,
195 alpha,
196 hue,
197 saturation,
198 value_hsv,
199 set_red,
200 set_green,
201 set_blue,
202 set_alpha,
203 set_hue,
204 set_saturation,
205 set_value_hsv,
206 set_hsv,
207 dragging: Rc::new(Cell::new(false)),
208 last_hue_cell,
209 }
210 }
211}