1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 *
16 * The Original Code is Copyright (C) 2008 Blender Foundation.
17 * All rights reserved.
18 */
19
20 /** \file
21 * \ingroup edinterface
22 *
23 * Color Picker Region & Color Utils
24 */
25
26 #include <stdarg.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include "MEM_guardedalloc.h"
31
32 #include "DNA_userdef_types.h"
33
34 #include "BLI_listbase.h"
35 #include "BLI_math.h"
36 #include "BLI_string.h"
37 #include "BLI_utildefines.h"
38
39 #include "BKE_context.h"
40
41 #include "WM_types.h"
42
43 #include "RNA_access.h"
44
45 #include "UI_interface.h"
46
47 #include "BLT_translation.h"
48
49 #include "ED_screen.h"
50
51 #include "IMB_colormanagement.h"
52
53 #include "interface_intern.h"
54
55 enum ePickerType {
56 PICKER_TYPE_RGB = 0,
57 PICKER_TYPE_HSV = 1,
58 PICKER_TYPE_HEX = 2,
59 };
60
61 /* -------------------------------------------------------------------- */
62 /** \name Color Conversion
63 * \{ */
64
ui_color_picker_rgb_round(float rgb[3])65 static void ui_color_picker_rgb_round(float rgb[3])
66 {
67 /* Handle small rounding errors in color space conversions. Doing these for
68 * all color space conversions would be expensive, but for the color picker
69 * we can do the extra work. */
70 for (int i = 0; i < 3; i++) {
71 if (fabsf(rgb[i]) < 1e-6f) {
72 rgb[i] = 0.0f;
73 }
74 else if (fabsf(1.0f - rgb[i]) < 1e-6f) {
75 rgb[i] = 1.0f;
76 }
77 }
78 }
79
ui_rgb_to_color_picker_compat_v(const float rgb[3],float r_cp[3])80 void ui_rgb_to_color_picker_compat_v(const float rgb[3], float r_cp[3])
81 {
82 switch (U.color_picker_type) {
83 case USER_CP_CIRCLE_HSL:
84 rgb_to_hsl_compat_v(rgb, r_cp);
85 break;
86 default:
87 rgb_to_hsv_compat_v(rgb, r_cp);
88 break;
89 }
90 }
91
ui_rgb_to_color_picker_v(const float rgb[3],float r_cp[3])92 void ui_rgb_to_color_picker_v(const float rgb[3], float r_cp[3])
93 {
94 switch (U.color_picker_type) {
95 case USER_CP_CIRCLE_HSL:
96 rgb_to_hsl_v(rgb, r_cp);
97 break;
98 default:
99 rgb_to_hsv_v(rgb, r_cp);
100 break;
101 }
102 }
103
ui_color_picker_to_rgb_v(const float r_cp[3],float rgb[3])104 void ui_color_picker_to_rgb_v(const float r_cp[3], float rgb[3])
105 {
106 switch (U.color_picker_type) {
107 case USER_CP_CIRCLE_HSL:
108 hsl_to_rgb_v(r_cp, rgb);
109 break;
110 default:
111 hsv_to_rgb_v(r_cp, rgb);
112 break;
113 }
114 }
115
ui_color_picker_to_rgb(float r_cp0,float r_cp1,float r_cp2,float * r,float * g,float * b)116 void ui_color_picker_to_rgb(float r_cp0, float r_cp1, float r_cp2, float *r, float *g, float *b)
117 {
118 switch (U.color_picker_type) {
119 case USER_CP_CIRCLE_HSL:
120 hsl_to_rgb(r_cp0, r_cp1, r_cp2, r, g, b);
121 break;
122 default:
123 hsv_to_rgb(r_cp0, r_cp1, r_cp2, r, g, b);
124 break;
125 }
126 }
127
128 /* Returns true if the button is for a color with gamma baked in,
129 * or if it's a color picker for such a button. */
ui_but_is_color_gamma(uiBut * but)130 bool ui_but_is_color_gamma(uiBut *but)
131 {
132 if (but->rnaprop) {
133 if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
134 return true;
135 }
136 }
137
138 return but->block->is_color_gamma_picker;
139 }
140
ui_scene_linear_to_color_picker_space(uiBut * but,float rgb[3])141 void ui_scene_linear_to_color_picker_space(uiBut *but, float rgb[3])
142 {
143 /* Map to color picking space for HSV values and HSV cube/circle,
144 * assuming it is more perceptually linear than the scene linear
145 * space for intuitive color picking. */
146 if (!ui_but_is_color_gamma(but)) {
147 IMB_colormanagement_scene_linear_to_color_picking_v3(rgb);
148 ui_color_picker_rgb_round(rgb);
149 }
150 }
151
ui_color_picker_to_scene_linear_space(uiBut * but,float rgb[3])152 void ui_color_picker_to_scene_linear_space(uiBut *but, float rgb[3])
153 {
154 if (!ui_but_is_color_gamma(but)) {
155 IMB_colormanagement_color_picking_to_scene_linear_v3(rgb);
156 ui_color_picker_rgb_round(rgb);
157 }
158 }
159
160 /** \} */
161
162 /* -------------------------------------------------------------------- */
163 /** \name Color Picker
164 * \{ */
165
166 /* for picker, while editing hsv */
ui_but_hsv_set(uiBut * but)167 void ui_but_hsv_set(uiBut *but)
168 {
169 float col[3];
170 ColorPicker *cpicker = but->custom_data;
171 float *hsv = cpicker->color_data;
172
173 ui_color_picker_to_rgb_v(hsv, col);
174
175 ui_but_v3_set(but, col);
176 }
177
178 /* Updates all buttons who share the same color picker as the one passed
179 * also used by small picker, be careful with name checks below... */
ui_update_color_picker_buts_rgb(uiBut * from_but,uiBlock * block,ColorPicker * cpicker,const float rgb[3])180 static void ui_update_color_picker_buts_rgb(uiBut *from_but,
181 uiBlock *block,
182 ColorPicker *cpicker,
183 const float rgb[3])
184 {
185 float *hsv = cpicker->color_data;
186
187 /* Convert from RGB to HSV in perceptually linear space. */
188 float tmp[3];
189 copy_v3_v3(tmp, rgb);
190 if (from_but) {
191 ui_scene_linear_to_color_picker_space(from_but, tmp);
192 }
193 ui_rgb_to_color_picker_compat_v(tmp, hsv);
194
195 /* this updates button strings,
196 * is hackish... but button pointers are on stack of caller function */
197 LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
198 if (bt->custom_data != cpicker) {
199 continue;
200 }
201
202 if (bt->rnaprop) {
203 ui_but_v3_set(bt, rgb);
204
205 /* original button that created the color picker already does undo
206 * push, so disable it on RNA buttons in the color picker block */
207 UI_but_flag_disable(bt, UI_BUT_UNDO);
208 }
209 else if (STREQ(bt->str, "Hex: ")) {
210 float rgb_hex[3];
211 uchar rgb_hex_uchar[3];
212 char col[16];
213
214 /* Hex code is assumed to be in sRGB space
215 * (coming from other applications, web, etc) */
216 copy_v3_v3(rgb_hex, rgb);
217 if (from_but && !ui_but_is_color_gamma(from_but)) {
218 IMB_colormanagement_scene_linear_to_srgb_v3(rgb_hex);
219 ui_color_picker_rgb_round(rgb_hex);
220 }
221
222 rgb_float_to_uchar(rgb_hex_uchar, rgb_hex);
223 BLI_snprintf(col, sizeof(col), "%02X%02X%02X", UNPACK3_EX((uint), rgb_hex_uchar, ));
224
225 strcpy(bt->poin, col);
226 }
227 else if (bt->str[1] == ' ') {
228 if (bt->str[0] == 'R') {
229 ui_but_value_set(bt, rgb[0]);
230 }
231 else if (bt->str[0] == 'G') {
232 ui_but_value_set(bt, rgb[1]);
233 }
234 else if (bt->str[0] == 'B') {
235 ui_but_value_set(bt, rgb[2]);
236 }
237 else if (bt->str[0] == 'H') {
238 ui_but_value_set(bt, hsv[0]);
239 }
240 else if (bt->str[0] == 'S') {
241 ui_but_value_set(bt, hsv[1]);
242 }
243 else if (bt->str[0] == 'V') {
244 ui_but_value_set(bt, hsv[2]);
245 }
246 else if (bt->str[0] == 'L') {
247 ui_but_value_set(bt, hsv[2]);
248 }
249 }
250
251 ui_but_update(bt);
252 }
253 }
254
ui_colorpicker_rna_cb(bContext * UNUSED (C),void * bt1,void * UNUSED (arg))255 static void ui_colorpicker_rna_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg))
256 {
257 uiBut *but = (uiBut *)bt1;
258 uiPopupBlockHandle *popup = but->block->handle;
259 PropertyRNA *prop = but->rnaprop;
260 PointerRNA ptr = but->rnapoin;
261 float rgb[4];
262
263 if (prop) {
264 RNA_property_float_get_array(&ptr, prop, rgb);
265 ui_update_color_picker_buts_rgb(but, but->block, but->custom_data, rgb);
266 }
267
268 if (popup) {
269 popup->menuretval = UI_RETURN_UPDATE;
270 }
271 }
272
ui_color_wheel_rna_cb(bContext * UNUSED (C),void * bt1,void * UNUSED (arg))273 static void ui_color_wheel_rna_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg))
274 {
275 uiBut *but = (uiBut *)bt1;
276 uiPopupBlockHandle *popup = but->block->handle;
277 float rgb[3];
278 ColorPicker *cpicker = but->custom_data;
279 float *hsv = cpicker->color_data;
280
281 ui_color_picker_to_rgb_v(hsv, rgb);
282
283 /* hsv is saved in perceptually linear space so convert back */
284 ui_color_picker_to_scene_linear_space(but, rgb);
285
286 ui_update_color_picker_buts_rgb(but, but->block, cpicker, rgb);
287
288 if (popup) {
289 popup->menuretval = UI_RETURN_UPDATE;
290 }
291 }
292
ui_colorpicker_hex_rna_cb(bContext * UNUSED (C),void * bt1,void * hexcl)293 static void ui_colorpicker_hex_rna_cb(bContext *UNUSED(C), void *bt1, void *hexcl)
294 {
295 uiBut *but = (uiBut *)bt1;
296 uiPopupBlockHandle *popup = but->block->handle;
297 ColorPicker *cpicker = but->custom_data;
298 char *hexcol = (char *)hexcl;
299 float rgb[3];
300
301 hex_to_rgb(hexcol, rgb, rgb + 1, rgb + 2);
302
303 /* Hex code is assumed to be in sRGB space (coming from other applications, web, etc) */
304 if (!ui_but_is_color_gamma(but)) {
305 IMB_colormanagement_srgb_to_scene_linear_v3(rgb);
306 ui_color_picker_rgb_round(rgb);
307 }
308
309 ui_update_color_picker_buts_rgb(but, but->block, cpicker, rgb);
310
311 if (popup) {
312 popup->menuretval = UI_RETURN_UPDATE;
313 }
314 }
315
ui_popup_close_cb(bContext * UNUSED (C),void * bt1,void * UNUSED (arg))316 static void ui_popup_close_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg))
317 {
318 uiBut *but = (uiBut *)bt1;
319 uiPopupBlockHandle *popup = but->block->handle;
320
321 if (popup) {
322 ColorPicker *cpicker = but->custom_data;
323 BLI_assert(cpicker->is_init);
324 popup->menuretval = (equals_v3v3(cpicker->color_data, cpicker->color_data_init) ?
325 UI_RETURN_CANCEL :
326 UI_RETURN_OK);
327 }
328 }
329
ui_colorpicker_hide_reveal(uiBlock * block,enum ePickerType colormode)330 static void ui_colorpicker_hide_reveal(uiBlock *block, enum ePickerType colormode)
331 {
332 /* tag buttons */
333 LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
334 if ((bt->func == ui_colorpicker_rna_cb) && (bt->type == UI_BTYPE_NUM_SLIDER) &&
335 (bt->rnaindex != 3)) {
336 /* RGB sliders (color circle and alpha are always shown) */
337 SET_FLAG_FROM_TEST(bt->flag, (colormode != PICKER_TYPE_RGB), UI_HIDDEN);
338 }
339 else if (bt->func == ui_color_wheel_rna_cb) {
340 /* HSV sliders */
341 SET_FLAG_FROM_TEST(bt->flag, (colormode != PICKER_TYPE_HSV), UI_HIDDEN);
342 }
343 else if (bt->func == ui_colorpicker_hex_rna_cb || bt->type == UI_BTYPE_LABEL) {
344 /* HEX input or gamma correction status label */
345 SET_FLAG_FROM_TEST(bt->flag, (colormode != PICKER_TYPE_HEX), UI_HIDDEN);
346 }
347 }
348 }
349
ui_colorpicker_create_mode_cb(bContext * UNUSED (C),void * bt1,void * UNUSED (arg))350 static void ui_colorpicker_create_mode_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg))
351 {
352 uiBut *bt = bt1;
353 const short colormode = ui_but_value_get(bt);
354 ui_colorpicker_hide_reveal(bt->block, colormode);
355 }
356
357 #define PICKER_H (7.5f * U.widget_unit)
358 #define PICKER_W (7.5f * U.widget_unit)
359 #define PICKER_SPACE (0.3f * U.widget_unit)
360 #define PICKER_BAR (0.7f * U.widget_unit)
361
362 #define PICKER_TOTAL_W (PICKER_W + PICKER_SPACE + PICKER_BAR)
363
ui_colorpicker_circle(uiBlock * block,PointerRNA * ptr,PropertyRNA * prop,ColorPicker * cpicker)364 static void ui_colorpicker_circle(uiBlock *block,
365 PointerRNA *ptr,
366 PropertyRNA *prop,
367 ColorPicker *cpicker)
368 {
369 uiBut *bt;
370 uiButHSVCube *hsv_but;
371
372 /* HS circle */
373 bt = uiDefButR_prop(block,
374 UI_BTYPE_HSVCIRCLE,
375 0,
376 "",
377 0,
378 0,
379 PICKER_H,
380 PICKER_W,
381 ptr,
382 prop,
383 -1,
384 0.0,
385 0.0,
386 0.0,
387 0,
388 TIP_("Color"));
389 UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
390 bt->custom_data = cpicker;
391
392 /* value */
393 if (U.color_picker_type == USER_CP_CIRCLE_HSL) {
394 hsv_but = (uiButHSVCube *)uiDefButR_prop(block,
395 UI_BTYPE_HSVCUBE,
396 0,
397 "",
398 PICKER_W + PICKER_SPACE,
399 0,
400 PICKER_BAR,
401 PICKER_H,
402 ptr,
403 prop,
404 -1,
405 0.0,
406 0.0,
407 0,
408 0,
409 "Lightness");
410 hsv_but->gradient_type = UI_GRAD_L_ALT;
411 UI_but_func_set(&hsv_but->but, ui_colorpicker_rna_cb, &hsv_but->but, NULL);
412 }
413 else {
414 hsv_but = (uiButHSVCube *)uiDefButR_prop(block,
415 UI_BTYPE_HSVCUBE,
416 0,
417 "",
418 PICKER_W + PICKER_SPACE,
419 0,
420 PICKER_BAR,
421 PICKER_H,
422 ptr,
423 prop,
424 -1,
425 0.0,
426 0.0,
427 0,
428 0,
429 TIP_("Value"));
430 hsv_but->gradient_type = UI_GRAD_V_ALT;
431 UI_but_func_set(&hsv_but->but, ui_colorpicker_rna_cb, &hsv_but->but, NULL);
432 }
433 hsv_but->but.custom_data = cpicker;
434 }
435
ui_colorpicker_square(uiBlock * block,PointerRNA * ptr,PropertyRNA * prop,eButGradientType type,ColorPicker * cpicker)436 static void ui_colorpicker_square(uiBlock *block,
437 PointerRNA *ptr,
438 PropertyRNA *prop,
439 eButGradientType type,
440 ColorPicker *cpicker)
441 {
442 uiButHSVCube *hsv_but;
443
444 BLI_assert(type <= UI_GRAD_HS);
445
446 /* HS square */
447 hsv_but = (uiButHSVCube *)uiDefButR_prop(block,
448 UI_BTYPE_HSVCUBE,
449 0,
450 "",
451 0,
452 PICKER_BAR + PICKER_SPACE,
453 PICKER_TOTAL_W,
454 PICKER_H,
455 ptr,
456 prop,
457 -1,
458 0.0,
459 0.0,
460 0,
461 0,
462 TIP_("Color"));
463 hsv_but->gradient_type = type;
464 UI_but_func_set(&hsv_but->but, ui_colorpicker_rna_cb, &hsv_but->but, NULL);
465 hsv_but->but.custom_data = cpicker;
466
467 /* value */
468 hsv_but = (uiButHSVCube *)uiDefButR_prop(block,
469 UI_BTYPE_HSVCUBE,
470 0,
471 "",
472 0,
473 0,
474 PICKER_TOTAL_W,
475 PICKER_BAR,
476 ptr,
477 prop,
478 -1,
479 0.0,
480 0.0,
481 0,
482 0,
483 TIP_("Value"));
484 hsv_but->gradient_type = type + 3;
485 UI_but_func_set(&hsv_but->but, ui_colorpicker_rna_cb, &hsv_but->but, NULL);
486 hsv_but->but.custom_data = cpicker;
487 }
488
489 /* a HS circle, V slider, rgb/hsv/hex sliders */
ui_block_colorpicker(uiBlock * block,uiBut * from_but,float rgba[4],bool show_picker)490 static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4], bool show_picker)
491 {
492 /* ePickerType */
493 static char colormode = 1;
494 uiBut *bt;
495 int width, butwidth;
496 static char hexcol[128];
497 float softmin, softmax, hardmin, hardmax, step, precision;
498 int yco;
499 ColorPicker *cpicker = ui_block_colorpicker_create(block);
500 float *hsv = cpicker->color_data;
501 PointerRNA *ptr = &from_but->rnapoin;
502 PropertyRNA *prop = from_but->rnaprop;
503
504 width = PICKER_TOTAL_W;
505 butwidth = width - 1.5f * UI_UNIT_X;
506
507 /* sneaky way to check for alpha */
508 rgba[3] = FLT_MAX;
509
510 RNA_property_float_ui_range(ptr, prop, &softmin, &softmax, &step, &precision);
511 RNA_property_float_range(ptr, prop, &hardmin, &hardmax);
512 RNA_property_float_get_array(ptr, prop, rgba);
513
514 float rgb_perceptual[3];
515 copy_v3_v3(rgb_perceptual, rgba);
516 ui_scene_linear_to_color_picker_space(from_but, rgb_perceptual);
517 ui_rgb_to_color_picker_v(rgb_perceptual, hsv);
518 if (cpicker->is_init == false) {
519 copy_v3_v3(cpicker->color_data_init, cpicker->color_data);
520 cpicker->is_init = true;
521 }
522
523 /* when the softmax isn't defined in the RNA,
524 * using very large numbers causes sRGB/linear round trip to fail. */
525 if (softmax == FLT_MAX) {
526 softmax = 1.0f;
527 }
528
529 switch (U.color_picker_type) {
530 case USER_CP_SQUARE_SV:
531 ui_colorpicker_square(block, ptr, prop, UI_GRAD_SV, cpicker);
532 break;
533 case USER_CP_SQUARE_HS:
534 ui_colorpicker_square(block, ptr, prop, UI_GRAD_HS, cpicker);
535 break;
536 case USER_CP_SQUARE_HV:
537 ui_colorpicker_square(block, ptr, prop, UI_GRAD_HV, cpicker);
538 break;
539
540 /* user default */
541 case USER_CP_CIRCLE_HSV:
542 case USER_CP_CIRCLE_HSL:
543 default:
544 ui_colorpicker_circle(block, ptr, prop, cpicker);
545 break;
546 }
547
548 /* mode */
549 yco = -1.5f * UI_UNIT_Y;
550 UI_block_align_begin(block);
551 bt = uiDefButC(block,
552 UI_BTYPE_ROW,
553 0,
554 IFACE_("RGB"),
555 0,
556 yco,
557 width / 3,
558 UI_UNIT_Y,
559 &colormode,
560 0.0,
561 (float)PICKER_TYPE_RGB,
562 0,
563 0,
564 "");
565 UI_but_flag_disable(bt, UI_BUT_UNDO);
566 UI_but_func_set(bt, ui_colorpicker_create_mode_cb, bt, NULL);
567 bt->custom_data = cpicker;
568 bt = uiDefButC(block,
569 UI_BTYPE_ROW,
570 0,
571 IFACE_((U.color_picker_type == USER_CP_CIRCLE_HSL) ? "HSL" : "HSV"),
572 width / 3,
573 yco,
574 width / 3,
575 UI_UNIT_Y,
576 &colormode,
577 0.0,
578 PICKER_TYPE_HSV,
579 0,
580 0,
581 "");
582 UI_but_flag_disable(bt, UI_BUT_UNDO);
583 UI_but_func_set(bt, ui_colorpicker_create_mode_cb, bt, NULL);
584 bt->custom_data = cpicker;
585 bt = uiDefButC(block,
586 UI_BTYPE_ROW,
587 0,
588 IFACE_("Hex"),
589 2 * width / 3,
590 yco,
591 width / 3,
592 UI_UNIT_Y,
593 &colormode,
594 0.0,
595 PICKER_TYPE_HEX,
596 0,
597 0,
598 "");
599 UI_but_flag_disable(bt, UI_BUT_UNDO);
600 UI_but_func_set(bt, ui_colorpicker_create_mode_cb, bt, NULL);
601 bt->custom_data = cpicker;
602 UI_block_align_end(block);
603
604 yco = -3.0f * UI_UNIT_Y;
605 if (show_picker) {
606 bt = uiDefIconButO(block,
607 UI_BTYPE_BUT,
608 "UI_OT_eyedropper_color",
609 WM_OP_INVOKE_DEFAULT,
610 ICON_EYEDROPPER,
611 butwidth + 10,
612 yco,
613 UI_UNIT_X,
614 UI_UNIT_Y,
615 NULL);
616 UI_but_flag_disable(bt, UI_BUT_UNDO);
617 UI_but_drawflag_disable(bt, UI_BUT_ICON_LEFT);
618 UI_but_func_set(bt, ui_popup_close_cb, bt, NULL);
619 bt->custom_data = cpicker;
620 }
621
622 /* Note: don't disable UI_BUT_UNDO for RGBA values, since these don't add undo steps. */
623
624 /* RGB values */
625 UI_block_align_begin(block);
626 bt = uiDefButR_prop(block,
627 UI_BTYPE_NUM_SLIDER,
628 0,
629 IFACE_("R:"),
630 0,
631 yco,
632 butwidth,
633 UI_UNIT_Y,
634 ptr,
635 prop,
636 0,
637 0.0,
638 0.0,
639 0,
640 3,
641 TIP_("Red"));
642 UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
643 bt->custom_data = cpicker;
644 bt = uiDefButR_prop(block,
645 UI_BTYPE_NUM_SLIDER,
646 0,
647 IFACE_("G:"),
648 0,
649 yco -= UI_UNIT_Y,
650 butwidth,
651 UI_UNIT_Y,
652 ptr,
653 prop,
654 1,
655 0.0,
656 0.0,
657 0,
658 3,
659 TIP_("Green"));
660 UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
661 bt->custom_data = cpicker;
662 bt = uiDefButR_prop(block,
663 UI_BTYPE_NUM_SLIDER,
664 0,
665 IFACE_("B:"),
666 0,
667 yco -= UI_UNIT_Y,
668 butwidth,
669 UI_UNIT_Y,
670 ptr,
671 prop,
672 2,
673 0.0,
674 0.0,
675 0,
676 3,
677 TIP_("Blue"));
678 UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
679 bt->custom_data = cpicker;
680
681 /* Could use:
682 * uiItemFullR(col, ptr, prop, -1, 0, UI_ITEM_R_EXPAND | UI_ITEM_R_SLIDER, "", ICON_NONE);
683 * but need to use UI_but_func_set for updating other fake buttons */
684
685 /* HSV values */
686 yco = -3.0f * UI_UNIT_Y;
687 UI_block_align_begin(block);
688 bt = uiDefButF(block,
689 UI_BTYPE_NUM_SLIDER,
690 0,
691 IFACE_("H:"),
692 0,
693 yco,
694 butwidth,
695 UI_UNIT_Y,
696 hsv,
697 0.0,
698 1.0,
699 10,
700 3,
701 TIP_("Hue"));
702 UI_but_flag_disable(bt, UI_BUT_UNDO);
703 UI_but_func_set(bt, ui_color_wheel_rna_cb, bt, hsv);
704 bt->custom_data = cpicker;
705 bt = uiDefButF(block,
706 UI_BTYPE_NUM_SLIDER,
707 0,
708 IFACE_("S:"),
709 0,
710 yco -= UI_UNIT_Y,
711 butwidth,
712 UI_UNIT_Y,
713 hsv + 1,
714 0.0,
715 1.0,
716 10,
717 3,
718 TIP_("Saturation"));
719 UI_but_flag_disable(bt, UI_BUT_UNDO);
720 UI_but_func_set(bt, ui_color_wheel_rna_cb, bt, hsv);
721 bt->custom_data = cpicker;
722 if (U.color_picker_type == USER_CP_CIRCLE_HSL) {
723 bt = uiDefButF(block,
724 UI_BTYPE_NUM_SLIDER,
725 0,
726 IFACE_("L:"),
727 0,
728 yco -= UI_UNIT_Y,
729 butwidth,
730 UI_UNIT_Y,
731 hsv + 2,
732 0.0,
733 1.0,
734 10,
735 3,
736 TIP_("Lightness"));
737 }
738 else {
739 bt = uiDefButF(block,
740 UI_BTYPE_NUM_SLIDER,
741 0,
742 IFACE_("V:"),
743 0,
744 yco -= UI_UNIT_Y,
745 butwidth,
746 UI_UNIT_Y,
747 hsv + 2,
748 0.0,
749 softmax,
750 10,
751 3,
752 TIP_("Value"));
753 }
754 UI_but_flag_disable(bt, UI_BUT_UNDO);
755
756 bt->hardmax = hardmax; /* not common but rgb may be over 1.0 */
757 UI_but_func_set(bt, ui_color_wheel_rna_cb, bt, hsv);
758 bt->custom_data = cpicker;
759
760 UI_block_align_end(block);
761
762 if (rgba[3] != FLT_MAX) {
763 bt = uiDefButR_prop(block,
764 UI_BTYPE_NUM_SLIDER,
765 0,
766 IFACE_("A: "),
767 0,
768 yco -= UI_UNIT_Y,
769 butwidth,
770 UI_UNIT_Y,
771 ptr,
772 prop,
773 3,
774 0.0,
775 0.0,
776 0,
777 3,
778 TIP_("Alpha"));
779 UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
780 bt->custom_data = cpicker;
781 }
782 else {
783 rgba[3] = 1.0f;
784 }
785
786 /* Hex color is in sRGB space. */
787 float rgb_hex[3];
788 uchar rgb_hex_uchar[3];
789
790 copy_v3_v3(rgb_hex, rgba);
791
792 if (!ui_but_is_color_gamma(from_but)) {
793 IMB_colormanagement_scene_linear_to_srgb_v3(rgb_hex);
794 ui_color_picker_rgb_round(rgb_hex);
795 }
796
797 rgb_float_to_uchar(rgb_hex_uchar, rgb_hex);
798 BLI_snprintf(hexcol, sizeof(hexcol), "%02X%02X%02X", UNPACK3_EX((uint), rgb_hex_uchar, ));
799
800 yco = -3.0f * UI_UNIT_Y;
801 bt = uiDefBut(block,
802 UI_BTYPE_TEXT,
803 0,
804 IFACE_("Hex: "),
805 0,
806 yco,
807 butwidth,
808 UI_UNIT_Y,
809 hexcol,
810 0,
811 8,
812 0,
813 0,
814 TIP_("Hex triplet for color (#RRGGBB)"));
815 UI_but_flag_disable(bt, UI_BUT_UNDO);
816 UI_but_func_set(bt, ui_colorpicker_hex_rna_cb, bt, hexcol);
817 bt->custom_data = cpicker;
818 uiDefBut(block,
819 UI_BTYPE_LABEL,
820 0,
821 IFACE_("(Gamma Corrected)"),
822 0,
823 yco - UI_UNIT_Y,
824 butwidth,
825 UI_UNIT_Y,
826 NULL,
827 0.0,
828 0.0,
829 0,
830 0,
831 "");
832
833 ui_colorpicker_hide_reveal(block, colormode);
834 }
835
ui_colorpicker_small_wheel_cb(const bContext * UNUSED (C),uiBlock * block,const wmEvent * event)836 static int ui_colorpicker_small_wheel_cb(const bContext *UNUSED(C),
837 uiBlock *block,
838 const wmEvent *event)
839 {
840 float add = 0.0f;
841
842 if (event->type == WHEELUPMOUSE) {
843 add = 0.05f;
844 }
845 else if (event->type == WHEELDOWNMOUSE) {
846 add = -0.05f;
847 }
848
849 if (add != 0.0f) {
850 LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
851 if (but->type == UI_BTYPE_HSVCUBE && but->active == NULL) {
852 uiPopupBlockHandle *popup = block->handle;
853 float rgb[3];
854 ColorPicker *cpicker = but->custom_data;
855 float *hsv = cpicker->color_data;
856
857 ui_but_v3_get(but, rgb);
858 ui_scene_linear_to_color_picker_space(but, rgb);
859 ui_rgb_to_color_picker_compat_v(rgb, hsv);
860
861 hsv[2] = clamp_f(hsv[2] + add, 0.0f, 1.0f);
862
863 ui_color_picker_to_rgb_v(hsv, rgb);
864 ui_color_picker_to_scene_linear_space(but, rgb);
865 ui_but_v3_set(but, rgb);
866
867 ui_update_color_picker_buts_rgb(but, block, cpicker, rgb);
868 if (popup) {
869 popup->menuretval = UI_RETURN_UPDATE;
870 }
871
872 return 1;
873 }
874 }
875 }
876 return 0;
877 }
878
ui_block_func_COLOR(bContext * C,uiPopupBlockHandle * handle,void * arg_but)879 uiBlock *ui_block_func_COLOR(bContext *C, uiPopupBlockHandle *handle, void *arg_but)
880 {
881 uiBut *but = arg_but;
882 uiBlock *block;
883 bool show_picker = true;
884
885 block = UI_block_begin(C, handle->region, __func__, UI_EMBOSS);
886
887 if (ui_but_is_color_gamma(but)) {
888 block->is_color_gamma_picker = true;
889 }
890
891 if (but->block) {
892 /* if color block is invoked from a popup we wouldn't be able to set color properly
893 * this is because color picker will close popups first and then will try to figure
894 * out active button RNA, and of course it'll fail
895 */
896 show_picker = (but->block->flag & UI_BLOCK_POPUP) == 0;
897 }
898
899 copy_v3_v3(handle->retvec, but->editvec);
900
901 ui_block_colorpicker(block, but, handle->retvec, show_picker);
902
903 block->flag = UI_BLOCK_LOOP | UI_BLOCK_KEEP_OPEN | UI_BLOCK_OUT_1 | UI_BLOCK_MOVEMOUSE_QUIT;
904 UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
905 UI_block_bounds_set_normal(block, 0.5 * UI_UNIT_X);
906
907 block->block_event_func = ui_colorpicker_small_wheel_cb;
908
909 /* and lets go */
910 block->direction = UI_DIR_UP;
911
912 return block;
913 }
914
ui_block_colorpicker_create(struct uiBlock * block)915 ColorPicker *ui_block_colorpicker_create(struct uiBlock *block)
916 {
917 ColorPicker *cpicker = MEM_callocN(sizeof(ColorPicker), "color_picker");
918 BLI_addhead(&block->color_pickers.list, cpicker);
919
920 return cpicker;
921 }
922
923 /** \} */
924