Fix T58549, T56741: HSV color picker issues with Filmic view transform.
[blender.git] / source / blender / editors / interface / interface_region_color_picker.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2008 Blender Foundation.
19  * All rights reserved.
20  *
21  * Contributor(s): Blender Foundation
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/editors/interface/interface_region_color_picker.c
27  *  \ingroup edinterface
28  *
29  * Color Picker Region & Color Utils
30  */
31
32 #include <stdarg.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <assert.h>
36
37 #include "MEM_guardedalloc.h"
38
39 #include "DNA_userdef_types.h"
40
41 #include "BLI_utildefines.h"
42 #include "BLI_math.h"
43 #include "BLI_listbase.h"
44 #include "BLI_string.h"
45
46 #include "BKE_context.h"
47
48 #include "WM_types.h"
49
50 #include "RNA_access.h"
51
52 #include "UI_interface.h"
53
54 #include "BLT_translation.h"
55
56 #include "ED_screen.h"
57
58 #include "IMB_colormanagement.h"
59
60 #include "interface_intern.h"
61
62 /* -------------------------------------------------------------------- */
63 /** \name Color Conversion
64  * \{ */
65
66 void ui_rgb_to_color_picker_compat_v(const float rgb[3], float r_cp[3])
67 {
68         switch (U.color_picker_type) {
69                 case USER_CP_CIRCLE_HSL:
70                         rgb_to_hsl_compat_v(rgb, r_cp);
71                         break;
72                 default:
73                         rgb_to_hsv_compat_v(rgb, r_cp);
74                         break;
75         }
76 }
77
78 void ui_rgb_to_color_picker_v(const float rgb[3], float r_cp[3])
79 {
80         switch (U.color_picker_type) {
81                 case USER_CP_CIRCLE_HSL:
82                         rgb_to_hsl_v(rgb, r_cp);
83                         break;
84                 default:
85                         rgb_to_hsv_v(rgb, r_cp);
86                         break;
87         }
88 }
89
90 void ui_color_picker_to_rgb_v(const float r_cp[3], float rgb[3])
91 {
92         switch (U.color_picker_type) {
93                 case USER_CP_CIRCLE_HSL:
94                         hsl_to_rgb_v(r_cp, rgb);
95                         break;
96                 default:
97                         hsv_to_rgb_v(r_cp, rgb);
98                         break;
99         }
100 }
101
102 void ui_color_picker_to_rgb(float r_cp0, float r_cp1, float r_cp2, float *r, float *g, float *b)
103 {
104         switch (U.color_picker_type) {
105                 case USER_CP_CIRCLE_HSL:
106                         hsl_to_rgb(r_cp0, r_cp1, r_cp2, r, g, b);
107                         break;
108                 default:
109                         hsv_to_rgb(r_cp0, r_cp1, r_cp2, r, g, b);
110                         break;
111         }
112 }
113
114 /* Returns true if the button is for a color with gamma baked in,
115  * or if it's a color picker for such a button. */
116 bool ui_but_is_color_gamma(uiBut *but)
117 {
118         if (but->rnaprop) {
119                 if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
120                         return true;
121                 }
122         }
123
124         return but->block->is_color_gamma_picker;
125 }
126
127 void ui_scene_linear_to_color_picker_space(uiBut *but, float rgb[3])
128 {
129         /* Map to color picking space for HSV values and HSV cube/circle,
130          * assuming it is more perceptually linear then the scene linear
131          * space for intuitive color picking. */
132         if (!ui_but_is_color_gamma(but)) {
133                 IMB_colormanagement_scene_linear_to_color_picking_v3(rgb);
134         }
135 }
136
137 void ui_color_picker_to_scene_linear_space(uiBut *but, float rgb[3])
138 {
139         if (!ui_but_is_color_gamma(but)) {
140                 IMB_colormanagement_color_picking_to_scene_linear_v3(rgb);
141         }
142 }
143
144 /** \} */
145
146 /* -------------------------------------------------------------------- */
147 /** \name Color Picker
148  * \{ */
149
150 /* for picker, while editing hsv */
151 void ui_but_hsv_set(uiBut *but)
152 {
153         float col[3];
154         ColorPicker *cpicker = but->custom_data;
155         float *hsv = cpicker->color_data;
156
157         ui_color_picker_to_rgb_v(hsv, col);
158
159         ui_but_v3_set(but, col);
160 }
161
162 /* Updates all buttons who share the same color picker as the one passed
163  * also used by small picker, be careful with name checks below... */
164 static void ui_update_color_picker_buts_rgb(
165         uiBut *from_but, uiBlock *block, ColorPicker *cpicker, const float rgb[3])
166 {
167         uiBut *bt;
168         float *hsv = cpicker->color_data;
169
170         /* Convert from RGB to HSV in perceptually linear space. */
171         float tmp[3];
172         copy_v3_v3(tmp, rgb);
173         if (from_but) {
174                 ui_scene_linear_to_color_picker_space(from_but, tmp);
175         }
176         ui_rgb_to_color_picker_compat_v(tmp, hsv);
177
178         /* this updates button strings, is hackish... but button pointers are on stack of caller function */
179         for (bt = block->buttons.first; bt; bt = bt->next) {
180                 if (bt->custom_data != cpicker)
181                         continue;
182
183                 if (bt->rnaprop) {
184                         ui_but_v3_set(bt, rgb);
185
186                         /* original button that created the color picker already does undo
187                          * push, so disable it on RNA buttons in the color picker block */
188                         UI_but_flag_disable(bt, UI_BUT_UNDO);
189                 }
190                 else if (STREQ(bt->str, "Hex: ")) {
191                         float rgb_gamma[3];
192                         unsigned char rgb_gamma_uchar[3];
193                         double intpart;
194                         char col[16];
195
196                         /* Hex code is assumed to be in sRGB space (coming from other applications, web, etc) */
197
198                         copy_v3_v3(rgb_gamma, rgb);
199
200                         if (!block->is_color_gamma_picker) {
201                                 /* make a display version, for Hex code */
202                                 ui_block_cm_to_display_space_v3(block, rgb_gamma);
203                         }
204
205                         if (rgb_gamma[0] > 1.0f) rgb_gamma[0] = modf(rgb_gamma[0], &intpart);
206                         if (rgb_gamma[1] > 1.0f) rgb_gamma[1] = modf(rgb_gamma[1], &intpart);
207                         if (rgb_gamma[2] > 1.0f) rgb_gamma[2] = modf(rgb_gamma[2], &intpart);
208
209                         rgb_float_to_uchar(rgb_gamma_uchar, rgb_gamma);
210                         BLI_snprintf(col, sizeof(col), "%02X%02X%02X", UNPACK3_EX((uint), rgb_gamma_uchar, ));
211
212                         strcpy(bt->poin, col);
213                 }
214                 else if (bt->str[1] == ' ') {
215                         if (bt->str[0] == 'R') {
216                                 ui_but_value_set(bt, rgb[0]);
217                         }
218                         else if (bt->str[0] == 'G') {
219                                 ui_but_value_set(bt, rgb[1]);
220                         }
221                         else if (bt->str[0] == 'B') {
222                                 ui_but_value_set(bt, rgb[2]);
223                         }
224                         else if (bt->str[0] == 'H') {
225                                 ui_but_value_set(bt, hsv[0]);
226                         }
227                         else if (bt->str[0] == 'S') {
228                                 ui_but_value_set(bt, hsv[1]);
229                         }
230                         else if (bt->str[0] == 'V') {
231                                 ui_but_value_set(bt, hsv[2]);
232                         }
233                         else if (bt->str[0] == 'L') {
234                                 ui_but_value_set(bt, hsv[2]);
235                         }
236                 }
237
238                 ui_but_update(bt);
239         }
240 }
241
242 static void ui_colorpicker_rna_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg))
243 {
244         uiBut *but = (uiBut *)bt1;
245         uiPopupBlockHandle *popup = but->block->handle;
246         PropertyRNA *prop = but->rnaprop;
247         PointerRNA ptr = but->rnapoin;
248         float rgb[4];
249
250         if (prop) {
251                 RNA_property_float_get_array(&ptr, prop, rgb);
252                 ui_update_color_picker_buts_rgb(
253                         but, but->block, but->custom_data, rgb);
254         }
255
256         if (popup)
257                 popup->menuretval = UI_RETURN_UPDATE;
258 }
259
260 static void ui_color_wheel_rna_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg))
261 {
262         uiBut *but = (uiBut *)bt1;
263         uiPopupBlockHandle *popup = but->block->handle;
264         float rgb[3];
265         ColorPicker *cpicker = but->custom_data;
266         float *hsv = cpicker->color_data;
267
268         ui_color_picker_to_rgb_v(hsv, rgb);
269
270         /* hsv is saved in perceptually linear space so convert back */
271         ui_color_picker_to_scene_linear_space(but, rgb);
272
273         ui_update_color_picker_buts_rgb(but, but->block, cpicker, rgb);
274
275         if (popup)
276                 popup->menuretval = UI_RETURN_UPDATE;
277 }
278
279 static void ui_colorpicker_hex_rna_cb(bContext *UNUSED(C), void *bt1, void *hexcl)
280 {
281         uiBut *but = (uiBut *)bt1;
282         uiPopupBlockHandle *popup = but->block->handle;
283         ColorPicker *cpicker = but->custom_data;
284         char *hexcol = (char *)hexcl;
285         float rgb[3];
286
287         hex_to_rgb(hexcol, rgb, rgb + 1, rgb + 2);
288
289         /* Hex code is assumed to be in sRGB space (coming from other applications, web, etc) */
290         if (!but->block->is_color_gamma_picker) {
291                 /* so we need to linearise it for Blender */
292                 ui_block_cm_to_scene_linear_v3(but->block, rgb);
293         }
294
295         ui_update_color_picker_buts_rgb(NULL, but->block, cpicker, rgb);
296
297         if (popup)
298                 popup->menuretval = UI_RETURN_UPDATE;
299 }
300
301 static void ui_popup_close_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg))
302 {
303         uiBut *but = (uiBut *)bt1;
304         uiPopupBlockHandle *popup = but->block->handle;
305
306         if (popup)
307                 popup->menuretval = UI_RETURN_OK;
308 }
309
310 static void ui_colorpicker_hide_reveal(uiBlock *block, short colormode)
311 {
312         uiBut *bt;
313
314         /* tag buttons */
315         for (bt = block->buttons.first; bt; bt = bt->next) {
316                 if ((bt->func == ui_colorpicker_rna_cb) && bt->type == UI_BTYPE_NUM_SLIDER && bt->rnaindex != 3) {
317                         /* RGB sliders (color circle and alpha are always shown) */
318                         if (colormode == 0) bt->flag &= ~UI_HIDDEN;
319                         else bt->flag |= UI_HIDDEN;
320                 }
321                 else if (bt->func == ui_color_wheel_rna_cb) {
322                         /* HSV sliders */
323                         if (colormode == 1) bt->flag &= ~UI_HIDDEN;
324                         else bt->flag |= UI_HIDDEN;
325                 }
326                 else if (bt->func == ui_colorpicker_hex_rna_cb || bt->type == UI_BTYPE_LABEL) {
327                         /* hex input or gamma correction status label */
328                         if (colormode == 2) bt->flag &= ~UI_HIDDEN;
329                         else bt->flag |= UI_HIDDEN;
330                 }
331         }
332 }
333
334 static void ui_colorpicker_create_mode_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg))
335 {
336         uiBut *bt = bt1;
337         short colormode = ui_but_value_get(bt);
338         ui_colorpicker_hide_reveal(bt->block, colormode);
339 }
340
341 #define PICKER_H    (7.5f * U.widget_unit)
342 #define PICKER_W    (7.5f * U.widget_unit)
343 #define PICKER_SPACE    (0.3f * U.widget_unit)
344 #define PICKER_BAR      (0.7f * U.widget_unit)
345
346 #define PICKER_TOTAL_W  (PICKER_W + PICKER_SPACE + PICKER_BAR)
347
348 static void ui_colorpicker_circle(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, ColorPicker *cpicker)
349 {
350         uiBut *bt;
351
352         /* HS circle */
353         bt = uiDefButR_prop(
354                 block, UI_BTYPE_HSVCIRCLE, 0, "", 0, 0, PICKER_H, PICKER_W,
355                 ptr, prop, -1, 0.0, 0.0, 0.0, 0, TIP_("Color"));
356         UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
357         bt->custom_data = cpicker;
358
359         /* value */
360         if (U.color_picker_type == USER_CP_CIRCLE_HSL) {
361                 bt = uiDefButR_prop(
362                         block, UI_BTYPE_HSVCUBE, 0, "", PICKER_W + PICKER_SPACE, 0, PICKER_BAR, PICKER_H,
363                         ptr, prop, -1, 0.0, 0.0, UI_GRAD_L_ALT, 0, "Lightness");
364                 UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
365         }
366         else {
367                 bt = uiDefButR_prop(
368                         block, UI_BTYPE_HSVCUBE, 0, "", PICKER_W + PICKER_SPACE, 0, PICKER_BAR, PICKER_H,
369                         ptr, prop, -1, 0.0, 0.0, UI_GRAD_V_ALT, 0, TIP_("Value"));
370                 UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
371         }
372         bt->custom_data = cpicker;
373 }
374
375
376 static void ui_colorpicker_square(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int type, ColorPicker *cpicker)
377 {
378         uiBut *bt;
379         int bartype = type + 3;
380
381         /* HS square */
382         bt = uiDefButR_prop(
383                 block, UI_BTYPE_HSVCUBE, 0, "",   0, PICKER_BAR + PICKER_SPACE, PICKER_TOTAL_W, PICKER_H,
384                 ptr, prop, -1, 0.0, 0.0, type, 0, TIP_("Color"));
385         UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
386         bt->custom_data = cpicker;
387
388         /* value */
389         bt = uiDefButR_prop(
390                 block, UI_BTYPE_HSVCUBE, 0, "",       0, 0, PICKER_TOTAL_W, PICKER_BAR,
391                 ptr, prop, -1, 0.0, 0.0, bartype, 0, TIP_("Value"));
392         UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
393         bt->custom_data = cpicker;
394 }
395
396 /* a HS circle, V slider, rgb/hsv/hex sliders */
397 static void ui_block_colorpicker(
398         uiBlock *block, uiBut *from_but, float rgba[4], bool show_picker)
399 {
400         static short colormode = 0;  /* temp? 0=rgb, 1=hsv, 2=hex */
401         uiBut *bt;
402         int width, butwidth;
403         static char hexcol[128];
404         float softmin, softmax, hardmin, hardmax, step, precision;
405         int yco;
406         ColorPicker *cpicker = ui_block_colorpicker_create(block);
407         float *hsv = cpicker->color_data;
408         PointerRNA *ptr = &from_but->rnapoin;
409         PropertyRNA *prop = from_but->rnaprop;
410
411         width = PICKER_TOTAL_W;
412         butwidth = width - 1.5f * UI_UNIT_X;
413
414         /* sneaky way to check for alpha */
415         rgba[3] = FLT_MAX;
416
417         RNA_property_float_ui_range(ptr, prop, &softmin, &softmax, &step, &precision);
418         RNA_property_float_range(ptr, prop, &hardmin, &hardmax);
419         RNA_property_float_get_array(ptr, prop, rgba);
420
421         float rgb_perceptual[3];
422         copy_v3_v3(rgb_perceptual, rgba);
423         ui_scene_linear_to_color_picker_space(from_but, rgb_perceptual);
424         ui_rgb_to_color_picker_v(rgb_perceptual, hsv);
425
426         /* when the softmax isn't defined in the RNA,
427          * using very large numbers causes sRGB/linear round trip to fail. */
428         if (softmax == FLT_MAX) {
429                 softmax = 1.0f;
430         }
431
432         switch (U.color_picker_type) {
433                 case USER_CP_SQUARE_SV:
434                         ui_colorpicker_square(block, ptr, prop, UI_GRAD_SV, cpicker);
435                         break;
436                 case USER_CP_SQUARE_HS:
437                         ui_colorpicker_square(block, ptr, prop, UI_GRAD_HS, cpicker);
438                         break;
439                 case USER_CP_SQUARE_HV:
440                         ui_colorpicker_square(block, ptr, prop, UI_GRAD_HV, cpicker);
441                         break;
442
443                 /* user default */
444                 case USER_CP_CIRCLE_HSV:
445                 case USER_CP_CIRCLE_HSL:
446                 default:
447                         ui_colorpicker_circle(block, ptr, prop, cpicker);
448                         break;
449         }
450
451         /* mode */
452         yco = -1.5f * UI_UNIT_Y;
453         UI_block_align_begin(block);
454         bt = uiDefButS(
455                 block, UI_BTYPE_ROW, 0, IFACE_("RGB"), 0, yco, width / 3, UI_UNIT_Y,
456                 &colormode, 0.0, 0.0, 0, 0, "");
457         UI_but_func_set(bt, ui_colorpicker_create_mode_cb, bt, NULL);
458         bt->custom_data = cpicker;
459         if (U.color_picker_type == USER_CP_CIRCLE_HSL) {
460                 bt = uiDefButS(
461                         block, UI_BTYPE_ROW, 0, IFACE_("HSL"), width / 3, yco, width / 3, UI_UNIT_Y,
462                         &colormode, 0.0, 1.0, 0, 0, "");
463         }
464         else {
465                 bt = uiDefButS(
466                         block, UI_BTYPE_ROW, 0, IFACE_("HSV"), width / 3, yco, width / 3, UI_UNIT_Y,
467                         &colormode, 0.0, 1.0, 0, 0, "");
468         }
469         UI_but_func_set(bt, ui_colorpicker_create_mode_cb, bt, NULL);
470         bt->custom_data = cpicker;
471         bt = uiDefButS(
472                 block, UI_BTYPE_ROW, 0, IFACE_("Hex"), 2 * width / 3, yco, width / 3, UI_UNIT_Y,
473                 &colormode, 0.0, 2.0, 0, 0, "");
474         UI_but_func_set(bt, ui_colorpicker_create_mode_cb, bt, NULL);
475         bt->custom_data = cpicker;
476         UI_block_align_end(block);
477
478         yco = -3.0f * UI_UNIT_Y;
479         if (show_picker) {
480                 bt = uiDefIconButO(
481                         block, UI_BTYPE_BUT, "UI_OT_eyedropper_color", WM_OP_INVOKE_DEFAULT, ICON_EYEDROPPER,
482                         butwidth + 10, yco, UI_UNIT_X, UI_UNIT_Y, NULL);
483                 UI_but_func_set(bt, ui_popup_close_cb, bt, NULL);
484                 bt->custom_data = cpicker;
485         }
486
487         /* RGB values */
488         UI_block_align_begin(block);
489         bt = uiDefButR_prop(
490                 block, UI_BTYPE_NUM_SLIDER, 0, IFACE_("R:"),  0, yco, butwidth, UI_UNIT_Y,
491                 ptr, prop, 0, 0.0, 0.0, 0, 3, TIP_("Red"));
492         UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
493         bt->custom_data = cpicker;
494         bt = uiDefButR_prop(
495                 block, UI_BTYPE_NUM_SLIDER, 0, IFACE_("G:"),  0, yco -= UI_UNIT_Y, butwidth, UI_UNIT_Y,
496                 ptr, prop, 1, 0.0, 0.0, 0, 3, TIP_("Green"));
497         UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
498         bt->custom_data = cpicker;
499         bt = uiDefButR_prop(
500                 block, UI_BTYPE_NUM_SLIDER, 0, IFACE_("B:"),  0, yco -= UI_UNIT_Y, butwidth, UI_UNIT_Y,
501                 ptr, prop, 2, 0.0, 0.0, 0, 3, TIP_("Blue"));
502         UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
503         bt->custom_data = cpicker;
504
505         /* could use uiItemFullR(col, ptr, prop, -1, 0, UI_ITEM_R_EXPAND|UI_ITEM_R_SLIDER, "", ICON_NONE);
506          * but need to use UI_but_func_set for updating other fake buttons */
507
508         /* HSV values */
509         yco = -3.0f * UI_UNIT_Y;
510         UI_block_align_begin(block);
511         bt = uiDefButF(
512                 block, UI_BTYPE_NUM_SLIDER, 0, IFACE_("H:"),   0, yco, butwidth,
513                 UI_UNIT_Y, hsv, 0.0, 1.0, 10, 3, TIP_("Hue"));
514         UI_but_func_set(bt, ui_color_wheel_rna_cb, bt, hsv);
515         bt->custom_data = cpicker;
516         bt = uiDefButF(
517                 block, UI_BTYPE_NUM_SLIDER, 0, IFACE_("S:"),   0, yco -= UI_UNIT_Y,
518                 butwidth, UI_UNIT_Y, hsv + 1, 0.0, 1.0, 10, 3, TIP_("Saturation"));
519         UI_but_func_set(bt, ui_color_wheel_rna_cb, bt, hsv);
520         bt->custom_data = cpicker;
521         if (U.color_picker_type == USER_CP_CIRCLE_HSL) {
522                 bt = uiDefButF(
523                         block, UI_BTYPE_NUM_SLIDER, 0, IFACE_("L:"),   0, yco -= UI_UNIT_Y,
524                         butwidth, UI_UNIT_Y, hsv + 2, 0.0, 1.0, 10, 3, TIP_("Lightness"));
525         }
526         else {
527                 bt = uiDefButF(
528                         block, UI_BTYPE_NUM_SLIDER, 0, IFACE_("V:"),   0, yco -= UI_UNIT_Y, butwidth, UI_UNIT_Y,
529                         hsv + 2, 0.0, softmax, 10, 3, TIP_("Value"));
530         }
531
532         bt->hardmax = hardmax;  /* not common but rgb  may be over 1.0 */
533         UI_but_func_set(bt, ui_color_wheel_rna_cb, bt, hsv);
534         bt->custom_data = cpicker;
535
536         UI_block_align_end(block);
537
538         if (rgba[3] != FLT_MAX) {
539                 bt = uiDefButR_prop(
540                         block, UI_BTYPE_NUM_SLIDER, 0, IFACE_("A: "),  0, yco -= UI_UNIT_Y, butwidth, UI_UNIT_Y,
541                         ptr, prop, 3, 0.0, 0.0, 0, 3, TIP_("Alpha"));
542                 UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
543                 bt->custom_data = cpicker;
544         }
545         else {
546                 rgba[3] = 1.0f;
547         }
548
549         /* Hex color is in display space. This should actually be sRGB without any view
550          * transform, as most other applications would expect this. */
551         float rgb_gamma[3];
552         unsigned char rgb_gamma_uchar[3];
553
554         if (block->is_color_gamma_picker) {
555                 copy_v3_v3(rgb_gamma, rgba);
556         }
557         else {
558                 copy_v3_v3(rgb_gamma, rgba);
559                 ui_block_cm_to_display_space_v3(block, rgb_gamma);
560         }
561
562         rgb_float_to_uchar(rgb_gamma_uchar, rgb_gamma);
563         BLI_snprintf(hexcol, sizeof(hexcol), "%02X%02X%02X", UNPACK3_EX((uint), rgb_gamma_uchar, ));
564
565         yco = -3.0f * UI_UNIT_Y;
566         bt = uiDefBut(
567                 block, UI_BTYPE_TEXT, 0, IFACE_("Hex: "), 0, yco, butwidth, UI_UNIT_Y,
568                 hexcol, 0, 8, 0, 0, TIP_("Hex triplet for color (#RRGGBB)"));
569         UI_but_func_set(bt, ui_colorpicker_hex_rna_cb, bt, hexcol);
570         bt->custom_data = cpicker;
571         uiDefBut(
572                 block, UI_BTYPE_LABEL, 0, IFACE_("(Gamma Corrected)"), 0, yco - UI_UNIT_Y,
573                 butwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
574
575         ui_colorpicker_hide_reveal(block, colormode);
576 }
577
578
579 static int ui_colorpicker_small_wheel_cb(const bContext *UNUSED(C), uiBlock *block, const wmEvent *event)
580 {
581         float add = 0.0f;
582
583         if (event->type == WHEELUPMOUSE)
584                 add = 0.05f;
585         else if (event->type == WHEELDOWNMOUSE)
586                 add = -0.05f;
587
588         if (add != 0.0f) {
589                 uiBut *but;
590
591                 for (but = block->buttons.first; but; but = but->next) {
592                         if (but->type == UI_BTYPE_HSVCUBE && but->active == NULL) {
593                                 uiPopupBlockHandle *popup = block->handle;
594                                 float rgb[3];
595                                 ColorPicker *cpicker = but->custom_data;
596                                 float *hsv = cpicker->color_data;
597
598                                 ui_but_v3_get(but, rgb);
599                                 ui_scene_linear_to_color_picker_space(but, rgb);
600                                 ui_rgb_to_color_picker_compat_v(rgb, hsv);
601
602                                 hsv[2] = clamp_f(hsv[2] + add, 0.0f, 1.0f);
603
604                                 ui_color_picker_to_rgb_v(hsv, rgb);
605                                 ui_color_picker_to_scene_linear_space(but, rgb);
606                                 ui_but_v3_set(but, rgb);
607
608                                 ui_update_color_picker_buts_rgb(but, block, cpicker, rgb);
609                                 if (popup)
610                                         popup->menuretval = UI_RETURN_UPDATE;
611
612                                 return 1;
613                         }
614                 }
615         }
616         return 0;
617 }
618
619 uiBlock *ui_block_func_COLOR(bContext *C, uiPopupBlockHandle *handle, void *arg_but)
620 {
621         uiBut *but = arg_but;
622         uiBlock *block;
623         bool show_picker = true;
624
625         block = UI_block_begin(C, handle->region, __func__, UI_EMBOSS);
626
627         if (ui_but_is_color_gamma(but)) {
628                 block->is_color_gamma_picker = true;
629         }
630
631         if (but->block) {
632                 /* if color block is invoked from a popup we wouldn't be able to set color properly
633                  * this is because color picker will close popups first and then will try to figure
634                  * out active button RNA, and of course it'll fail
635                  */
636                 show_picker = (but->block->flag & UI_BLOCK_POPUP) == 0;
637         }
638
639         copy_v3_v3(handle->retvec, but->editvec);
640
641         ui_block_colorpicker(block, but, handle->retvec, show_picker);
642
643         block->flag = UI_BLOCK_LOOP | UI_BLOCK_KEEP_OPEN | UI_BLOCK_OUT_1 | UI_BLOCK_MOVEMOUSE_QUIT;
644         UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
645         UI_block_bounds_set_normal(block, 0.5 * UI_UNIT_X);
646
647         block->block_event_func = ui_colorpicker_small_wheel_cb;
648
649         /* and lets go */
650         block->direction = UI_DIR_UP;
651
652         return block;
653 }
654
655 ColorPicker *ui_block_colorpicker_create(struct uiBlock *block)
656 {
657         ColorPicker *cpicker = MEM_callocN(sizeof(ColorPicker), "color_picker");
658         BLI_addhead(&block->color_pickers.list, cpicker);
659
660         return cpicker;
661 }
662
663 /** \} */