Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / interface / interface_eyedropper_color.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) 2009 Blender Foundation.
19  * All rights reserved.
20  *
21  * ***** END GPL LICENSE BLOCK *****
22  */
23
24 /** \file blender/editors/interface/interface_eyedropper_color.c
25  *  \ingroup edinterface
26  *
27  * Eyedropper (RGB Color)
28  *
29  * Defines:
30  * - #UI_OT_eyedropper_color
31  */
32
33 #include "MEM_guardedalloc.h"
34
35 #include "DNA_space_types.h"
36 #include "DNA_screen_types.h"
37
38 #include "BLI_math_vector.h"
39
40 #include "BKE_context.h"
41 #include "BKE_main.h"
42 #include "BKE_screen.h"
43
44 #include "RNA_access.h"
45
46 #include "BIF_gl.h"
47
48 #include "UI_interface.h"
49
50 #include "IMB_colormanagement.h"
51
52 #include "WM_api.h"
53 #include "WM_types.h"
54
55 #include "interface_intern.h"
56
57 #include "ED_image.h"
58 #include "ED_node.h"
59 #include "ED_clip.h"
60
61 #include "interface_eyedropper_intern.h"
62
63 typedef struct Eyedropper {
64         struct ColorManagedDisplay *display;
65
66         PointerRNA ptr;
67         PropertyRNA *prop;
68         int index;
69
70         float init_col[3]; /* for resetting on cancel */
71
72         bool  accum_start; /* has mouse been pressed */
73         float accum_col[3];
74         int   accum_tot;
75 } Eyedropper;
76
77 static bool eyedropper_init(bContext *C, wmOperator *op)
78 {
79         Scene *scene = CTX_data_scene(C);
80         Eyedropper *eye;
81
82         op->customdata = eye = MEM_callocN(sizeof(Eyedropper), "Eyedropper");
83
84         UI_context_active_but_prop_get(C, &eye->ptr, &eye->prop, &eye->index);
85
86         if ((eye->ptr.data == NULL) ||
87             (eye->prop == NULL) ||
88             (RNA_property_editable(&eye->ptr, eye->prop) == false) ||
89             (RNA_property_array_length(&eye->ptr, eye->prop) < 3) ||
90             (RNA_property_type(eye->prop) != PROP_FLOAT))
91         {
92                 return false;
93         }
94
95         if (RNA_property_subtype(eye->prop) != PROP_COLOR) {
96                 const char *display_device;
97                 float col[4];
98
99                 display_device = scene->display_settings.display_device;
100                 eye->display = IMB_colormanagement_display_get_named(display_device);
101
102                 /* store inital color */
103                 RNA_property_float_get_array(&eye->ptr, eye->prop, col);
104                 if (eye->display) {
105                         IMB_colormanagement_display_to_scene_linear_v3(col, eye->display);
106                 }
107                 copy_v3_v3(eye->init_col, col);
108         }
109
110         return true;
111 }
112
113 static void eyedropper_exit(bContext *C, wmOperator *op)
114 {
115         WM_cursor_modal_restore(CTX_wm_window(C));
116
117         if (op->customdata) {
118                 MEM_freeN(op->customdata);
119                 op->customdata = NULL;
120         }
121 }
122
123 /* *** eyedropper_color_ helper functions *** */
124
125 /**
126  * \brief get the color from the screen.
127  *
128  * Special check for image or nodes where we MAY have HDR pixels which don't display.
129  *
130  * \note Exposed by 'interface_eyedropper_intern.h' for use with color band picking.
131  */
132 void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3])
133 {
134         /* we could use some clever */
135         Main *bmain = CTX_data_main(C);
136         bScreen *screen = CTX_wm_screen(C);
137         ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
138         const char *display_device = CTX_data_scene(C)->display_settings.display_device;
139         struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
140
141         if (sa) {
142                 if (sa->spacetype == SPACE_IMAGE) {
143                         ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
144                         if (ar) {
145                                 SpaceImage *sima = sa->spacedata.first;
146                                 int mval[2] = {mx - ar->winrct.xmin,
147                                                my - ar->winrct.ymin};
148
149                                 if (ED_space_image_color_sample(sima, ar, mval, r_col)) {
150                                         return;
151                                 }
152                         }
153                 }
154                 else if (sa->spacetype == SPACE_NODE) {
155                         ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
156                         if (ar) {
157                                 SpaceNode *snode = sa->spacedata.first;
158                                 int mval[2] = {mx - ar->winrct.xmin,
159                                                my - ar->winrct.ymin};
160
161                                 if (ED_space_node_color_sample(bmain, snode, ar, mval, r_col)) {
162                                         return;
163                                 }
164                         }
165                 }
166                 else if (sa->spacetype == SPACE_CLIP) {
167                         ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
168                         if (ar) {
169                                 SpaceClip *sc = sa->spacedata.first;
170                                 int mval[2] = {mx - ar->winrct.xmin,
171                                                my - ar->winrct.ymin};
172
173                                 if (ED_space_clip_color_sample(sc, ar, mval, r_col)) {
174                                         return;
175                                 }
176                         }
177                 }
178         }
179
180         /* fallback to simple opengl picker */
181         glReadBuffer(GL_FRONT);
182         glReadPixels(mx, my, 1, 1, GL_RGB, GL_FLOAT, r_col);
183         glReadBuffer(GL_BACK);
184
185         IMB_colormanagement_display_to_scene_linear_v3(r_col, display);
186 }
187
188 /* sets the sample color RGB, maintaining A */
189 static void eyedropper_color_set(bContext *C, Eyedropper *eye, const float col[3])
190 {
191         float col_conv[4];
192
193         /* to maintain alpha */
194         RNA_property_float_get_array(&eye->ptr, eye->prop, col_conv);
195
196         /* convert from linear rgb space to display space */
197         if (eye->display) {
198                 copy_v3_v3(col_conv, col);
199                 IMB_colormanagement_scene_linear_to_display_v3(col_conv, eye->display);
200         }
201         else {
202                 copy_v3_v3(col_conv, col);
203         }
204
205         RNA_property_float_set_array(&eye->ptr, eye->prop, col_conv);
206
207         RNA_property_update(C, &eye->ptr, eye->prop);
208 }
209
210 /* set sample from accumulated values */
211 static void eyedropper_color_set_accum(bContext *C, Eyedropper *eye)
212 {
213         float col[3];
214         mul_v3_v3fl(col, eye->accum_col, 1.0f / (float)eye->accum_tot);
215         eyedropper_color_set(C, eye, col);
216 }
217
218 /* single point sample & set */
219 static void eyedropper_color_sample(bContext *C, Eyedropper *eye, int mx, int my)
220 {
221         float col[3];
222         eyedropper_color_sample_fl(C, mx, my, col);
223         eyedropper_color_set(C, eye, col);
224 }
225
226 static void eyedropper_color_sample_accum(bContext *C, Eyedropper *eye, int mx, int my)
227 {
228         float col[3];
229         eyedropper_color_sample_fl(C, mx, my, col);
230         /* delay linear conversion */
231         add_v3_v3(eye->accum_col, col);
232         eye->accum_tot++;
233 }
234
235 static void eyedropper_cancel(bContext *C, wmOperator *op)
236 {
237         Eyedropper *eye = op->customdata;
238         eyedropper_color_set(C, eye, eye->init_col);
239         eyedropper_exit(C, op);
240 }
241
242 /* main modal status check */
243 static int eyedropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
244 {
245         Eyedropper *eye = (Eyedropper *)op->customdata;
246
247         /* handle modal keymap */
248         if (event->type == EVT_MODAL_MAP) {
249                 switch (event->val) {
250                         case EYE_MODAL_CANCEL:
251                                 eyedropper_cancel(C, op);
252                                 return OPERATOR_CANCELLED;
253                         case EYE_MODAL_SAMPLE_CONFIRM:
254                                 if (eye->accum_tot == 0) {
255                                         eyedropper_color_sample(C, eye, event->x, event->y);
256                                 }
257                                 else {
258                                         eyedropper_color_set_accum(C, eye);
259                                 }
260                                 eyedropper_exit(C, op);
261                                 return OPERATOR_FINISHED;
262                         case EYE_MODAL_SAMPLE_BEGIN:
263                                 /* enable accum and make first sample */
264                                 eye->accum_start = true;
265                                 eyedropper_color_sample_accum(C, eye, event->x, event->y);
266                                 break;
267                         case EYE_MODAL_SAMPLE_RESET:
268                                 eye->accum_tot = 0;
269                                 zero_v3(eye->accum_col);
270                                 eyedropper_color_sample_accum(C, eye, event->x, event->y);
271                                 eyedropper_color_set_accum(C, eye);
272                                 break;
273                 }
274         }
275         else if (event->type == MOUSEMOVE) {
276                 if (eye->accum_start) {
277                         /* button is pressed so keep sampling */
278                         eyedropper_color_sample_accum(C, eye, event->x, event->y);
279                         eyedropper_color_set_accum(C, eye);
280                 }
281         }
282
283         return OPERATOR_RUNNING_MODAL;
284 }
285
286 /* Modal Operator init */
287 static int eyedropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
288 {
289         /* init */
290         if (eyedropper_init(C, op)) {
291                 WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
292
293                 /* add temp handler */
294                 WM_event_add_modal_handler(C, op);
295
296                 return OPERATOR_RUNNING_MODAL;
297         }
298         else {
299                 eyedropper_exit(C, op);
300                 return OPERATOR_CANCELLED;
301         }
302 }
303
304 /* Repeat operator */
305 static int eyedropper_exec(bContext *C, wmOperator *op)
306 {
307         /* init */
308         if (eyedropper_init(C, op)) {
309
310                 /* do something */
311
312                 /* cleanup */
313                 eyedropper_exit(C, op);
314
315                 return OPERATOR_FINISHED;
316         }
317         else {
318                 return OPERATOR_CANCELLED;
319         }
320 }
321
322 static int eyedropper_poll(bContext *C)
323 {
324         PointerRNA ptr;
325         PropertyRNA *prop;
326         int index_dummy;
327         uiBut *but;
328
329         /* Only color buttons */
330         if ((CTX_wm_window(C) != NULL) &&
331             (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
332             (but->type == UI_BTYPE_COLOR))
333         {
334                 return 1;
335         }
336
337         return 0;
338 }
339
340 void UI_OT_eyedropper_color(wmOperatorType *ot)
341 {
342         /* identifiers */
343         ot->name = "Eyedropper";
344         ot->idname = "UI_OT_eyedropper_color";
345         ot->description = "Sample a color from the Blender Window to store in a property";
346
347         /* api callbacks */
348         ot->invoke = eyedropper_invoke;
349         ot->modal = eyedropper_modal;
350         ot->cancel = eyedropper_cancel;
351         ot->exec = eyedropper_exec;
352         ot->poll = eyedropper_poll;
353
354         /* flags */
355         ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
356
357         /* properties */
358 }