Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / interface / interface_eyedropper.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  * Contributor(s): Blender Foundation, Joshua Leung
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/editors/interface/interface_eyedropper.c
27  *  \ingroup edinterface
28  */
29
30 #include "MEM_guardedalloc.h"
31
32 #include "DNA_anim_types.h"
33 #include "DNA_space_types.h"
34 #include "DNA_screen_types.h"
35 #include "DNA_object_types.h"
36
37 #include "BLI_blenlib.h"
38 #include "BLI_math_vector.h"
39
40 #include "BLT_translation.h"
41
42 #include "BKE_context.h"
43 #include "BKE_screen.h"
44 #include "BKE_report.h"
45 #include "BKE_animsys.h"
46 #include "BKE_idcode.h"
47 #include "BKE_unit.h"
48
49 #include "DEG_depsgraph.h"
50 #include "DEG_depsgraph_build.h"
51
52 #include "RNA_access.h"
53 #include "RNA_define.h"
54
55 #include "BIF_gl.h"
56
57 #include "UI_interface.h"
58
59 #include "IMB_colormanagement.h"
60
61 #include "WM_api.h"
62 #include "WM_types.h"
63
64 #include "interface_intern.h"
65
66 /* for HDR color sampling */
67 #include "ED_image.h"
68 #include "ED_node.h"
69 #include "ED_clip.h"
70
71 /* for ID data eyedropper */
72 #include "ED_space_api.h"
73 #include "ED_screen.h"
74 #include "ED_view3d.h"
75
76 /* for Driver eyedropper */
77 #include "ED_keyframing.h"
78
79
80 /* -------------------------------------------------------------------- */
81 /* Keymap
82  */
83 /** \name Modal Keymap
84  * \{ */
85
86 enum {
87         EYE_MODAL_CANCEL = 1,
88         EYE_MODAL_SAMPLE_CONFIRM,
89         EYE_MODAL_SAMPLE_BEGIN,
90         EYE_MODAL_SAMPLE_RESET,
91 };
92
93 wmKeyMap *eyedropper_modal_keymap(wmKeyConfig *keyconf)
94 {
95         static const EnumPropertyItem modal_items[] = {
96                 {EYE_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
97                 {EYE_MODAL_SAMPLE_CONFIRM, "SAMPLE_CONFIRM", 0, "Confirm Sampling", ""},
98                 {EYE_MODAL_SAMPLE_BEGIN, "SAMPLE_BEGIN", 0, "Start Sampling", ""},
99                 {EYE_MODAL_SAMPLE_RESET, "SAMPLE_RESET", 0, "Reset Sampling", ""},
100                 {0, NULL, 0, NULL, NULL}
101         };
102
103         wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Eyedropper Modal Map");
104
105         /* this function is called for each spacetype, only needs to add map once */
106         if (keymap && keymap->modal_items)
107                 return NULL;
108
109         keymap = WM_modalkeymap_add(keyconf, "Eyedropper Modal Map", modal_items);
110
111         /* items for modal map */
112         WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, EYE_MODAL_CANCEL);
113         WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_ANY, 0, EYE_MODAL_CANCEL);
114         WM_modalkeymap_add_item(keymap, RETKEY, KM_RELEASE, KM_ANY, 0, EYE_MODAL_SAMPLE_CONFIRM);
115         WM_modalkeymap_add_item(keymap, PADENTER, KM_RELEASE, KM_ANY, 0, EYE_MODAL_SAMPLE_CONFIRM);
116         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, EYE_MODAL_SAMPLE_CONFIRM);
117         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, EYE_MODAL_SAMPLE_BEGIN);
118         WM_modalkeymap_add_item(keymap, SPACEKEY, KM_RELEASE, KM_ANY, 0, EYE_MODAL_SAMPLE_RESET);
119
120         /* assign to operators */
121         WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_color");
122         WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_id");
123         WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_depth");
124         WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_driver");
125
126         return keymap;
127 }
128
129 /** \} */
130
131
132 /* -------------------------------------------------------------------- */
133 /* Utility Functions
134  */
135 /** \name Generic Shared Functions
136  * \{ */
137
138 static void eyedropper_draw_cursor_text(const struct bContext *C, ARegion *ar, const char *name)
139 {
140         const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
141         wmWindow *win = CTX_wm_window(C);
142         int x = win->eventstate->x;
143         int y = win->eventstate->y;
144         const float col_fg[4] = {1.0f, 1.0f, 1.0f, 1.0f};
145         const float col_bg[4] = {0.0f, 0.0f, 0.0f, 0.2f};
146
147
148         if ((name[0] == '\0') ||
149             (BLI_rcti_isect_pt(&ar->winrct, x, y) == false))
150         {
151                 return;
152         }
153
154         x = x - ar->winrct.xmin;
155         y = y - ar->winrct.ymin;
156
157         y += U.widget_unit;
158
159         UI_fontstyle_draw_simple_backdrop(fstyle, x, y, name, col_fg, col_bg);
160 }
161
162
163 /**
164  * Utility to retrieve a button representing a RNA property that is currently under the cursor.
165  *
166  * This is to be used by any eyedroppers which fetch properties (e.g. UI_OT_eyedropper_driver).
167  * Especially during modal operations (e.g. as with the eyedroppers), context cannot be relied
168  * upon to provide this information, as it is not updated until the operator finishes.
169  *
170  * \return A button under the mouse which relates to some RNA Property, or NULL
171  */
172 static uiBut *eyedropper_get_property_button_under_mouse(bContext *C, const wmEvent *event)
173 {
174         bScreen *screen = CTX_wm_screen(C);
175         ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->x, event->y);
176         ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_ANY, event->x, event->y);
177         
178         uiBut *but = ui_but_find_mouse_over(ar, event);
179         
180         if (ELEM(NULL, but, but->rnapoin.data, but->rnaprop)) {
181                 return NULL;
182         }
183         else {
184                 return but;
185         }
186 }
187
188 /** \} */
189
190
191 /* -------------------------------------------------------------------- */
192 /* Eyedropper
193  */
194
195 /** \name Eyedropper (RGB Color)
196  * \{ */
197
198 typedef struct Eyedropper {
199         struct ColorManagedDisplay *display;
200
201         PointerRNA ptr;
202         PropertyRNA *prop;
203         int index;
204
205         float init_col[3]; /* for resetting on cancel */
206
207         bool  accum_start; /* has mouse been pressed */
208         float accum_col[3];
209         int   accum_tot;
210 } Eyedropper;
211
212 static bool eyedropper_init(bContext *C, wmOperator *op)
213 {
214         Scene *scene = CTX_data_scene(C);
215         Eyedropper *eye;
216
217         op->customdata = eye = MEM_callocN(sizeof(Eyedropper), "Eyedropper");
218
219         UI_context_active_but_prop_get(C, &eye->ptr, &eye->prop, &eye->index);
220
221         if ((eye->ptr.data == NULL) ||
222             (eye->prop == NULL) ||
223             (RNA_property_editable(&eye->ptr, eye->prop) == false) ||
224             (RNA_property_array_length(&eye->ptr, eye->prop) < 3) ||
225             (RNA_property_type(eye->prop) != PROP_FLOAT))
226         {
227                 return false;
228         }
229
230         if (RNA_property_subtype(eye->prop) != PROP_COLOR) {
231                 const char *display_device;
232                 float col[4];
233
234                 display_device = scene->display_settings.display_device;
235                 eye->display = IMB_colormanagement_display_get_named(display_device);
236
237                 /* store inital color */
238                 RNA_property_float_get_array(&eye->ptr, eye->prop, col);
239                 if (eye->display) {
240                         IMB_colormanagement_display_to_scene_linear_v3(col, eye->display);
241                 }
242                 copy_v3_v3(eye->init_col, col);
243         }
244
245         return true;
246 }
247
248 static void eyedropper_exit(bContext *C, wmOperator *op)
249 {
250         WM_cursor_modal_restore(CTX_wm_window(C));
251
252         if (op->customdata) {
253                 MEM_freeN(op->customdata);
254                 op->customdata = NULL;
255         }
256 }
257
258 /* *** eyedropper_color_ helper functions *** */
259
260 /**
261  * \brief get the color from the screen.
262  *
263  * Special check for image or nodes where we MAY have HDR pixels which don't display.
264  */
265 static void eyedropper_color_sample_fl(bContext *C, Eyedropper *UNUSED(eye), int mx, int my, float r_col[3])
266 {
267         /* we could use some clever */
268         bScreen *screen = CTX_wm_screen(C);
269         ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
270         const char *display_device = CTX_data_scene(C)->display_settings.display_device;
271         struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
272
273         if (sa) {
274                 if (sa->spacetype == SPACE_IMAGE) {
275                         ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
276                         if (ar) {
277                                 SpaceImage *sima = sa->spacedata.first;
278                                 int mval[2] = {mx - ar->winrct.xmin,
279                                                my - ar->winrct.ymin};
280
281                                 if (ED_space_image_color_sample(sima, ar, mval, r_col)) {
282                                         return;
283                                 }
284                         }
285                 }
286                 else if (sa->spacetype == SPACE_NODE) {
287                         ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
288                         if (ar) {
289                                 SpaceNode *snode = sa->spacedata.first;
290                                 int mval[2] = {mx - ar->winrct.xmin,
291                                                my - ar->winrct.ymin};
292
293                                 if (ED_space_node_color_sample(snode, ar, mval, r_col)) {
294                                         return;
295                                 }
296                         }
297                 }
298                 else if (sa->spacetype == SPACE_CLIP) {
299                         ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
300                         if (ar) {
301                                 SpaceClip *sc = sa->spacedata.first;
302                                 int mval[2] = {mx - ar->winrct.xmin,
303                                                my - ar->winrct.ymin};
304
305                                 if (ED_space_clip_color_sample(sc, ar, mval, r_col)) {
306                                         return;
307                                 }
308                         }
309                 }
310         }
311
312         /* fallback to simple opengl picker */
313         glReadBuffer(GL_FRONT);
314         glReadPixels(mx, my, 1, 1, GL_RGB, GL_FLOAT, r_col);
315         glReadBuffer(GL_BACK);
316         
317         IMB_colormanagement_display_to_scene_linear_v3(r_col, display);
318 }
319
320 /* sets the sample color RGB, maintaining A */
321 static void eyedropper_color_set(bContext *C, Eyedropper *eye, const float col[3])
322 {
323         float col_conv[4];
324
325         /* to maintain alpha */
326         RNA_property_float_get_array(&eye->ptr, eye->prop, col_conv);
327
328         /* convert from linear rgb space to display space */
329         if (eye->display) {
330                 copy_v3_v3(col_conv, col);
331                 IMB_colormanagement_scene_linear_to_display_v3(col_conv, eye->display);
332         }
333         else {
334                 copy_v3_v3(col_conv, col);
335         }
336
337         RNA_property_float_set_array(&eye->ptr, eye->prop, col_conv);
338
339         RNA_property_update(C, &eye->ptr, eye->prop);
340 }
341
342 /* set sample from accumulated values */
343 static void eyedropper_color_set_accum(bContext *C, Eyedropper *eye)
344 {
345         float col[3];
346         mul_v3_v3fl(col, eye->accum_col, 1.0f / (float)eye->accum_tot);
347         eyedropper_color_set(C, eye, col);
348 }
349
350 /* single point sample & set */
351 static void eyedropper_color_sample(bContext *C, Eyedropper *eye, int mx, int my)
352 {
353         float col[3];
354         eyedropper_color_sample_fl(C, eye, mx, my, col);
355         eyedropper_color_set(C, eye, col);
356 }
357
358 static void eyedropper_color_sample_accum(bContext *C, Eyedropper *eye, int mx, int my)
359 {
360         float col[3];
361         eyedropper_color_sample_fl(C, eye, mx, my, col);
362         /* delay linear conversion */
363         add_v3_v3(eye->accum_col, col);
364         eye->accum_tot++;
365 }
366
367 static void eyedropper_cancel(bContext *C, wmOperator *op)
368 {
369         Eyedropper *eye = op->customdata;
370         eyedropper_color_set(C, eye, eye->init_col);
371         eyedropper_exit(C, op);
372 }
373
374 /* main modal status check */
375 static int eyedropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
376 {
377         Eyedropper *eye = (Eyedropper *)op->customdata;
378
379         /* handle modal keymap */
380         if (event->type == EVT_MODAL_MAP) {
381                 switch (event->val) {
382                         case EYE_MODAL_CANCEL:
383                                 eyedropper_cancel(C, op);
384                                 return OPERATOR_CANCELLED;
385                         case EYE_MODAL_SAMPLE_CONFIRM:
386                                 if (eye->accum_tot == 0) {
387                                         eyedropper_color_sample(C, eye, event->x, event->y);
388                                 }
389                                 else {
390                                         eyedropper_color_set_accum(C, eye);
391                                 }
392                                 eyedropper_exit(C, op);
393                                 return OPERATOR_FINISHED;
394                         case EYE_MODAL_SAMPLE_BEGIN:
395                                 /* enable accum and make first sample */
396                                 eye->accum_start = true;
397                                 eyedropper_color_sample_accum(C, eye, event->x, event->y);
398                                 break;
399                         case EYE_MODAL_SAMPLE_RESET:
400                                 eye->accum_tot = 0;
401                                 zero_v3(eye->accum_col);
402                                 eyedropper_color_sample_accum(C, eye, event->x, event->y);
403                                 eyedropper_color_set_accum(C, eye);
404                                 break;
405                 }
406         }
407         else if (event->type == MOUSEMOVE) {
408                 if (eye->accum_start) {
409                         /* button is pressed so keep sampling */
410                         eyedropper_color_sample_accum(C, eye, event->x, event->y);
411                         eyedropper_color_set_accum(C, eye);
412                 }
413         }
414
415         return OPERATOR_RUNNING_MODAL;
416 }
417
418 /* Modal Operator init */
419 static int eyedropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
420 {
421         /* init */
422         if (eyedropper_init(C, op)) {
423                 WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
424
425                 /* add temp handler */
426                 WM_event_add_modal_handler(C, op);
427
428                 return OPERATOR_RUNNING_MODAL;
429         }
430         else {
431                 eyedropper_exit(C, op);
432                 return OPERATOR_CANCELLED;
433         }
434 }
435
436 /* Repeat operator */
437 static int eyedropper_exec(bContext *C, wmOperator *op)
438 {
439         /* init */
440         if (eyedropper_init(C, op)) {
441
442                 /* do something */
443
444                 /* cleanup */
445                 eyedropper_exit(C, op);
446
447                 return OPERATOR_FINISHED;
448         }
449         else {
450                 return OPERATOR_CANCELLED;
451         }
452 }
453
454 static int eyedropper_poll(bContext *C)
455 {
456         PointerRNA ptr;
457         PropertyRNA *prop;
458         int index_dummy;
459         uiBut *but;
460
461         /* Only color buttons */
462         if ((CTX_wm_window(C) != NULL) &&
463             (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
464             (but->type == UI_BTYPE_COLOR))
465         {
466                 return 1;
467         }
468
469         return 0;
470 }
471
472 void UI_OT_eyedropper_color(wmOperatorType *ot)
473 {
474         /* identifiers */
475         ot->name = "Eyedropper";
476         ot->idname = "UI_OT_eyedropper_color";
477         ot->description = "Sample a color from the Blender Window to store in a property";
478
479         /* api callbacks */
480         ot->invoke = eyedropper_invoke;
481         ot->modal = eyedropper_modal;
482         ot->cancel = eyedropper_cancel;
483         ot->exec = eyedropper_exec;
484         ot->poll = eyedropper_poll;
485
486         /* flags */
487         ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
488
489         /* properties */
490 }
491
492 /** \} */
493
494
495 /* -------------------------------------------------------------------- */
496 /* Data Dropper */
497
498 /** \name Eyedropper (ID data-blocks)
499  *
500  * \note: datadropper is only internal name to avoid confusion in this file.
501  * \{ */
502
503 typedef struct DataDropper {
504         PointerRNA ptr;
505         PropertyRNA *prop;
506         short idcode;
507         const char *idcode_name;
508
509         ID *init_id; /* for resetting on cancel */
510
511         ARegionType *art;
512         void *draw_handle_pixel;
513         char name[200];
514 } DataDropper;
515
516
517 static void datadropper_draw_cb(const struct bContext *C, ARegion *ar, void *arg)
518 {
519         DataDropper *ddr = arg;
520         eyedropper_draw_cursor_text(C, ar, ddr->name);
521 }
522
523
524 static int datadropper_init(bContext *C, wmOperator *op)
525 {
526         DataDropper *ddr;
527         int index_dummy;
528         StructRNA *type;
529
530         SpaceType *st;
531         ARegionType *art;
532
533         st = BKE_spacetype_from_id(SPACE_VIEW3D);
534         art = BKE_regiontype_from_id(st, RGN_TYPE_WINDOW);
535
536         op->customdata = ddr = MEM_callocN(sizeof(DataDropper), "DataDropper");
537
538         UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &index_dummy);
539
540         if ((ddr->ptr.data == NULL) ||
541             (ddr->prop == NULL) ||
542             (RNA_property_editable(&ddr->ptr, ddr->prop) == false) ||
543             (RNA_property_type(ddr->prop) != PROP_POINTER))
544         {
545                 return false;
546         }
547
548         ddr->art = art;
549         ddr->draw_handle_pixel = ED_region_draw_cb_activate(art, datadropper_draw_cb, ddr, REGION_DRAW_POST_PIXEL);
550
551         type = RNA_property_pointer_type(&ddr->ptr, ddr->prop);
552         ddr->idcode = RNA_type_to_ID_code(type);
553         BLI_assert(ddr->idcode != 0);
554         /* Note we can translate here (instead of on draw time), because this struct has very short lifetime. */
555         ddr->idcode_name = TIP_(BKE_idcode_to_name(ddr->idcode));
556
557         PointerRNA ptr = RNA_property_pointer_get(&ddr->ptr, ddr->prop);
558         ddr->init_id = ptr.id.data;
559
560         return true;
561 }
562
563 static void datadropper_exit(bContext *C, wmOperator *op)
564 {
565         WM_cursor_modal_restore(CTX_wm_window(C));
566
567         if (op->customdata) {
568                 DataDropper *ddr = (DataDropper *)op->customdata;
569
570                 if (ddr->art) {
571                         ED_region_draw_cb_exit(ddr->art, ddr->draw_handle_pixel);
572                 }
573
574                 MEM_freeN(op->customdata);
575
576                 op->customdata = NULL;
577         }
578
579         WM_event_add_mousemove(C);
580 }
581
582 /* *** datadropper id helper functions *** */
583 /**
584  * \brief get the ID from the screen.
585  *
586  */
587 static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int my, ID **r_id)
588 {
589         /* we could use some clever */
590         bScreen *screen = CTX_wm_screen(C);
591         ScrArea *sa = BKE_screen_find_area_xy(screen, -1, mx, my);
592
593         ScrArea *area_prev = CTX_wm_area(C);
594         ARegion *ar_prev = CTX_wm_region(C);
595
596         ddr->name[0] = '\0';
597
598         if (sa) {
599                 if (sa->spacetype == SPACE_VIEW3D) {
600                         ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
601                         if (ar) {
602                                 const int mval[2] = {
603                                     mx - ar->winrct.xmin,
604                                     my - ar->winrct.ymin};
605                                 BaseLegacy *base;
606
607                                 CTX_wm_area_set(C, sa);
608                                 CTX_wm_region_set(C, ar);
609
610                                 /* grr, always draw else we leave stale text */
611                                 ED_region_tag_redraw(ar);
612
613                                 base = ED_view3d_give_base_under_cursor(C, mval);
614                                 if (base) {
615                                         Object *ob = base->object;
616                                         ID *id = NULL;
617                                         if (ddr->idcode == ID_OB) {
618                                                 id = (ID *)ob;
619                                         }
620                                         else if (ob->data) {
621                                                 if (GS(((ID *)ob->data)->name) == ddr->idcode) {
622                                                         id = (ID *)ob->data;
623                                                 }
624                                                 else {
625                                                         BLI_snprintf(ddr->name, sizeof(ddr->name), "Incompatible, expected a %s",
626                                                                      ddr->idcode_name);
627                                                 }
628                                         }
629
630                                         if (id) {
631                                                 BLI_snprintf(ddr->name, sizeof(ddr->name), "%s: %s",
632                                                              ddr->idcode_name, id->name + 2);
633                                                 *r_id = id;
634                                         }
635                                 }
636                         }
637                 }
638         }
639
640         CTX_wm_area_set(C, area_prev);
641         CTX_wm_region_set(C, ar_prev);
642 }
643
644 /* sets the ID, returns success */
645 static bool datadropper_id_set(bContext *C, DataDropper *ddr, ID *id)
646 {
647         PointerRNA ptr_value;
648
649         RNA_id_pointer_create(id, &ptr_value);
650
651         RNA_property_pointer_set(&ddr->ptr, ddr->prop, ptr_value);
652
653         RNA_property_update(C, &ddr->ptr, ddr->prop);
654
655         ptr_value = RNA_property_pointer_get(&ddr->ptr, ddr->prop);
656
657         return (ptr_value.id.data == id);
658 }
659
660 /* single point sample & set */
661 static bool datadropper_id_sample(bContext *C, DataDropper *ddr, int mx, int my)
662 {
663         ID *id = NULL;
664
665         datadropper_id_sample_pt(C, ddr, mx, my, &id);
666         return datadropper_id_set(C, ddr, id);
667 }
668
669 static void datadropper_cancel(bContext *C, wmOperator *op)
670 {
671         DataDropper *ddr = op->customdata;
672         datadropper_id_set(C, ddr, ddr->init_id);
673         datadropper_exit(C, op);
674 }
675
676 /* main modal status check */
677 static int datadropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
678 {
679         DataDropper *ddr = (DataDropper *)op->customdata;
680
681         /* handle modal keymap */
682         if (event->type == EVT_MODAL_MAP) {
683                 switch (event->val) {
684                         case EYE_MODAL_CANCEL:
685                                 datadropper_cancel(C, op);
686                                 return OPERATOR_CANCELLED;
687                         case EYE_MODAL_SAMPLE_CONFIRM:
688                         {
689                                 bool success;
690
691                                 success = datadropper_id_sample(C, ddr, event->x, event->y);
692                                 datadropper_exit(C, op);
693
694                                 if (success) {
695                                         return OPERATOR_FINISHED;
696                                 }
697                                 else {
698                                         BKE_report(op->reports, RPT_WARNING, "Failed to set value");
699                                         return OPERATOR_CANCELLED;
700                                 }
701                         }
702                 }
703         }
704         else if (event->type == MOUSEMOVE) {
705                 ID *id = NULL;
706                 datadropper_id_sample_pt(C, ddr, event->x, event->y, &id);
707         }
708
709         return OPERATOR_RUNNING_MODAL;
710 }
711
712 /* Modal Operator init */
713 static int datadropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
714 {
715         /* init */
716         if (datadropper_init(C, op)) {
717                 WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
718
719                 /* add temp handler */
720                 WM_event_add_modal_handler(C, op);
721
722                 return OPERATOR_RUNNING_MODAL;
723         }
724         else {
725                 datadropper_exit(C, op);
726                 return OPERATOR_CANCELLED;
727         }
728 }
729
730 /* Repeat operator */
731 static int datadropper_exec(bContext *C, wmOperator *op)
732 {
733         /* init */
734         if (datadropper_init(C, op)) {
735                 /* cleanup */
736                 datadropper_exit(C, op);
737
738                 return OPERATOR_FINISHED;
739         }
740         else {
741                 return OPERATOR_CANCELLED;
742         }
743 }
744
745 static int datadropper_poll(bContext *C)
746 {
747         PointerRNA ptr;
748         PropertyRNA *prop;
749         int index_dummy;
750         uiBut *but;
751
752         /* data dropper only supports object data */
753         if ((CTX_wm_window(C) != NULL) &&
754             (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
755             (but->type == UI_BTYPE_SEARCH_MENU) &&
756             (but->flag & UI_BUT_VALUE_CLEAR))
757         {
758                 if (prop && RNA_property_type(prop) == PROP_POINTER) {
759                         StructRNA *type = RNA_property_pointer_type(&ptr, prop);
760                         const short idcode = RNA_type_to_ID_code(type);
761                         if ((idcode == ID_OB) || OB_DATA_SUPPORT_ID(idcode)) {
762                                 return 1;
763                         }
764                 }
765         }
766
767         return 0;
768 }
769
770 void UI_OT_eyedropper_id(wmOperatorType *ot)
771 {
772         /* identifiers */
773         ot->name = "Eyedropper Data-Block";
774         ot->idname = "UI_OT_eyedropper_id";
775         ot->description = "Sample a data-block from the 3D View to store in a property";
776
777         /* api callbacks */
778         ot->invoke = datadropper_invoke;
779         ot->modal = datadropper_modal;
780         ot->cancel = datadropper_cancel;
781         ot->exec = datadropper_exec;
782         ot->poll = datadropper_poll;
783
784         /* flags */
785         ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
786
787         /* properties */
788 }
789
790 /** \} */
791
792
793 /* -------------------------------------------------------------------- */
794 /* Depth Dropper */
795
796 /** \name Eyedropper (Depth)
797  *
798  * \note: depthdropper is only internal name to avoid confusion in this file.
799  * \{ */
800
801 typedef struct DepthDropper {
802         PointerRNA ptr;
803         PropertyRNA *prop;
804
805         float init_depth; /* for resetting on cancel */
806
807         bool  accum_start; /* has mouse been presed */
808         float accum_depth;
809         int   accum_tot;
810
811         ARegionType *art;
812         void *draw_handle_pixel;
813         char name[200];
814 } DepthDropper;
815
816
817 static void depthdropper_draw_cb(const struct bContext *C, ARegion *ar, void *arg)
818 {
819         DepthDropper *ddr = arg;
820         eyedropper_draw_cursor_text(C, ar, ddr->name);
821 }
822
823
824 static int depthdropper_init(bContext *C, wmOperator *op)
825 {
826         DepthDropper *ddr;
827         int index_dummy;
828
829         SpaceType *st;
830         ARegionType *art;
831
832         st = BKE_spacetype_from_id(SPACE_VIEW3D);
833         art = BKE_regiontype_from_id(st, RGN_TYPE_WINDOW);
834
835         op->customdata = ddr = MEM_callocN(sizeof(DepthDropper), "DepthDropper");
836
837         UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &index_dummy);
838
839         /* fallback to the active camera's dof */
840         if (ddr->prop == NULL) {
841                 RegionView3D *rv3d = CTX_wm_region_view3d(C);
842                 if (rv3d && rv3d->persp == RV3D_CAMOB) {
843                         View3D *v3d = CTX_wm_view3d(C);
844                         if (v3d->camera && v3d->camera->data && !ID_IS_LINKED(v3d->camera->data)) {
845                                 RNA_id_pointer_create(v3d->camera->data, &ddr->ptr);
846                                 ddr->prop = RNA_struct_find_property(&ddr->ptr, "dof_distance");
847                         }
848                 }
849         }
850
851         if ((ddr->ptr.data == NULL) ||
852             (ddr->prop == NULL) ||
853             (RNA_property_editable(&ddr->ptr, ddr->prop) == false) ||
854             (RNA_property_type(ddr->prop) != PROP_FLOAT))
855         {
856                 return false;
857         }
858
859         ddr->art = art;
860         ddr->draw_handle_pixel = ED_region_draw_cb_activate(art, depthdropper_draw_cb, ddr, REGION_DRAW_POST_PIXEL);
861         ddr->init_depth = RNA_property_float_get(&ddr->ptr, ddr->prop);
862
863         return true;
864 }
865
866 static void depthdropper_exit(bContext *C, wmOperator *op)
867 {
868         WM_cursor_modal_restore(CTX_wm_window(C));
869
870         if (op->customdata) {
871                 DepthDropper *ddr = (DepthDropper *)op->customdata;
872
873                 if (ddr->art) {
874                         ED_region_draw_cb_exit(ddr->art, ddr->draw_handle_pixel);
875                 }
876
877                 MEM_freeN(op->customdata);
878
879                 op->customdata = NULL;
880         }
881 }
882
883 /* *** depthdropper id helper functions *** */
884 /**
885  * \brief get the ID from the screen.
886  *
887  */
888 static void depthdropper_depth_sample_pt(bContext *C, DepthDropper *ddr, int mx, int my, float *r_depth)
889 {
890         /* we could use some clever */
891         bScreen *screen = CTX_wm_screen(C);
892         ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
893         Scene *scene = CTX_data_scene(C);
894         UnitSettings *unit = &scene->unit;
895         const bool do_split = (unit->flag & USER_UNIT_OPT_SPLIT) != 0;
896
897         ScrArea *area_prev = CTX_wm_area(C);
898         ARegion *ar_prev = CTX_wm_region(C);
899
900         ddr->name[0] = '\0';
901
902         if (sa) {
903                 if (sa->spacetype == SPACE_VIEW3D) {
904                         ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
905                         if (ar) {
906                                 struct Depsgraph *graph = CTX_data_depsgraph(C);
907                                 View3D *v3d = sa->spacedata.first;
908                                 RegionView3D *rv3d = ar->regiondata;
909                                 /* weak, we could pass in some reference point */
910                                 const float *view_co = v3d->camera ? v3d->camera->obmat[3] : rv3d->viewinv[3];
911                                 const int mval[2] = {
912                                     mx - ar->winrct.xmin,
913                                     my - ar->winrct.ymin};
914                                 float co[3];
915
916                                 EvaluationContext eval_ctx;
917                                 CTX_data_eval_ctx(C, &eval_ctx);
918
919                                 CTX_wm_area_set(C, sa);
920                                 CTX_wm_region_set(C, ar);
921
922                                 /* grr, always draw else we leave stale text */
923                                 ED_region_tag_redraw(ar);
924
925                                 view3d_operator_needs_opengl(C);
926
927                                 if (ED_view3d_autodist(&eval_ctx, graph, ar, v3d, mval, co, true, NULL)) {
928                                         const float mval_center_fl[2] = {
929                                             (float)ar->winx / 2,
930                                             (float)ar->winy / 2};
931                                         float co_align[3];
932
933                                         /* quick way to get view-center aligned point */
934                                         ED_view3d_win_to_3d(v3d, ar, co, mval_center_fl, co_align);
935
936                                         *r_depth = len_v3v3(view_co, co_align);
937
938                                         bUnit_AsString(ddr->name, sizeof(ddr->name),
939                                                        (double)*r_depth,
940                                                        4, unit->system, B_UNIT_LENGTH, do_split, false);
941                                 }
942                                 else {
943                                         BLI_strncpy(ddr->name, "Nothing under cursor", sizeof(ddr->name));
944                                 }
945                         }
946                 }
947         }
948
949         CTX_wm_area_set(C, area_prev);
950         CTX_wm_region_set(C, ar_prev);
951 }
952
953 /* sets the sample depth RGB, maintaining A */
954 static void depthdropper_depth_set(bContext *C, DepthDropper *ddr, const float depth)
955 {
956         RNA_property_float_set(&ddr->ptr, ddr->prop, depth);
957         RNA_property_update(C, &ddr->ptr, ddr->prop);
958 }
959
960 /* set sample from accumulated values */
961 static void depthdropper_depth_set_accum(bContext *C, DepthDropper *ddr)
962 {
963         float depth = ddr->accum_depth;
964         if (ddr->accum_tot) {
965                 depth /= (float)ddr->accum_tot;
966         }
967         depthdropper_depth_set(C, ddr, depth);
968 }
969
970 /* single point sample & set */
971 static void depthdropper_depth_sample(bContext *C, DepthDropper *ddr, int mx, int my)
972 {
973         float depth = -1.0f;
974         if (depth != -1.0f) {
975                 depthdropper_depth_sample_pt(C, ddr, mx, my, &depth);
976                 depthdropper_depth_set(C, ddr, depth);
977         }
978 }
979
980 static void depthdropper_depth_sample_accum(bContext *C, DepthDropper *ddr, int mx, int my)
981 {
982         float depth = -1.0f;
983         depthdropper_depth_sample_pt(C, ddr, mx, my, &depth);
984         if (depth != -1.0f) {
985                 ddr->accum_depth += depth;
986                 ddr->accum_tot++;
987         }
988 }
989
990 static void depthdropper_cancel(bContext *C, wmOperator *op)
991 {
992         DepthDropper *ddr = op->customdata;
993         depthdropper_depth_set(C, ddr, ddr->init_depth);
994         depthdropper_exit(C, op);
995 }
996
997 /* main modal status check */
998 static int depthdropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
999 {
1000         DepthDropper *ddr = (DepthDropper *)op->customdata;
1001
1002         /* handle modal keymap */
1003         if (event->type == EVT_MODAL_MAP) {
1004                 switch (event->val) {
1005                         case EYE_MODAL_CANCEL:
1006                                 depthdropper_cancel(C, op);
1007                                 return OPERATOR_CANCELLED;
1008                         case EYE_MODAL_SAMPLE_CONFIRM:
1009                                 if (ddr->accum_tot == 0) {
1010                                         depthdropper_depth_sample(C, ddr, event->x, event->y);
1011                                 }
1012                                 else {
1013                                         depthdropper_depth_set_accum(C, ddr);
1014                                 }
1015                                 depthdropper_exit(C, op);
1016                                 return OPERATOR_FINISHED;
1017                         case EYE_MODAL_SAMPLE_BEGIN:
1018                                 /* enable accum and make first sample */
1019                                 ddr->accum_start = true;
1020                                 depthdropper_depth_sample_accum(C, ddr, event->x, event->y);
1021                                 break;
1022                         case EYE_MODAL_SAMPLE_RESET:
1023                                 ddr->accum_tot = 0;
1024                                 ddr->accum_depth = 0.0f;
1025                                 depthdropper_depth_sample_accum(C, ddr, event->x, event->y);
1026                                 depthdropper_depth_set_accum(C, ddr);
1027                                 break;
1028                 }
1029         }
1030         else if (event->type == MOUSEMOVE) {
1031                 if (ddr->accum_start) {
1032                         /* button is pressed so keep sampling */
1033                         depthdropper_depth_sample_accum(C, ddr, event->x, event->y);
1034                         depthdropper_depth_set_accum(C, ddr);
1035                 }
1036         }
1037
1038         return OPERATOR_RUNNING_MODAL;
1039 }
1040
1041 /* Modal Operator init */
1042 static int depthdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1043 {
1044         /* init */
1045         if (depthdropper_init(C, op)) {
1046                 WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
1047
1048                 /* add temp handler */
1049                 WM_event_add_modal_handler(C, op);
1050
1051                 return OPERATOR_RUNNING_MODAL;
1052         }
1053         else {
1054                 depthdropper_exit(C, op);
1055                 return OPERATOR_CANCELLED;
1056         }
1057 }
1058
1059 /* Repeat operator */
1060 static int depthdropper_exec(bContext *C, wmOperator *op)
1061 {
1062         /* init */
1063         if (depthdropper_init(C, op)) {
1064                 /* cleanup */
1065                 depthdropper_exit(C, op);
1066
1067                 return OPERATOR_FINISHED;
1068         }
1069         else {
1070                 return OPERATOR_CANCELLED;
1071         }
1072 }
1073
1074 static int depthdropper_poll(bContext *C)
1075 {
1076         PointerRNA ptr;
1077         PropertyRNA *prop;
1078         int index_dummy;
1079         uiBut *but;
1080
1081         /* check if there's an active button taking depth value */
1082         if ((CTX_wm_window(C) != NULL) &&
1083             (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
1084             (but->type == UI_BTYPE_NUM) &&
1085             (prop != NULL))
1086         {
1087                 if ((RNA_property_type(prop) == PROP_FLOAT) &&
1088                     (RNA_property_subtype(prop) & PROP_UNIT_LENGTH) &&
1089                     (RNA_property_array_check(prop) == false))
1090                 {
1091                         return 1;
1092                 }
1093         }
1094         else {
1095                 RegionView3D *rv3d = CTX_wm_region_view3d(C);
1096                 if (rv3d && rv3d->persp == RV3D_CAMOB) {
1097                         View3D *v3d = CTX_wm_view3d(C);
1098                         if (v3d->camera && v3d->camera->data && !ID_IS_LINKED(v3d->camera->data)) {
1099                                 return 1;
1100                         }
1101                 }
1102         }
1103
1104         return 0;
1105 }
1106
1107 void UI_OT_eyedropper_depth(wmOperatorType *ot)
1108 {
1109         /* identifiers */
1110         ot->name = "Eyedropper Depth";
1111         ot->idname = "UI_OT_eyedropper_depth";
1112         ot->description = "Sample depth from the 3D view";
1113
1114         /* api callbacks */
1115         ot->invoke = depthdropper_invoke;
1116         ot->modal = depthdropper_modal;
1117         ot->cancel = depthdropper_cancel;
1118         ot->exec = depthdropper_exec;
1119         ot->poll = depthdropper_poll;
1120
1121         /* flags */
1122         ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
1123
1124         /* properties */
1125 }
1126
1127 /** \} */
1128
1129 /* -------------------------------------------------------------------- */
1130 /* Eyedropper
1131  */
1132  
1133 /* NOTE: This is here (instead of in drivers.c) because we need access the button internals,
1134  * which we cannot access outside of the interface module
1135  */
1136
1137 /** \name Eyedropper (Driver Target)
1138  * \{ */
1139
1140 typedef struct DriverDropper {
1141         /* Destination property (i.e. where we'll add a driver) */
1142         PointerRNA ptr;
1143         PropertyRNA *prop;
1144         int index;
1145         
1146         // TODO: new target?
1147 } DriverDropper;
1148
1149 static bool driverdropper_init(bContext *C, wmOperator *op)
1150 {
1151         DriverDropper *ddr;
1152         uiBut *but;
1153
1154         op->customdata = ddr = MEM_callocN(sizeof(DriverDropper), "DriverDropper");
1155
1156         but = UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &ddr->index);
1157
1158         if ((ddr->ptr.data == NULL) ||
1159             (ddr->prop == NULL) ||
1160             (RNA_property_editable(&ddr->ptr, ddr->prop) == false) ||
1161             (RNA_property_animateable(&ddr->ptr, ddr->prop) == false) ||
1162             (but->flag & UI_BUT_DRIVEN))
1163         {
1164                 return false;
1165         }
1166         
1167         return true;
1168 }
1169
1170 static void driverdropper_exit(bContext *C, wmOperator *op)
1171 {
1172         WM_cursor_modal_restore(CTX_wm_window(C));
1173
1174         if (op->customdata) {
1175                 MEM_freeN(op->customdata);
1176                 op->customdata = NULL;
1177         }
1178 }
1179
1180 static void driverdropper_sample(bContext *C, wmOperator *op, const wmEvent *event)
1181 {
1182         DriverDropper *ddr = (DriverDropper *)op->customdata;
1183         uiBut *but = eyedropper_get_property_button_under_mouse(C, event);
1184         
1185         short mapping_type = RNA_enum_get(op->ptr, "mapping_type");
1186         short flag = 0;
1187         
1188         /* we can only add a driver if we know what RNA property it corresponds to */
1189         if (but == NULL) {
1190                 return;
1191         }
1192         else {
1193                 /* Get paths for src... */
1194                 PointerRNA *target_ptr = &but->rnapoin;
1195                 PropertyRNA *target_prop = but->rnaprop;
1196                 int target_index = but->rnaindex;
1197                 
1198                 char *target_path = RNA_path_from_ID_to_property(target_ptr, target_prop);
1199                 
1200                 /* ... and destination */
1201                 char *dst_path    = BKE_animdata_driver_path_hack(C, &ddr->ptr, ddr->prop, NULL);
1202                 
1203                 /* Now create driver(s) */
1204                 if (target_path && dst_path) {
1205                         int success = ANIM_add_driver_with_target(op->reports,
1206                                                                   ddr->ptr.id.data, dst_path, ddr->index,
1207                                                                   target_ptr->id.data, target_path, target_index,
1208                                                                   flag, DRIVER_TYPE_PYTHON, mapping_type);
1209                         
1210                         if (success) {
1211                                 /* send updates */
1212                                 UI_context_update_anim_flag(C);
1213                                 DEG_relations_tag_update(CTX_data_main(C));
1214                                 DEG_id_tag_update(ddr->ptr.id.data, OB_RECALC_OB | OB_RECALC_DATA);
1215                                 WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL);  // XXX
1216                         }
1217                 }
1218                 
1219                 /* cleanup */
1220                 if (target_path)
1221                         MEM_freeN(target_path);
1222                 if (dst_path)
1223                         MEM_freeN(dst_path);
1224         }
1225 }
1226
1227 static void driverdropper_cancel(bContext *C, wmOperator *op)
1228 {
1229         driverdropper_exit(C, op);
1230 }
1231
1232 /* main modal status check */
1233 static int driverdropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
1234 {
1235         /* handle modal keymap */
1236         if (event->type == EVT_MODAL_MAP) {
1237                 switch (event->val) {
1238                         case EYE_MODAL_CANCEL:
1239                                 driverdropper_cancel(C, op);
1240                                 return OPERATOR_CANCELLED;
1241                                 
1242                         case EYE_MODAL_SAMPLE_CONFIRM:
1243                                 driverdropper_sample(C, op, event);
1244                                 driverdropper_exit(C, op);
1245                                 
1246                                 return OPERATOR_FINISHED;
1247                 }
1248         }
1249         
1250         return OPERATOR_RUNNING_MODAL;
1251 }
1252
1253 /* Modal Operator init */
1254 static int driverdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1255 {
1256         /* init */
1257         if (driverdropper_init(C, op)) {
1258                 WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
1259                 
1260                 /* add temp handler */
1261                 WM_event_add_modal_handler(C, op);
1262                 
1263                 return OPERATOR_RUNNING_MODAL;
1264         }
1265         else {
1266                 driverdropper_exit(C, op);
1267                 return OPERATOR_CANCELLED;
1268         }
1269 }
1270
1271 /* Repeat operator */
1272 static int driverdropper_exec(bContext *C, wmOperator *op)
1273 {
1274         /* init */
1275         if (driverdropper_init(C, op)) {
1276                 /* cleanup */
1277                 driverdropper_exit(C, op);
1278                 
1279                 return OPERATOR_FINISHED;
1280         }
1281         else {
1282                 return OPERATOR_CANCELLED;
1283         }
1284 }
1285
1286 static int driverdropper_poll(bContext *C)
1287 {
1288         if (!CTX_wm_window(C)) return 0;
1289         else return 1;
1290 }
1291
1292 void UI_OT_eyedropper_driver(wmOperatorType *ot)
1293 {
1294         /* identifiers */
1295         ot->name = "Eyedropper Driver";
1296         ot->idname = "UI_OT_eyedropper_driver";
1297         ot->description = "Pick a property to use as a driver target";
1298         
1299         /* api callbacks */
1300         ot->invoke = driverdropper_invoke;
1301         ot->modal = driverdropper_modal;
1302         ot->cancel = driverdropper_cancel;
1303         ot->exec = driverdropper_exec;
1304         ot->poll = driverdropper_poll;
1305         
1306         /* flags */
1307         ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL | OPTYPE_UNDO;
1308         
1309         /* properties */
1310         RNA_def_enum(ot->srna, "mapping_type", prop_driver_create_mapping_types, 0,
1311                      "Mapping Type", "Method used to match target and driven properties");
1312 }
1313
1314 /** \} */