Blender V4.5
interface_region_color_picker.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2008 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include <cstdarg>
12#include <cstdlib>
13#include <cstring>
14
15#include "MEM_guardedalloc.h"
16
17#include "DNA_userdef_types.h"
18
19#include "BLI_listbase.h"
20#include "BLI_string.h"
21#include "BLI_utildefines.h"
22
23#include "WM_api.hh"
24#include "WM_types.hh"
25
26#include "RNA_access.hh"
27
28#include "UI_interface.hh"
29
30#include "BLT_translation.hh"
31
33
34#include "interface_intern.hh"
35
40
41/* -------------------------------------------------------------------- */
44
45static void ui_color_picker_rgb_round(float rgb[3])
46{
47 /* Handle small rounding errors in color space conversions. Doing these for
48 * all color space conversions would be expensive, but for the color picker
49 * we can do the extra work. */
50 for (int i = 0; i < 3; i++) {
51 if (fabsf(rgb[i]) < 5e-5f) {
52 rgb[i] = 0.0f;
53 }
54 else if (fabsf(1.0f - rgb[i]) < 5e-5f) {
55 rgb[i] = 1.0f;
56 }
57 }
58}
59
60void ui_color_picker_rgb_to_hsv_compat(const float rgb[3], float r_cp[3])
61{
62 /* Convert RGB to HSV, remaining as compatible as possible with the existing
63 * r_hsv value (for example when value goes to zero, preserve the hue). */
64 switch (U.color_picker_type) {
66 rgb_to_hsl_compat_v(rgb, r_cp);
67 break;
68 default:
69 rgb_to_hsv_compat_v(rgb, r_cp);
70 break;
71 }
72}
73
74void ui_color_picker_rgb_to_hsv(const float rgb[3], float r_cp[3])
75{
76 switch (U.color_picker_type) {
78 rgb_to_hsl_v(rgb, r_cp);
79 break;
80 default:
81 rgb_to_hsv_v(rgb, r_cp);
82 break;
83 }
84}
85
86void ui_color_picker_hsv_to_rgb(const float r_cp[3], float rgb[3])
87{
88 switch (U.color_picker_type) {
90 hsl_to_rgb_v(r_cp, rgb);
91 break;
92 default:
93 hsv_to_rgb_v(r_cp, rgb);
94 break;
95 }
96}
97
99{
100 if (but->rnaprop) {
102 return true;
103 }
104 }
105
106 return but->block->is_color_gamma_picker;
107}
108
110{
111 if (but->rnaprop) {
112 const PropertySubType prop_subtype = RNA_property_subtype(but->rnaprop);
113 if (ELEM(prop_subtype, PROP_COLOR, PROP_COLOR_GAMMA)) {
114 const int color_components_count = RNA_property_array_length(&but->rnapoin, but->rnaprop);
115 if (color_components_count == 4) {
116 return true;
117 }
118 }
119 }
120
121 return false;
122}
123
125{
126 /* Map to color picking space for HSV values and HSV cube/circle,
127 * assuming it is more perceptually linear than the scene linear
128 * space for intuitive color picking. */
129 if (!ui_but_is_color_gamma(but)) {
132 }
133}
134
142
144
145/* -------------------------------------------------------------------- */
148
150 uiBut *from_but,
151 const float rgb_scene_linear[3])
152{
153 /* Convert from RGB to HSV in scene linear space color for number editing. */
154 if (cpicker->is_init == false) {
155 ui_color_picker_rgb_to_hsv(rgb_scene_linear, cpicker->hsv_scene_linear);
156 }
157 else {
158 ui_color_picker_rgb_to_hsv_compat(rgb_scene_linear, cpicker->hsv_scene_linear);
159 }
160
161 /* Convert from RGB to HSV in perceptually linear space for picker widgets. */
162 float rgb_perceptual[3];
163 copy_v3_v3(rgb_perceptual, rgb_scene_linear);
164 if (from_but) {
165 ui_scene_linear_to_perceptual_space(from_but, rgb_perceptual);
166 }
167
168 if (cpicker->is_init == false) {
169 ui_color_picker_rgb_to_hsv(rgb_perceptual, cpicker->hsv_perceptual);
171 }
172 else {
173 ui_color_picker_rgb_to_hsv_compat(rgb_perceptual, cpicker->hsv_perceptual);
174 }
175
176 cpicker->is_init = true;
177}
178
180{
181 float rgb_perceptual[3];
182 ColorPicker *cpicker = static_cast<ColorPicker *>(but->custom_data);
183 float *hsv_perceptual = cpicker->hsv_perceptual;
184
185 ui_color_picker_hsv_to_rgb(hsv_perceptual, rgb_perceptual);
186
187 ui_but_v3_set(but, rgb_perceptual);
188}
189
190/* Updates all buttons who share the same color picker as the one passed. */
192 uiBlock *block,
193 ColorPicker *cpicker,
194 const float rgba_scene_linear[4])
195{
196 ui_color_picker_update_hsv(cpicker, from_but, rgba_scene_linear);
197
198 for (const std::unique_ptr<uiBut> &bt : block->buttons) {
199 if (bt->custom_data != cpicker) {
200 continue;
201 }
202
203 if (bt->rnaprop) {
204 ui_but_v4_set(bt.get(), rgba_scene_linear);
205 /* original button that created the color picker already does undo
206 * push, so disable it on RNA buttons in the color picker block */
208 }
209 else if (bt->type == UI_BTYPE_TEXT) {
210 /* Hex text input field. */
211 float rgba_hex[4];
212 uchar rgba_hex_uchar[4];
213 char col[16];
214
215 /* Hex code is assumed to be in sRGB space (coming from other applications, web, etc...). */
216 copy_v4_v4(rgba_hex, rgba_scene_linear);
217 if (from_but && !ui_but_is_color_gamma(from_but)) {
220 }
221
222 rgba_float_to_uchar(rgba_hex_uchar, rgba_hex);
223
224 int col_len;
225 if (cpicker->has_alpha) {
226 col_len = SNPRINTF_RLEN(col, "#%02X%02X%02X%02X", UNPACK4_EX((uint), rgba_hex_uchar, ));
227 }
228 else {
229 col_len = SNPRINTF_RLEN(col, "#%02X%02X%02X", UNPACK3_EX((uint), rgba_hex_uchar, ));
230 }
231 memcpy(bt->poin, col, col_len + 1); /* +1 offset for the # symbol. */
232 }
233
234 ui_but_update(bt.get());
235 }
236}
237
238static void ui_colorpicker_rgba_update_cb(bContext * /*C*/, void *bt1, void * /*arg*/)
239{
240 uiBut *but = static_cast<uiBut *>(bt1);
241 uiPopupBlockHandle *popup = but->block->handle;
242 ColorPicker *cpicker = static_cast<ColorPicker *>(but->custom_data);
243 PointerRNA ptr = but->rnapoin;
244 PropertyRNA *prop = but->rnaprop;
245 float rgba_scene_linear[4];
246
247 if (prop) {
248 zero_v4(rgba_scene_linear);
250 &ptr, prop, rgba_scene_linear, ARRAY_SIZE(rgba_scene_linear));
251 ui_update_color_picker_buts_rgba(but, but->block, cpicker, rgba_scene_linear);
252 }
253
254 if (popup) {
256 }
257}
258
259static void ui_colorpicker_hsv_update_cb(bContext * /*C*/, void *bt1, void *bt2)
260{
261 uiBut *but = static_cast<uiBut *>(bt1);
262 uiPopupBlockHandle *popup = but->block->handle;
263 ColorPicker *cpicker = static_cast<ColorPicker *>(but->custom_data);
264
265 /* Get RNA ptr/prop from the original color datablock button (bt2) since the HSV buttons (bt1)
266 * do not directly point to it. */
267 uiBut *color_but = static_cast<uiBut *>(bt2);
268 PointerRNA color_ptr = color_but->rnapoin;
269 PropertyRNA *color_prop = color_but->rnaprop;
270 float rgba_scene_linear[4];
271
272 if (color_prop) {
273 zero_v4(rgba_scene_linear);
274 /* Get the current RGBA color for its (optional) Alpha component,
275 * then update RGB components from the current HSV values. */
277 &color_ptr, color_prop, rgba_scene_linear, ARRAY_SIZE(rgba_scene_linear));
278 ui_color_picker_hsv_to_rgb(cpicker->hsv_scene_linear, rgba_scene_linear);
279 ui_update_color_picker_buts_rgba(but, but->block, cpicker, rgba_scene_linear);
280 }
281
282 if (popup) {
284 }
285}
286
287static void ui_colorpicker_hex_rna_cb(bContext * /*C*/, void *bt1, void *bt2)
288{
289 uiBut *but = static_cast<uiBut *>(bt1);
290 uiPopupBlockHandle *popup = but->block->handle;
291 ColorPicker *cpicker = static_cast<ColorPicker *>(but->custom_data);
292 char hexcol[128];
293 ui_but_string_get(but, hexcol, ARRAY_SIZE(hexcol));
294
295 /* In case the current color contains an Alpha component but the Hex string does not, get the
296 * current color to preserve the Alpha component.
297 * Like #ui_colorpicker_hsv_update_cb, the original color datablock button (bt2) is used since
298 * Hex Text Field button (bt1) doesn't directly point to it. */
299 uiBut *color_but = static_cast<uiBut *>(bt2);
300 PointerRNA color_ptr = color_but->rnapoin;
301 PropertyRNA *color_prop = color_but->rnaprop;
302
303 float rgba[4];
304 if (color_prop) {
305 zero_v4(rgba);
306 RNA_property_float_get_array_at_most(&color_ptr, color_prop, rgba, ARRAY_SIZE(rgba));
307 }
308 /* Override current color with parsed the Hex string to preserve the original Alpha if the
309 * hex string doesn't contain it. */
310 hex_to_rgba(hexcol, rgba, rgba + 1, rgba + 2, rgba + 3);
311
312 /* Hex code is assumed to be in sRGB space (coming from other applications, web, etc...). */
313 if (!ui_but_is_color_gamma(but)) {
316 }
317
318 ui_update_color_picker_buts_rgba(but, but->block, cpicker, rgba);
319
320 if (popup) {
322 }
323}
324
325static void ui_popup_close_cb(bContext * /*C*/, void *bt1, void * /*arg*/)
326{
327 uiBut *but = (uiBut *)bt1;
328 uiPopupBlockHandle *popup = but->block->handle;
329
330 if (popup) {
331 ColorPicker *cpicker = static_cast<ColorPicker *>(but->custom_data);
332 BLI_assert(cpicker->is_init);
333 popup->menuretval = (equals_v3v3(cpicker->hsv_perceptual, cpicker->hsv_perceptual_init) ?
336 }
337}
338
339static void ui_colorpicker_hide_reveal(uiBlock *block, ePickerType colormode)
340{
341 /* tag buttons */
342 for (const std::unique_ptr<uiBut> &bt : block->buttons) {
343 if ((bt->func == ui_colorpicker_rgba_update_cb) && (bt->type == UI_BTYPE_NUM_SLIDER) &&
344 (bt->rnaindex != 3))
345 {
346 /* RGB sliders (color circle and alpha are always shown) */
347 SET_FLAG_FROM_TEST(bt->flag, (colormode != PICKER_TYPE_RGB), UI_HIDDEN);
348 }
349 else if (bt->func == ui_colorpicker_hsv_update_cb) {
350 /* HSV sliders */
351 SET_FLAG_FROM_TEST(bt->flag, (colormode != PICKER_TYPE_HSV), UI_HIDDEN);
352 }
353 }
354}
355
356static void ui_colorpicker_create_mode_cb(bContext * /*C*/, void *bt1, void * /*arg*/)
357{
358 uiBut *bt = static_cast<uiBut *>(bt1);
359 const short colormode = ui_but_value_get(bt);
361}
362
363#define PICKER_TOTAL_W (180.0f * UI_SCALE_FAC)
364#define PICKER_BAR ((8.0f * UI_SCALE_FAC) + (6 * U.pixelsize))
365#define PICKER_SPACE (8.0f * UI_SCALE_FAC)
366#define PICKER_W (PICKER_TOTAL_W - PICKER_BAR - PICKER_SPACE)
367#define PICKER_H PICKER_W
368
371 PropertyRNA *prop,
372 ColorPicker *cpicker)
373{
374 uiBut *bt;
375 uiButHSVCube *hsv_but;
376
377 /* HS circle */
378 bt = uiDefButR_prop(block,
380 0,
381 "",
382 0,
383 0,
384 PICKER_H,
385 PICKER_W,
386 ptr,
387 prop,
388 -1,
389 0.0,
390 0.0,
391 TIP_("Color"));
393 bt->custom_data = cpicker;
394
395 /* value */
396 if (U.color_picker_type == USER_CP_CIRCLE_HSL) {
397 hsv_but = (uiButHSVCube *)uiDefButR_prop(block,
399 0,
400 "",
402 0,
404 PICKER_H,
405 ptr,
406 prop,
407 -1,
408 0.0,
409 0.0,
410 "Lightness");
411 hsv_but->gradient_type = UI_GRAD_L_ALT;
412 UI_but_func_set(hsv_but, ui_colorpicker_rgba_update_cb, hsv_but, nullptr);
413 }
414 else {
415 hsv_but = (uiButHSVCube *)uiDefButR_prop(block,
417 0,
418 "",
420 0,
422 PICKER_H,
423 ptr,
424 prop,
425 -1,
426 0.0,
427 0.0,
429 hsv_but->gradient_type = UI_GRAD_V_ALT;
430 UI_but_func_set(hsv_but, ui_colorpicker_rgba_update_cb, hsv_but, nullptr);
431 }
432 hsv_but->custom_data = cpicker;
433}
434
437 PropertyRNA *prop,
438 eButGradientType type,
439 ColorPicker *cpicker)
440{
441 uiButHSVCube *hsv_but;
442
443 BLI_assert(type <= UI_GRAD_HS);
444
445 /* HS square */
446 hsv_but = (uiButHSVCube *)uiDefButR_prop(block,
448 0,
449 "",
450 0,
453 PICKER_H,
454 ptr,
455 prop,
456 -1,
457 0.0,
458 0.0,
459 TIP_("Color"));
460 hsv_but->gradient_type = type;
461 UI_but_func_set(hsv_but, ui_colorpicker_rgba_update_cb, hsv_but, nullptr);
462 hsv_but->custom_data = cpicker;
463
464 /* value */
465 hsv_but = (uiButHSVCube *)uiDefButR_prop(block,
467 0,
468 "",
469 0,
470 0,
473 ptr,
474 prop,
475 -1,
476 0.0,
477 0.0,
479 hsv_but->gradient_type = (eButGradientType)(type + 3);
480 UI_but_func_set(hsv_but, ui_colorpicker_rgba_update_cb, hsv_but, nullptr);
481 hsv_but->custom_data = cpicker;
482}
483
484/* a HS circle, V slider, rgb/hsv/hex sliders */
485static void ui_block_colorpicker(uiBlock *block,
486 uiBut *from_but,
487 float rgba_scene_linear[4],
488 bool show_picker)
489{
490 /* ePickerType */
491 static char colormode = 1;
492 uiBut *bt;
493 int picker_width;
494 static char hexcol[128];
495 float softmin, softmax, hardmin, hardmax, step, precision;
496 int yco;
498 PointerRNA *ptr = &from_but->rnapoin;
499 PropertyRNA *prop = from_but->rnaprop;
500
501 picker_width = PICKER_TOTAL_W;
502
503 RNA_property_float_ui_range(ptr, prop, &softmin, &softmax, &step, &precision);
504 RNA_property_float_range(ptr, prop, &hardmin, &hardmax);
505 RNA_property_float_get_array_at_most(ptr, prop, rgba_scene_linear, 4);
506
507 ui_color_picker_update_hsv(cpicker, from_but, rgba_scene_linear);
508 cpicker->has_alpha = ui_but_color_has_alpha(from_but);
509
510 /* when the softmax isn't defined in the RNA,
511 * using very large numbers causes sRGB/linear round trip to fail. */
512 if (softmax == FLT_MAX) {
513 softmax = 1.0f;
514 }
515
516 switch (U.color_picker_type) {
518 ui_colorpicker_square(block, ptr, prop, UI_GRAD_SV, cpicker);
519 break;
521 ui_colorpicker_square(block, ptr, prop, UI_GRAD_HS, cpicker);
522 break;
524 ui_colorpicker_square(block, ptr, prop, UI_GRAD_HV, cpicker);
525 break;
526
527 /* user default */
530 default:
531 ui_colorpicker_circle(block, ptr, prop, cpicker);
532 break;
533 }
534
535 /* mode */
536 yco = -1.5f * UI_UNIT_Y;
538 bt = uiDefButC(block,
540 0,
541 IFACE_("RGB"),
542 0,
543 yco,
544 picker_width / 2,
545 UI_UNIT_Y,
546 &colormode,
547 0.0,
548 float(PICKER_TYPE_RGB),
549 TIP_("Red, Green, Blue"));
553 bt->custom_data = cpicker;
554 bt = uiDefButC(block,
556 0,
557 IFACE_((U.color_picker_type == USER_CP_CIRCLE_HSL) ? "HSL" : "HSV"),
558 picker_width / 2,
559 yco,
560 picker_width / 2,
561 UI_UNIT_Y,
562 &colormode,
563 0.0,
564 float(PICKER_TYPE_HSV),
565 (U.color_picker_type == USER_CP_CIRCLE_HSL) ? TIP_("Hue, Saturation, Lightness") :
566 TIP_("Hue, Saturation, Value"));
570 bt->custom_data = cpicker;
571 UI_block_align_end(block);
572
573 yco = -3.0f * UI_UNIT_Y;
574
575 /* NOTE: don't disable UI_BUT_UNDO for RGBA values, since these don't add undo steps. */
576
577 /* RGB values */
579 bt = uiDefButR_prop(block,
581 0,
582 IFACE_("Red:"),
583 0,
584 yco,
585 picker_width,
586 UI_UNIT_Y,
587 ptr,
588 prop,
589 0,
590 0.0,
591 0.0,
592 TIP_("Red"));
596 bt->custom_data = cpicker;
597 bt = uiDefButR_prop(block,
599 0,
600 IFACE_("Green:"),
601 0,
602 yco -= UI_UNIT_Y,
603 picker_width,
604 UI_UNIT_Y,
605 ptr,
606 prop,
607 1,
608 0.0,
609 0.0,
610 TIP_("Green"));
614 bt->custom_data = cpicker;
615 bt = uiDefButR_prop(block,
617 0,
618 IFACE_("Blue:"),
619 0,
620 yco -= UI_UNIT_Y,
621 picker_width,
622 UI_UNIT_Y,
623 ptr,
624 prop,
625 2,
626 0.0,
627 0.0,
628 TIP_("Blue"));
632 bt->custom_data = cpicker;
633
634 /* Could use:
635 * col->prop(ptr, prop, -1, 0, UI_ITEM_R_EXPAND | UI_ITEM_R_SLIDER, "", ICON_NONE);
636 * but need to use UI_but_func_set for updating other fake buttons */
637
638 /* HSV values */
639 yco = -3.0f * UI_UNIT_Y;
640 bt = uiDefButF(block,
642 0,
643 IFACE_("Hue:"),
644 0,
645 yco,
646 picker_width,
647 UI_UNIT_Y,
648 cpicker->hsv_scene_linear,
649 0.0,
650 1.0,
651 TIP_("Hue"));
656 bt->custom_data = cpicker;
657 bt = uiDefButF(block,
659 0,
660 IFACE_("Saturation:"),
661 0,
662 yco -= UI_UNIT_Y,
663 picker_width,
664 UI_UNIT_Y,
665 cpicker->hsv_scene_linear + 1,
666 0.0,
667 1.0,
668 TIP_("Saturation"));
673 bt->custom_data = cpicker;
674 if (U.color_picker_type == USER_CP_CIRCLE_HSL) {
675 bt = uiDefButF(block,
677 0,
678 IFACE_("Lightness:"),
679 0,
680 yco -= UI_UNIT_Y,
681 picker_width,
682 UI_UNIT_Y,
683 cpicker->hsv_scene_linear + 2,
684 0.0,
685 1.0,
686 TIP_("Lightness"));
689 }
690 else {
691 bt = uiDefButF(block,
693 0,
695 0,
696 yco -= UI_UNIT_Y,
697 picker_width,
698 UI_UNIT_Y,
699 cpicker->hsv_scene_linear + 2,
700 0.0,
701 softmax,
703 }
707
708 bt->hardmax = hardmax; /* Not common but RGB may be over 1.0. */
710 bt->custom_data = cpicker;
711
712 if (cpicker->has_alpha) {
713 bt = uiDefButR_prop(block,
715 0,
716 IFACE_("Alpha:"),
717 0,
718 yco -= UI_UNIT_Y,
719 picker_width,
720 UI_UNIT_Y,
721 ptr,
722 prop,
723 3,
724 0.0,
725 0.0,
726 TIP_("Alpha"));
730 bt->custom_data = cpicker;
731 }
732 else {
733 rgba_scene_linear[3] = 1.0f;
734 }
735
736 UI_block_align_end(block);
737
738 /* Hex color is in sRGB space. */
739 float rgba_hex[4];
740 uchar rgba_hex_uchar[4];
741
742 copy_v4_v4(rgba_hex, rgba_scene_linear);
743
744 if (!ui_but_is_color_gamma(from_but)) {
747 }
748
749 rgba_float_to_uchar(rgba_hex_uchar, rgba_hex);
750
751 if (cpicker->has_alpha) {
752 SNPRINTF(hexcol, "#%02X%02X%02X%02X", UNPACK4_EX((uint), rgba_hex_uchar, ));
753 }
754 else {
755 SNPRINTF(hexcol, "#%02X%02X%02X", UNPACK3_EX((uint), rgba_hex_uchar, ));
756 }
757
758 yco -= UI_UNIT_Y * 1.5f;
759
760 const int label_width = picker_width * 0.15f;
761 const int eyedropper_offset = show_picker ? UI_UNIT_X * 1.25f : 0;
762 const int text_width = picker_width - label_width - eyedropper_offset;
763
764 uiDefBut(block,
766 0,
767 IFACE_("Hex"),
768 0,
769 yco,
770 label_width,
771 UI_UNIT_Y,
772 nullptr,
773 0.0,
774 0.0,
775 std::nullopt);
776
777 bt = uiDefBut(block,
779 0,
780 IFACE_(""),
781 label_width,
782 yco,
783 text_width,
784 UI_UNIT_Y,
785 hexcol,
786 0,
787 cpicker->has_alpha ? 10 : 8,
788 std::nullopt);
789 const auto bt_tooltip_func = [](bContext & /*C*/, uiTooltipData &tip, void *has_alpha_ptr) {
790 const bool *has_alpha = static_cast<bool *>(has_alpha_ptr);
791 if (*has_alpha) {
793 "Hex triplet for color with alpha (#RRGGBBAA).",
794 {},
797 false);
798 }
799 else {
801 "Hex triplet for color (#RRGGBB).",
802 {},
805 false);
806 }
808 tip, "Gamma corrected", {}, UI_TIP_STYLE_NORMAL, UI_TIP_LC_NORMAL, false);
809 };
811 bt, bt_tooltip_func, static_cast<void *>(&cpicker->has_alpha), nullptr);
814 bt->custom_data = cpicker;
815
816 if (show_picker) {
817 bt = uiDefIconButO(block,
819 "UI_OT_eyedropper_color",
821 ICON_EYEDROPPER,
822 picker_width - UI_UNIT_X,
823 yco,
824 UI_UNIT_X,
825 UI_UNIT_Y,
826 std::nullopt);
829 UI_but_func_set(bt, ui_popup_close_cb, bt, nullptr);
830 bt->custom_data = cpicker;
831 }
832
833 ui_colorpicker_hide_reveal(block, (ePickerType)colormode);
834}
835
836static int ui_colorpicker_wheel_cb(const bContext * /*C*/, uiBlock *block, const wmEvent *event)
837{
838 /* Increase/Decrease the Color HSV Value component using the mouse wheel. */
839 float add = 0.0f;
840
841 switch (event->type) {
842 case WHEELUPMOUSE:
843 add = 0.05f;
844 break;
845 case WHEELDOWNMOUSE:
846 add = -0.05f;
847 break;
848 case MOUSEPAN:
849 add = 0.005f * WM_event_absolute_delta_y(event) / UI_SCALE_FAC;
850 break;
851 default:
852 break;
853 }
854
855 if (add != 0.0f) {
856 for (const std::unique_ptr<uiBut> &but : block->buttons) {
857 if (but->type == UI_BTYPE_HSVCUBE && but->active == nullptr) {
858 uiPopupBlockHandle *popup = block->handle;
859 ColorPicker *cpicker = static_cast<ColorPicker *>(but->custom_data);
860 float *hsv_perceptual = cpicker->hsv_perceptual;
861
862 /* Get the RGBA Color. */
863 float rgba_perceptual[4];
864 ui_but_v4_get(but.get(), rgba_perceptual);
865 ui_scene_linear_to_perceptual_space(but.get(), rgba_perceptual);
866
867 /* Convert it to HSV. */
868 ui_color_picker_rgb_to_hsv_compat(rgba_perceptual, hsv_perceptual);
869
870 /* Increment/Decrement its value from mouse wheel input. */
871 hsv_perceptual[2] = clamp_f(hsv_perceptual[2] + add, 0.0f, 1.0f);
872
873 /* Convert it to linear space RGBA, and apply it back to the button. */
874 float rgba_scene_linear[4];
875 rgba_scene_linear[3] = rgba_perceptual[3]; /* Transfer Alpha component. */
876 ui_color_picker_hsv_to_rgb(hsv_perceptual, rgba_scene_linear);
877 ui_perceptual_to_scene_linear_space(but.get(), rgba_scene_linear);
878 ui_but_v4_set(but.get(), rgba_scene_linear);
879
880 /* Update all other Color Picker buttons to reflect the color change. */
881 ui_update_color_picker_buts_rgba(but.get(), block, cpicker, rgba_scene_linear);
882 if (popup) {
884 }
885
886 return 1;
887 }
888 }
889 }
890 return 0;
891}
892
894{
895 uiBut *but = static_cast<uiBut *>(arg_but);
896 uiBlock *block;
897
898 block = UI_block_begin(C, handle->region, __func__, blender::ui::EmbossType::Emboss);
899
900 if (ui_but_is_color_gamma(but)) {
901 block->is_color_gamma_picker = true;
902 }
903
904 copy_v3_v3(handle->retvec, but->editvec);
905
906 ui_block_colorpicker(block, but, handle->retvec, true);
907
911
913 block->direction = UI_DIR_UP;
914
915 return block;
916}
917
919{
920 ColorPicker *cpicker = MEM_callocN<ColorPicker>(__func__);
921 BLI_addhead(&block->color_pickers.list, cpicker);
922
923 return cpicker;
924}
925
#define BLI_assert(a)
Definition BLI_assert.h:46
void BLI_addhead(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:91
MINLINE float clamp_f(float value, float min, float max)
void hsv_to_rgb_v(const float hsv[3], float r_rgb[3])
Definition math_color.cc:57
void rgb_to_hsv_v(const float rgb[3], float r_hsv[3])
void rgb_to_hsv_compat_v(const float rgb[3], float r_hsv[3])
void hex_to_rgba(const char *hexcol, float *r_r, float *r_g, float *r_b, float *r_a)
void hsl_to_rgb_v(const float hsl[3], float r_rgb[3])
Definition math_color.cc:62
void rgba_float_to_uchar(unsigned char r_col[4], const float col_f[4])
void rgb_to_hsl_v(const float rgb[3], float r_hsl[3])
void rgb_to_hsl_compat_v(const float rgb[3], float r_hsl[3])
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE bool equals_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void zero_v4(float r[4])
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:599
#define SNPRINTF_RLEN(dst, format,...)
Definition BLI_string.h:600
unsigned char uchar
unsigned int uint
#define UNPACK3_EX(pre, a, post)
#define ARRAY_SIZE(arr)
#define UNPACK4_EX(pre, a, post)
#define SET_FLAG_FROM_TEST(value, test, flag)
#define ELEM(...)
#define TIP_(msgid)
#define CTX_IFACE_(context, msgid)
#define IFACE_(msgid)
#define CTX_TIP_(context, msgid)
#define BLT_I18NCONTEXT_COLOR
#define UI_SCALE_FAC
@ USER_CP_SQUARE_SV
@ USER_CP_CIRCLE_HSL
@ USER_CP_SQUARE_HS
@ USER_CP_SQUARE_HV
@ USER_CP_CIRCLE_HSV
BLI_INLINE void IMB_colormanagement_srgb_to_scene_linear_v3(float scene_linear[3], const float srgb[3])
void IMB_colormanagement_color_picking_to_scene_linear_v3(float scene_linear[3], const float color_picking[3])
void IMB_colormanagement_scene_linear_to_color_picking_v3(float color_picking[3], const float scene_linear[3])
BLI_INLINE void IMB_colormanagement_scene_linear_to_srgb_v3(float srgb[3], const float scene_linear[3])
Read Guarded memory(de)allocation.
PropertySubType
Definition RNA_types.hh:220
@ PROP_COLOR
Definition RNA_types.hh:248
@ PROP_COLOR_GAMMA
Definition RNA_types.hh:260
#define C
Definition RandGen.cpp:29
void UI_but_func_set(uiBut *but, std::function< void(bContext &)> func)
void UI_but_flag_disable(uiBut *but, int flag)
#define UI_UNIT_Y
void UI_block_theme_style_set(uiBlock *block, char theme_style)
void UI_but_func_tooltip_custom_set(uiBut *but, uiButToolTipCustomFunc func, void *arg, uiFreeArgFunc free_arg)
uiBut * uiDefButR_prop(uiBlock *block, int type, int retval, std::optional< blender::StringRef > str, int x, int y, short width, short height, PointerRNA *ptr, PropertyRNA *prop, int index, float min, float max, std::optional< blender::StringRef > tip)
uiBlock * UI_block_begin(const bContext *C, ARegion *region, std::string name, blender::ui::EmbossType emboss)
@ UI_RETURN_UPDATE
@ UI_RETURN_CANCEL
@ UI_RETURN_OK
uiBut * uiDefBut(uiBlock *block, int type, int retval, blender::StringRef str, int x, int y, short width, short height, void *poin, float min, float max, std::optional< blender::StringRef > tip)
void UI_block_bounds_set_normal(uiBlock *block, int addval)
Definition interface.cc:625
void UI_tooltip_text_field_add(uiTooltipData &data, std::string text, std::string suffix, const uiTooltipStyle style, const uiTooltipColorID color_id, const bool is_pad=false)
@ UI_BLOCK_THEME_STYLE_POPUP
void UI_but_number_slider_precision_set(uiBut *but, float precision)
uiBut * uiDefIconButO(uiBlock *block, int type, blender::StringRefNull opname, wmOperatorCallContext opcontext, int icon, int x, int y, short width, short height, std::optional< blender::StringRef > tip)
uiBut * uiDefButC(uiBlock *block, int type, int retval, blender::StringRef str, int x, int y, short width, short height, char *poin, float min, float max, std::optional< blender::StringRef > tip)
@ UI_TIP_STYLE_NORMAL
@ UI_TIP_STYLE_HEADER
void UI_but_number_slider_step_size_set(uiBut *but, float step_size)
void UI_but_drawflag_disable(uiBut *but, int flag)
void UI_block_align_begin(uiBlock *block)
@ UI_BUT_ICON_LEFT
@ UI_BUT_TEXT_LEFT
eButGradientType
@ UI_GRAD_L_ALT
@ UI_GRAD_SV
@ UI_GRAD_V_ALT
@ UI_GRAD_HV
@ UI_GRAD_HS
@ UI_DIR_UP
@ UI_TIP_LC_NORMAL
#define UI_UNIT_X
@ UI_BTYPE_BUT
@ UI_BTYPE_NUM_SLIDER
@ UI_BTYPE_HSVCIRCLE
@ UI_BTYPE_TEXT
@ UI_BTYPE_HSVCUBE
@ UI_BTYPE_LABEL
@ UI_BTYPE_ROW
@ UI_BUT_UNDO
@ UI_BLOCK_LOOP
@ UI_BLOCK_MOVEMOUSE_QUIT
@ UI_BLOCK_KEEP_OPEN
@ UI_BLOCK_OUT_1
uiBut * uiDefButF(uiBlock *block, int type, int retval, blender::StringRef str, int x, int y, short width, short height, float *poin, float min, float max, std::optional< blender::StringRef > tip)
void UI_block_align_end(uiBlock *block)
@ WM_OP_INVOKE_DEFAULT
Definition WM_types.hh:238
#define U
#define fabsf(x)
uint col
VecBase< float, D > step(VecOp< float, D >, VecOp< float, D >) RET
void ui_but_v4_get(uiBut *but, float vec[4])
void ui_but_v4_set(uiBut *but, const float vec[4])
void ui_but_update(uiBut *but)
double ui_but_value_get(uiBut *but)
void ui_but_string_get(uiBut *but, char *str, const size_t str_maxncpy)
void ui_but_v3_set(uiBut *but, const float vec[3])
@ UI_HIDDEN
static void ui_color_picker_rgb_round(float rgb[3])
static void ui_colorpicker_hide_reveal(uiBlock *block, ePickerType colormode)
static void ui_colorpicker_square(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, eButGradientType type, ColorPicker *cpicker)
ColorPicker * ui_block_colorpicker_create(uiBlock *block)
void ui_perceptual_to_scene_linear_space(uiBut *but, float rgb[3])
static void ui_colorpicker_rgba_update_cb(bContext *, void *bt1, void *)
void ui_color_picker_hsv_to_rgb(const float r_cp[3], float rgb[3])
static void ui_colorpicker_hex_rna_cb(bContext *, void *bt1, void *bt2)
static void ui_colorpicker_circle(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, ColorPicker *cpicker)
void ui_color_picker_rgb_to_hsv(const float rgb[3], float r_cp[3])
void ui_scene_linear_to_perceptual_space(uiBut *but, float rgb[3])
static void ui_color_picker_update_hsv(ColorPicker *cpicker, uiBut *from_but, const float rgb_scene_linear[3])
void ui_but_hsv_set(uiBut *but)
static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba_scene_linear[4], bool show_picker)
static void ui_colorpicker_create_mode_cb(bContext *, void *bt1, void *)
uiBlock * ui_block_func_COLOR(bContext *C, uiPopupBlockHandle *handle, void *arg_but)
void ui_color_picker_rgb_to_hsv_compat(const float rgb[3], float r_cp[3])
bool ui_but_color_has_alpha(uiBut *but)
static void ui_colorpicker_hsv_update_cb(bContext *, void *bt1, void *bt2)
bool ui_but_is_color_gamma(uiBut *but)
static int ui_colorpicker_wheel_cb(const bContext *, uiBlock *block, const wmEvent *event)
static void ui_popup_close_cb(bContext *, void *bt1, void *)
static void ui_update_color_picker_buts_rgba(uiBut *from_but, uiBlock *block, ColorPicker *cpicker, const float rgba_scene_linear[4])
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
static void add(blender::Map< std::string, std::string > &messages, Message &msg)
Definition msgfmt.cc:222
void RNA_property_float_ui_range(PointerRNA *ptr, PropertyRNA *prop, float *softmin, float *softmax, float *step, float *precision)
void RNA_property_float_range(PointerRNA *ptr, PropertyRNA *prop, float *hardmin, float *hardmax)
void RNA_property_float_get_array_at_most(PointerRNA *ptr, PropertyRNA *prop, float *values, int values_num)
int RNA_property_array_length(PointerRNA *ptr, PropertyRNA *prop)
PropertySubType RNA_property_subtype(PropertyRNA *prop)
#define FLT_MAX
Definition stdcycles.h:14
float hsv_perceptual_init[3]
float hsv_scene_linear[3]
float hsv_perceptual[3]
blender::Vector< std::unique_ptr< uiBut > > buttons
bool is_color_gamma_picker
ColorPickerData color_pickers
uiPopupBlockHandle * handle
int(* block_event_func)(const bContext *C, uiBlock *, const wmEvent *)
eButGradientType gradient_type
void * custom_data
float * editvec
PropertyRNA * rnaprop
uiBlock * block
PointerRNA rnapoin
wmEventType type
Definition WM_types.hh:754
i
Definition text_draw.cc:230
int WM_event_absolute_delta_y(const wmEvent *event)
@ MOUSEPAN
@ WHEELUPMOUSE
@ WHEELDOWNMOUSE
PointerRNA * ptr
Definition wm_files.cc:4227