1use crate::makepad_draw::*;
2
3
4live_design!{
5 import makepad_draw::shader::std::*;
6
7 DrawColorWheel= {{DrawColorWheel}} {
8 instance hover: float
9 instance pressed: float
10
11 fn circ_to_rect(u: float, v: float) -> vec2 {
12 let u2 = u * u;
13 let v2 = v * v;
14 return vec2(
15 0.5 * sqrt(2. + 2. * sqrt(2.) * u + u2 - v2) -
16 0.5 * sqrt(2. - 2. * sqrt(2.) * u + u2 - v2),
17 0.5 * sqrt(2. + 2. * sqrt(2.) * v - u2 + v2) -
18 0.5 * sqrt(2. - 2. * sqrt(2.) * v - u2 + v2)
19 );
20 }
21
22 fn pixel(self) -> vec4 {
23
24 let rgbv = Pal::hsv2rgb(vec4(self.hue, self.sat, self.val, 1.));
25 let w = self.rect_size.x;
26 let h = self.rect_size.y;
27 let sdf = Sdf2d::viewport(self.pos * vec2(w, h));
28 let cx = w * 0.5;
29 let cy = h * 0.5;
30
31 let radius = w * 0.37;
32 let inner = w * 0.28;
33
34 sdf.hexagon(cx, cy, w * 0.45);
35 sdf.hexagon(cx, cy, w * 0.4);
36 sdf.subtract();
37 let ang = atan(self.pos.x * w - cx, 0.0001 + self.pos.y * h - cy) / PI * 0.5 - 0.33333;
38 sdf.fill(Pal::hsv2rgb(vec4(ang, 1.0, 1.0, 1.0)));
39
40 let rsize = inner / sqrt(2.0);
41 sdf.rect(cx - rsize, cy - rsize, rsize * 2.0, rsize * 2.0);
42
43 let norm_rect = vec2(self.pos.x * w - (cx - inner), self.pos.y * h - (cy - inner)) / (2. * inner);
44 let circ = clamp(circ_to_rect(norm_rect.x * 2. - 1., norm_rect.y * 2. - 1.), vec2(-1.), vec2(1.));
45
46 sdf.fill(Pal::hsv2rgb(vec4(self.hue, (circ.x * .5 + .5), 1. - (circ.y * .5 + .5), 1.)));
47
48 let col_angle = (self.hue + .333333) * 2. * PI;
49 let circle_puk = vec2(sin(col_angle) * radius + cx, cos(col_angle) * radius + cy);
50
51 let rect_puk = vec2(cx + self.sat * 2. * rsize - rsize, cy + (1. - self.val) * 2. * rsize - rsize);
52
53 let color = mix(mix(#3, #E, self.hover), #F, self.pressed);
54 let puck_size = 0.1 * w;
55 sdf.circle(rect_puk.x, rect_puk.y, puck_size);
56 sdf.rect(cx - rsize, cy - rsize, rsize * 2.0, rsize * 2.0);
57 sdf.intersect();
58 sdf.fill(color);
59 sdf.circle(rect_puk.x, rect_puk.y, puck_size - 1. - 2. * self.hover + self.pressed);
60 sdf.rect(cx - rsize, cy - rsize, rsize * 2.0, rsize * 2.0);
61 sdf.intersect();
62 sdf.fill(rgbv);
63
64 sdf.circle(circle_puk.x, circle_puk.y, puck_size);
65 sdf.fill(color);
66 sdf.circle(circle_puk.x, circle_puk.y, puck_size - 1. - 2. * self.hover + self.pressed);
67 sdf.fill(rgbv);
68
69 return sdf.result;
70 }
71 }
72
73 ColorPicker= {{ColorPicker}} {
74
75 animator: {
76 hover = {
77 default: off
78 off = {
79 from: {all: Forward {duration: 0.1}}
80 apply: {
81 draw_wheel: {pressed: 0.0, hover: 0.0}
82 }
83 }
84
85 on = {
86 cursor: Arrow,
87 from: {
88 all: Forward {duration: 0.1}
89 pressed: Forward {duration: 0.01}
90 }
91 apply: {
92 draw_wheel: {
93 pressed: 0.0,
94 hover: [{time: 0.0, value: 1.0}],
95 }
96 }
97 }
98
99 pressed = {
100 cursor: Arrow,
101 from: {all: Forward {duration: 0.2}}
102 apply: {
103 draw_wheel: {
104 pressed: [{time: 0.0, value: 1.0}],
105 hover: 1.0,
106 }
107 }
108 }
109 }
110 }
111 }
112}
113
114
115#[derive(Live, LiveHook)]
116#[repr(C)]
117pub struct DrawColorWheel {
118 #[deref] draw_super: DrawQuad,
119 #[live] hue: f32,
120 #[live] sat: f32,
121 #[live] val: f32,
122}
123
124#[derive(Live, LiveHook)]
125pub struct ColorPicker {
126 #[live] draw_wheel: DrawColorWheel,
127
128 #[animator] animator: Animator,
129
130 #[rust] pub size: f64,
131 #[rust] hue: f32,
132 #[rust] sat: f32,
133 #[rust] val: f32,
134 #[rust(ColorPickerDragMode::None)] drag_mode: ColorPickerDragMode
135}
136
137pub enum ColorPickerAction {
138 Change {rgba: Vec4},
139 DoneChanging,
140 None
141}
142
143#[derive(Clone, Debug, PartialEq)]
144pub enum ColorPickerDragMode {
145 Wheel,
146 Rect,
147 None
148}
149
150impl ColorPicker {
151
152 pub fn handle_finger(&mut self, cx: &mut Cx, rel: DVec2, dispatch_action: &mut dyn FnMut(&mut Cx, ColorPickerAction)) {
153
154 fn clamp(x: f64, mi: f64, ma: f64) -> f64 {if x < mi {mi} else if x > ma {ma} else {x}}
155
156 let vx = rel.x - 0.5 * self.size;
157 let vy = rel.y - 0.5 * self.size;
158 let rsize = (self.size * 0.28) / 2.0f64.sqrt();
159 let last_hue = self.hue;
160 let last_sat = self.sat;
161 let last_val = self.val;
162
163 match self.drag_mode {
164 ColorPickerDragMode::Rect => {
165 self.sat = clamp((vx + rsize) / (2.0 * rsize), 0.0, 1.0) as f32;
166 self.val = 1.0 - clamp((vy + rsize) / (2.0 * rsize), 0.0, 1.0) as f32;
167 },
168 ColorPickerDragMode::Wheel => {
169 self.hue = ((vx.atan2(vy) / std::f64::consts::PI * 0.5) - 0.33333 + 1.0) as f32;
170 },
171 _ => ()
172 }
173 let mut changed = false;
175
176 if last_hue != self.hue {
177 self.draw_wheel.apply_over(cx, live!{hue: (self.hue)});
178 changed = true;
179 }
180 if last_sat != self.sat {
181 self.draw_wheel.apply_over(cx, live!{sat: (self.sat)});
182 changed = true;
183 }
184 if last_val != self.val {
185 self.draw_wheel.apply_over(cx, live!{val: (self.val)});
186 changed = true;
187 }
188 if changed {
189 dispatch_action(cx, ColorPickerAction::Change {rgba: self.to_rgba()})
190 }
191 }
192
193 pub fn to_rgba(&self) -> Vec4 {
194 Vec4::from_hsva(Vec4 {x: self.hue, y: self.sat, z: self.val, w: 1.0})
195 }
196
197 pub fn handle_event_with(&mut self, cx: &mut Cx, event: &Event, dispatch_action: &mut dyn FnMut(&mut Cx, ColorPickerAction)) {
198 self.animator_handle_event(cx, event);
199
200 match event.hits(cx, self.draw_wheel.area()) {
201 Hit::FingerHoverIn(_) => {
202 self.animator_play(cx, id!(hover.on));
203 }
204 Hit::FingerHoverOut(_) => {
205 self.animator_play(cx, id!(hover.off));
206 },
207 Hit::FingerDown(fe) => {
208 self.animator_play(cx, id!(hover.pressed));
209 let rsize = (self.size * 0.28) / 2.0f64.sqrt();
210 let rel = fe.abs - fe.rect.pos;
211 let vx = rel.x - 0.5 * self.size;
212 let vy = rel.y - 0.5 * self.size;
213 if vx >= -rsize && vx <= rsize && vy >= -rsize && vy <= rsize {
214 self.drag_mode = ColorPickerDragMode::Rect;
215 }
216 else if vx >= -0.5 * self.size && vx <= 0.5 * self.size && vy >= -0.5 * self.size && vy <= 0.5 * self.size {
217 self.drag_mode = ColorPickerDragMode::Wheel;
218 }
219 else {
220 self.drag_mode = ColorPickerDragMode::None;
221 }
222 return self.handle_finger(cx, rel, dispatch_action);
223 },
225 Hit::FingerUp(fe) => {
226 if fe.is_over && fe.device.has_hovers() {
227 self.animator_play(cx, id!(hover.on));
228 }
229 else {
230 self.animator_play(cx, id!(hover.off));
231 }
232 self.drag_mode = ColorPickerDragMode::None;
233 dispatch_action(cx, ColorPickerAction::DoneChanging)
234 }
235 Hit::FingerMove(fe) => {
236 let rel = fe.abs - fe.rect.pos;
237 return self.handle_finger(cx, rel, dispatch_action)
238
239 },
240 _ => ()
241 }
242 }
243
244 pub fn draw(&mut self, cx: &mut Cx2d, rgba: Vec4, height_scale: f64) {
245 if self.drag_mode == ColorPickerDragMode::None {
246 let old_rgba = self.to_rgba();
248 if !rgba.is_equal_enough(&old_rgba, 0.0001) {
249 let hsva = rgba.to_hsva();
250 self.hue = hsva.x;
251 self.sat = hsva.y;
252 self.val = hsva.z;
253 }
254 }
255 self.size = cx.turtle().rect().size.y;
258 self.draw_wheel.hue = self.hue;
259 self.draw_wheel.sat = self.sat;
260 self.draw_wheel.val = self.val;
261 self.draw_wheel.draw_walk(cx, Walk::fixed_size(dvec2(self.size * height_scale, self.size * height_scale)));
262 }
263}
264