Cleanup: use typed unsigned ints
[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_hex[3];
192                         uchar rgb_hex_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                         copy_v3_v3(rgb_hex, rgb);
198                         if (from_but && !ui_but_is_color_gamma(from_but)) {
199                                 IMB_colormanagement_scene_linear_to_srgb_v3(rgb_hex);
200                         }
201
202                         if (rgb_hex[0] > 1.0f) rgb_hex[0] = modf(rgb_hex[0], &intpart);
203                         if (rgb_hex[1] > 1.0f) rgb_hex[1] = modf(rgb_hex[1], &intpart);
204                         if (rgb_hex[2] > 1.0f) rgb_hex[2] = modf(rgb_hex[2], &intpart);
205
206                         rgb_float_to_uchar(rgb_hex_uchar, rgb_hex);
207                         BLI_snprintf(col, sizeof(col), "%02X%02X%02X", UNPACK3_EX((uint), rgb_hex_uchar, ));
208
209                         strcpy(bt->poin, col);
210                 }
211                 else if (bt->str[1] == ' ') {
212                         if (bt->str[0] == 'R') {
213                                 ui_but_value_set(bt, rgb[0]);
214                         }
215                         else if (bt->str[0] == 'G') {
216                                 ui_but_value_set(bt, rgb[1]);
217                         }
218                         else if (bt->str[0] == 'B') {
219                                 ui_but_value_set(bt, rgb[2]);
220                         }
221                         else if (bt->str[0] == 'H') {
222                                 ui_but_value_set(bt, hsv[0]);
223                         }
224                         else if (bt->str[0] == 'S') {
225                                 ui_but_value_set(bt, hsv[1]);
226                         }
227                         else if (bt->str[0] == 'V') {
228                                 ui_but_value_set(bt, hsv[2]);
229                         }
230                         else if (bt->str[0] == 'L') {
231                                 ui_but_value_set(bt, hsv[2]);
232                         }
233                 }
234
235                 ui_but_update(bt);
236         }
237 }
238
239 static void ui_colorpicker_rna_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg))
240 {
241         uiBut *but = (uiBut *)bt1;
242         uiPopupBlockHandle *popup = but->block->handle;
243         PropertyRNA *prop = but->rnaprop;
244         PointerRNA ptr = but->rnapoin;
245         float rgb[4];
246
247         if (prop) {
248                 RNA_property_float_get_array(&ptr, prop, rgb);
249                 ui_update_color_picker_buts_rgb(
250                         but, but->block, but->custom_data, rgb);
251         }
252
253         if (popup)
254                 popup->menuretval = UI_RETURN_UPDATE;
255 }
256
257 static void ui_color_wheel_rna_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg))
258 {
259         uiBut *but = (uiBut *)bt1;
260         uiPopupBlockHandle *popup = but->block->handle;
261         float rgb[3];
262         ColorPicker *cpicker = but->custom_data;
263         float *hsv = cpicker->color_data;
264
265         ui_color_picker_to_rgb_v(hsv, rgb);
266
267         /* hsv is saved in perceptually linear space so convert back */
268         ui_color_picker_to_scene_linear_space(but, rgb);
269
270         ui_update_color_picker_buts_rgb(but, but->block, cpicker, rgb);
271
272         if (popup)
273                 popup->menuretval = UI_RETURN_UPDATE;
274 }
275
276 static void ui_colorpicker_hex_rna_cb(bContext *UNUSED(C), void *bt1, void *hexcl)
277 {
278         uiBut *but = (uiBut *)bt1;
279         uiPopupBlockHandle *popup = but->block->handle;
280         ColorPicker *cpicker = but->custom_data;
281         char *hexcol = (char *)hexcl;
282         float rgb[3];
283
284         hex_to_rgb(hexcol, rgb, rgb + 1, rgb + 2);
285
286         /* Hex code is assumed to be in sRGB space (coming from other applications, web, etc) */
287         if (!ui_but_is_color_gamma(but)) {
288                 IMB_colormanagement_srgb_to_scene_linear_v3(rgb);
289         }
290
291         ui_update_color_picker_buts_rgb(NULL, but->block, cpicker, rgb);
292
293         if (popup)
294                 popup->menuretval = UI_RETURN_UPDATE;
295 }
296
297 static void ui_popup_close_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg))
298 {
299         uiBut *but = (uiBut *)bt1;
300         uiPopupBlockHandle *popup = but->block->handle;
301
302         if (popup)
303                 popup->menuretval = UI_RETURN_OK;
304 }
305
306 static void ui_colorpicker_hide_reveal(uiBlock *block, short colormode)
307 {
308         uiBut *bt;
309
310         /* tag buttons */
311         for (bt = block->buttons.first; bt; bt = bt->next) {
312                 if ((bt->func == ui_colorpicker_rna_cb) && bt->type == UI_BTYPE_NUM_SLIDER && bt->rnaindex != 3) {
313                         /* RGB sliders (color circle and alpha are always shown) */
314                         if (colormode == 0) bt->flag &= ~UI_HIDDEN;
315                         else bt->flag |= UI_HIDDEN;
316                 }
317                 else if (bt->func == ui_color_wheel_rna_cb) {
318                         /* HSV sliders */
319                         if (colormode == 1) bt->flag &= ~UI_HIDDEN;
320                         else bt->flag |= UI_HIDDEN;
321                 }
322                 else if (bt->func == ui_colorpicker_hex_rna_cb || bt->type == UI_BTYPE_LABEL) {
323                         /* hex input or gamma correction status label */
324                         if (colormode == 2) bt->flag &= ~UI_HIDDEN;
325                         else bt->flag |= UI_HIDDEN;
326                 }
327         }
328 }
329
330 static void ui_colorpicker_create_mode_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg))
331 {
332         uiBut *bt = bt1;
333         short colormode = ui_but_value_get(bt);
334         ui_colorpicker_hide_reveal(bt->block, colormode);
335 }
336
337 #define PICKER_H    (7.5f * U.widget_unit)
338 #define PICKER_W    (7.5f * U.widget_unit)
339 #define PICKER_SPACE    (0.3f * U.widget_unit)
340 #define PICKER_BAR      (0.7f * U.widget_unit)
341
342 #define PICKER_TOTAL_W  (PICKER_W + PICKER_SPACE + PICKER_BAR)
343
344 static void ui_colorpicker_circle(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, ColorPicker *cpicker)
345 {
346         uiBut *bt;
347
348         /* HS circle */
349         bt = uiDefButR_prop(
350                 block, UI_BTYPE_HSVCIRCLE, 0, "", 0, 0, PICKER_H, PICKER_W,
351                 ptr, prop, -1, 0.0, 0.0, 0.0, 0, TIP_("Color"));
352         UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
353         bt->custom_data = cpicker;
354
355         /* value */
356         if (U.color_picker_type == USER_CP_CIRCLE_HSL) {
357                 bt = uiDefButR_prop(
358                         block, UI_BTYPE_HSVCUBE, 0, "", PICKER_W + PICKER_SPACE, 0, PICKER_BAR, PICKER_H,
359                         ptr, prop, -1, 0.0, 0.0, UI_GRAD_L_ALT, 0, "Lightness");
360                 UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
361         }
362         else {
363                 bt = uiDefButR_prop(
364                         block, UI_BTYPE_HSVCUBE, 0, "", PICKER_W + PICKER_SPACE, 0, PICKER_BAR, PICKER_H,
365                         ptr, prop, -1, 0.0, 0.0, UI_GRAD_V_ALT, 0, TIP_("Value"));
366                 UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
367         }
368         bt->custom_data = cpicker;
369 }
370
371
372 static void ui_colorpicker_square(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int type, ColorPicker *cpicker)
373 {
374         uiBut *bt;
375         int bartype = type + 3;
376
377         /* HS square */
378         bt = uiDefButR_prop(
379                 block, UI_BTYPE_HSVCUBE, 0, "",   0, PICKER_BAR + PICKER_SPACE, PICKER_TOTAL_W, PICKER_H,
380                 ptr, prop, -1, 0.0, 0.0, type, 0, TIP_("Color"));
381         UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
382         bt->custom_data = cpicker;
383
384         /* value */
385         bt = uiDefButR_prop(
386                 block, UI_BTYPE_HSVCUBE, 0, "",       0, 0, PICKER_TOTAL_W, PICKER_BAR,
387                 ptr, prop, -1, 0.0, 0.0, bartype, 0, TIP_("Value"));
388         UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
389         bt->custom_data = cpicker;
390 }
391
392 /* a HS circle, V slider, rgb/hsv/hex sliders */
393 static void ui_block_colorpicker(
394         uiBlock *block, uiBut *from_but, float rgba[4], bool show_picker)
395 {
396         static short colormode = 0;  /* temp? 0=rgb, 1=hsv, 2=hex */
397         uiBut *bt;
398         int width, butwidth;
399         static char hexcol[128];
400         float softmin, softmax, hardmin, hardmax, step, precision;
401         int yco;
402         ColorPicker *cpicker = ui_block_colorpicker_create(block);
403         float *hsv = cpicker->color_data;
404         PointerRNA *ptr = &from_but->rnapoin;
405         PropertyRNA *prop = from_but->rnaprop;
406
407         width = PICKER_TOTAL_W;
408         butwidth = width - 1.5f * UI_UNIT_X;
409
410         /* sneaky way to check for alpha */
411         rgba[3] = FLT_MAX;
412
413         RNA_property_float_ui_range(ptr, prop, &softmin, &softmax, &step, &precision);
414         RNA_property_float_range(ptr, prop, &hardmin, &hardmax);
415         RNA_property_float_get_array(ptr, prop, rgba);
416
417         float rgb_perceptual[3];
418         copy_v3_v3(rgb_perceptual, rgba);
419         ui_scene_linear_to_color_picker_space(from_but, rgb_perceptual);
420         ui_rgb_to_color_picker_v(rgb_perceptual, hsv);
421
422         /* when the softmax isn't defined in the RNA,
423          * using very large numbers causes sRGB/linear round trip to fail. */
424         if (softmax == FLT_MAX) {
425                 softmax = 1.0f;
426         }
427
428         switch (U.color_picker_type) {
429                 case USER_CP_SQUARE_SV:
430                         ui_colorpicker_square(block, ptr, prop, UI_GRAD_SV, cpicker);
431                         break;
432                 case USER_CP_SQUARE_HS:
433                         ui_colorpicker_square(block, ptr, prop, UI_GRAD_HS, cpicker);
434                         break;
435                 case USER_CP_SQUARE_HV:
436                         ui_colorpicker_square(block, ptr, prop, UI_GRAD_HV, cpicker);
437                         break;
438
439                 /* user default */
440                 case USER_CP_CIRCLE_HSV:
441                 case USER_CP_CIRCLE_HSL:
442                 default:
443                         ui_colorpicker_circle(block, ptr, prop, cpicker);
444                         break;
445         }
446
447         /* mode */
448         yco = -1.5f * UI_UNIT_Y;
449         UI_block_align_begin(block);
450         bt = uiDefButS(
451                 block, UI_BTYPE_ROW, 0, IFACE_("RGB"), 0, yco, width / 3, UI_UNIT_Y,
452                 &colormode, 0.0, 0.0, 0, 0, "");
453         UI_but_func_set(bt, ui_colorpicker_create_mode_cb, bt, NULL);
454         bt->custom_data = cpicker;
455         if (U.color_picker_type == USER_CP_CIRCLE_HSL) {
456                 bt = uiDefButS(
457                         block, UI_BTYPE_ROW, 0, IFACE_("HSL"), width / 3, yco, width / 3, UI_UNIT_Y,
458                         &colormode, 0.0, 1.0, 0, 0, "");
459         }
460         else {
461                 bt = uiDefButS(
462                         block, UI_BTYPE_ROW, 0, IFACE_("HSV"), width / 3, yco, width / 3, UI_UNIT_Y,
463                         &colormode, 0.0, 1.0, 0, 0, "");
464         }
465         UI_but_func_set(bt, ui_colorpicker_create_mode_cb, bt, NULL);
466         bt->custom_data = cpicker;
467         bt = uiDefButS(
468                 block, UI_BTYPE_ROW, 0, IFACE_("Hex"), 2 * width / 3, yco, width / 3, UI_UNIT_Y,
469                 &colormode, 0.0, 2.0, 0, 0, "");
470         UI_but_func_set(bt, ui_colorpicker_create_mode_cb, bt, NULL);
471         bt->custom_data = cpicker;
472         UI_block_align_end(block);
473
474         yco = -3.0f * UI_UNIT_Y;
475         if (show_picker) {
476                 bt = uiDefIconButO(
477                         block, UI_BTYPE_BUT, "UI_OT_eyedropper_color", WM_OP_INVOKE_DEFAULT, ICON_EYEDROPPER,
478                         butwidth + 10, yco, UI_UNIT_X, UI_UNIT_Y, NULL);
479                 UI_but_func_set(bt, ui_popup_close_cb, bt, NULL);
480                 bt->custom_data = cpicker;
481         }
482
483         /* RGB values */
484         UI_block_align_begin(block);
485         bt = uiDefButR_prop(
486                 block, UI_BTYPE_NUM_SLIDER, 0, IFACE_("R:"),  0, yco, butwidth, UI_UNIT_Y,
487                 ptr, prop, 0, 0.0, 0.0, 0, 3, TIP_("Red"));
488         UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
489         bt->custom_data = cpicker;
490         bt = uiDefButR_prop(
491                 block, UI_BTYPE_NUM_SLIDER, 0, IFACE_("G:"),  0, yco -= UI_UNIT_Y, butwidth, UI_UNIT_Y,
492                 ptr, prop, 1, 0.0, 0.0, 0, 3, TIP_("Green"));
493         UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
494         bt->custom_data = cpicker;
495         bt = uiDefButR_prop(
496                 block, UI_BTYPE_NUM_SLIDER, 0, IFACE_("B:"),  0, yco -= UI_UNIT_Y, butwidth, UI_UNIT_Y,
497                 ptr, prop, 2, 0.0, 0.0, 0, 3, TIP_("Blue"));
498         UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
499         bt->custom_data = cpicker;
500
501         /* could use uiItemFullR(col, ptr, prop, -1, 0, UI_ITEM_R_EXPAND|UI_ITEM_R_SLIDER, "", ICON_NONE);
502          * but need to use UI_but_func_set for updating other fake buttons */
503
504         /* HSV values */
505         yco = -3.0f * UI_UNIT_Y;
506         UI_block_align_begin(block);
507         bt = uiDefButF(
508                 block, UI_BTYPE_NUM_SLIDER, 0, IFACE_("H:"),   0, yco, butwidth,
509                 UI_UNIT_Y, hsv, 0.0, 1.0, 10, 3, TIP_("Hue"));
510         UI_but_func_set(bt, ui_color_wheel_rna_cb, bt, hsv);
511         bt->custom_data = cpicker;
512         bt = uiDefButF(
513                 block, UI_BTYPE_NUM_SLIDER, 0, IFACE_("S:"),   0, yco -= UI_UNIT_Y,
514                 butwidth, UI_UNIT_Y, hsv + 1, 0.0, 1.0, 10, 3, TIP_("Saturation"));
515         UI_but_func_set(bt, ui_color_wheel_rna_cb, bt, hsv);
516         bt->custom_data = cpicker;
517         if (U.color_picker_type == USER_CP_CIRCLE_HSL) {
518                 bt = uiDefButF(
519                         block, UI_BTYPE_NUM_SLIDER, 0, IFACE_("L:"),   0, yco -= UI_UNIT_Y,
520                         butwidth, UI_UNIT_Y, hsv + 2, 0.0, 1.0, 10, 3, TIP_("Lightness"));
521         }
522         else {
523                 bt = uiDefButF(
524                         block, UI_BTYPE_NUM_SLIDER, 0, IFACE_("V:"),   0, yco -= UI_UNIT_Y, butwidth, UI_UNIT_Y,
525                         hsv + 2, 0.0, softmax, 10, 3, TIP_("Value"));
526         }
527
528         bt->hardmax = hardmax;  /* not common but rgb  may be over 1.0 */
529         UI_but_func_set(bt, ui_color_wheel_rna_cb, bt, hsv);
530         bt->custom_data = cpicker;
531
532         UI_block_align_end(block);
533
534         if (rgba[3] != FLT_MAX) {
535                 bt = uiDefButR_prop(
536                         block, UI_BTYPE_NUM_SLIDER, 0, IFACE_("A: "),  0, yco -= UI_UNIT_Y, butwidth, UI_UNIT_Y,
537                         ptr, prop, 3, 0.0, 0.0, 0, 3, TIP_("Alpha"));
538                 UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL);
539                 bt->custom_data = cpicker;
540         }
541         else {
542                 rgba[3] = 1.0f;
543         }
544
545         /* Hex color is in sRGB space. */
546         float rgb_hex[3];
547         uchar rgb_hex_uchar[3];
548
549         copy_v3_v3(rgb_hex, rgba);
550
551         if (!ui_but_is_color_gamma(from_but)) {
552                 IMB_colormanagement_scene_linear_to_srgb_v3(rgb_hex);
553         }
554
555         rgb_float_to_uchar(rgb_hex_uchar, rgb_hex);
556         BLI_snprintf(hexcol, sizeof(hexcol), "%02X%02X%02X", UNPACK3_EX((uint), rgb_hex_uchar, ));
557
558         yco = -3.0f * UI_UNIT_Y;
559         bt = uiDefBut(
560                 block, UI_BTYPE_TEXT, 0, IFACE_("Hex: "), 0, yco, butwidth, UI_UNIT_Y,
561                 hexcol, 0, 8, 0, 0, TIP_("Hex triplet for color (#RRGGBB)"));
562         UI_but_func_set(bt, ui_colorpicker_hex_rna_cb, bt, hexcol);
563         bt->custom_data = cpicker;
564         uiDefBut(
565                 block, UI_BTYPE_LABEL, 0, IFACE_("(Gamma Corrected)"), 0, yco - UI_UNIT_Y,
566                 butwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
567
568         ui_colorpicker_hide_reveal(block, colormode);
569 }
570
571
572 static int ui_colorpicker_small_wheel_cb(const bContext *UNUSED(C), uiBlock *block, const wmEvent *event)
573 {
574         float add = 0.0f;
575
576         if (event->type == WHEELUPMOUSE)
577                 add = 0.05f;
578         else if (event->type == WHEELDOWNMOUSE)
579                 add = -0.05f;
580
581         if (add != 0.0f) {
582                 uiBut *but;
583
584                 for (but = block->buttons.first; but; but = but->next) {
585                         if (but->type == UI_BTYPE_HSVCUBE && but->active == NULL) {
586                                 uiPopupBlockHandle *popup = block->handle;
587                                 float rgb[3];
588                                 ColorPicker *cpicker = but->custom_data;
589                                 float *hsv = cpicker->color_data;
590
591                                 ui_but_v3_get(but, rgb);
592                                 ui_scene_linear_to_color_picker_space(but, rgb);
593                                 ui_rgb_to_color_picker_compat_v(rgb, hsv);
594
595                                 hsv[2] = clamp_f(hsv[2] + add, 0.0f, 1.0f);
596
597                                 ui_color_picker_to_rgb_v(hsv, rgb);
598                                 ui_color_picker_to_scene_linear_space(but, rgb);
599                                 ui_but_v3_set(but, rgb);
600
601                                 ui_update_color_picker_buts_rgb(but, block, cpicker, rgb);
602                                 if (popup)
603                                         popup->menuretval = UI_RETURN_UPDATE;
604
605                                 return 1;
606                         }
607                 }
608         }
609         return 0;
610 }
611
612 uiBlock *ui_block_func_COLOR(bContext *C, uiPopupBlockHandle *handle, void *arg_but)
613 {
614         uiBut *but = arg_but;
615         uiBlock *block;
616         bool show_picker = true;
617
618         block = UI_block_begin(C, handle->region, __func__, UI_EMBOSS);
619
620         if (ui_but_is_color_gamma(but)) {
621                 block->is_color_gamma_picker = true;
622         }
623
624         if (but->block) {
625                 /* if color block is invoked from a popup we wouldn't be able to set color properly
626                  * this is because color picker will close popups first and then will try to figure
627                  * out active button RNA, and of course it'll fail
628                  */
629                 show_picker = (but->block->flag & UI_BLOCK_POPUP) == 0;
630         }
631
632         copy_v3_v3(handle->retvec, but->editvec);
633
634         ui_block_colorpicker(block, but, handle->retvec, show_picker);
635
636         block->flag = UI_BLOCK_LOOP | UI_BLOCK_KEEP_OPEN | UI_BLOCK_OUT_1 | UI_BLOCK_MOVEMOUSE_QUIT;
637         UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
638         UI_block_bounds_set_normal(block, 0.5 * UI_UNIT_X);
639
640         block->block_event_func = ui_colorpicker_small_wheel_cb;
641
642         /* and lets go */
643         block->direction = UI_DIR_UP;
644
645         return block;
646 }
647
648 ColorPicker *ui_block_colorpicker_create(struct uiBlock *block)
649 {
650         ColorPicker *cpicker = MEM_callocN(sizeof(ColorPicker), "color_picker");
651         BLI_addhead(&block->color_pickers.list, cpicker);
652
653         return cpicker;
654 }
655
656 /** \} */