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