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 /* for colorband eyedropper*/
80 #include "BLI_bitmap_draw_2d.h"
81 #include "BKE_colorband.h"
82
83 /* -------------------------------------------------------------------- */
84 /* Keymap
85  */
86 /** \name Modal Keymap
87  * \{ */
88
89 enum {
90         EYE_MODAL_CANCEL = 1,
91         EYE_MODAL_SAMPLE_CONFIRM,
92         EYE_MODAL_SAMPLE_BEGIN,
93         EYE_MODAL_SAMPLE_RESET,
94 };
95
96 /* Color-band point sample. */
97 enum {
98         EYE_MODAL_POINT_CANCEL = 1,
99         EYE_MODAL_POINT_SAMPLE,
100         EYE_MODAL_POINT_CONFIRM,
101         EYE_MODAL_POINT_RESET,
102         EYE_MODAL_POINT_REMOVE_LAST,
103 };
104
105
106 wmKeyMap *eyedropper_modal_keymap(wmKeyConfig *keyconf)
107 {
108         static const EnumPropertyItem modal_items[] = {
109                 {EYE_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
110                 {EYE_MODAL_SAMPLE_CONFIRM, "SAMPLE_CONFIRM", 0, "Confirm Sampling", ""},
111                 {EYE_MODAL_SAMPLE_BEGIN, "SAMPLE_BEGIN", 0, "Start Sampling", ""},
112                 {EYE_MODAL_SAMPLE_RESET, "SAMPLE_RESET", 0, "Reset Sampling", ""},
113                 {0, NULL, 0, NULL, NULL}
114         };
115
116         wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Eyedropper Modal Map");
117
118         /* this function is called for each spacetype, only needs to add map once */
119         if (keymap && keymap->modal_items)
120                 return NULL;
121
122         keymap = WM_modalkeymap_add(keyconf, "Eyedropper Modal Map", modal_items);
123
124         /* items for modal map */
125         WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, EYE_MODAL_CANCEL);
126         WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_ANY, 0, EYE_MODAL_CANCEL);
127         WM_modalkeymap_add_item(keymap, RETKEY, KM_RELEASE, KM_ANY, 0, EYE_MODAL_SAMPLE_CONFIRM);
128         WM_modalkeymap_add_item(keymap, PADENTER, KM_RELEASE, KM_ANY, 0, EYE_MODAL_SAMPLE_CONFIRM);
129         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, EYE_MODAL_SAMPLE_CONFIRM);
130         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, EYE_MODAL_SAMPLE_BEGIN);
131         WM_modalkeymap_add_item(keymap, SPACEKEY, KM_RELEASE, KM_ANY, 0, EYE_MODAL_SAMPLE_RESET);
132
133         /* assign to operators */
134         WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_colorband");
135         WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_color");
136         WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_id");
137         WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_depth");
138         WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_driver");
139
140         return keymap;
141 }
142
143 wmKeyMap *eyedropper_colorband_modal_keymap(wmKeyConfig *keyconf)
144 {
145         static const EnumPropertyItem modal_items_point[] = {
146                 {EYE_MODAL_POINT_CANCEL, "CANCEL", 0, "Cancel", ""},
147                 {EYE_MODAL_POINT_SAMPLE, "SAMPLE_SAMPLE", 0, "Sample a point", ""},
148                 {EYE_MODAL_POINT_CONFIRM, "SAMPLE_CONFIRM", 0, "Confirm Sampling", ""},
149                 {EYE_MODAL_POINT_RESET, "SAMPLE_RESET", 0, "Reset Sampling", ""},
150                 {0, NULL, 0, NULL, NULL}
151         };
152
153         wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Eyedropper ColorBand PointSampling Map");
154         if (keymap && keymap->modal_items)
155                 return keymap;
156
157         keymap = WM_modalkeymap_add(keyconf, "Eyedropper ColorBand PointSampling Map", modal_items_point);
158
159         /* items for modal map */
160         WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, EYE_MODAL_CANCEL);
161         WM_modalkeymap_add_item(keymap, BACKSPACEKEY, KM_PRESS, KM_ANY, 0, EYE_MODAL_POINT_REMOVE_LAST);
162         WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_ANY, 0, EYE_MODAL_POINT_CONFIRM);
163         WM_modalkeymap_add_item(keymap, RETKEY, KM_RELEASE, KM_ANY, 0, EYE_MODAL_POINT_CONFIRM);
164         WM_modalkeymap_add_item(keymap, PADENTER, KM_RELEASE, KM_ANY, 0, EYE_MODAL_POINT_CONFIRM);
165         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, EYE_MODAL_POINT_SAMPLE);
166         WM_modalkeymap_add_item(keymap, SPACEKEY, KM_RELEASE, KM_ANY, 0, EYE_MODAL_POINT_RESET);
167
168         /* assign to operators */
169         WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_colorband_point");
170
171         return keymap;
172 }
173
174 /** \} */
175
176
177 /* -------------------------------------------------------------------- */
178 /* Utility Functions
179  */
180 /** \name Generic Shared Functions
181  * \{ */
182
183 static void eyedropper_draw_cursor_text(const struct bContext *C, ARegion *ar, const char *name)
184 {
185         const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
186         wmWindow *win = CTX_wm_window(C);
187         int x = win->eventstate->x;
188         int y = win->eventstate->y;
189         const float col_fg[4] = {1.0f, 1.0f, 1.0f, 1.0f};
190         const float col_bg[4] = {0.0f, 0.0f, 0.0f, 0.2f};
191
192
193         if ((name[0] == '\0') ||
194             (BLI_rcti_isect_pt(&ar->winrct, x, y) == false))
195         {
196                 return;
197         }
198
199         x = x - ar->winrct.xmin;
200         y = y - ar->winrct.ymin;
201
202         y += U.widget_unit;
203
204         UI_fontstyle_draw_simple_backdrop(fstyle, x, y, name, col_fg, col_bg);
205 }
206
207
208 /**
209  * Utility to retrieve a button representing a RNA property that is currently under the cursor.
210  *
211  * This is to be used by any eyedroppers which fetch properties (e.g. UI_OT_eyedropper_driver).
212  * Especially during modal operations (e.g. as with the eyedroppers), context cannot be relied
213  * upon to provide this information, as it is not updated until the operator finishes.
214  *
215  * \return A button under the mouse which relates to some RNA Property, or NULL
216  */
217 static uiBut *eyedropper_get_property_button_under_mouse(bContext *C, const wmEvent *event)
218 {
219         bScreen *screen = CTX_wm_screen(C);
220         ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->x, event->y);
221         ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_ANY, event->x, event->y);
222         
223         uiBut *but = ui_but_find_mouse_over(ar, event);
224         
225         if (ELEM(NULL, but, but->rnapoin.data, but->rnaprop)) {
226                 return NULL;
227         }
228         else {
229                 return but;
230         }
231 }
232
233 /** \} */
234
235
236 /* -------------------------------------------------------------------- */
237 /* Eyedropper
238  */
239
240 /** \name Eyedropper (RGB Color)
241  * \{ */
242
243 typedef struct Eyedropper {
244         struct ColorManagedDisplay *display;
245
246         PointerRNA ptr;
247         PropertyRNA *prop;
248         int index;
249
250         float init_col[3]; /* for resetting on cancel */
251
252         bool  accum_start; /* has mouse been pressed */
253         float accum_col[3];
254         int   accum_tot;
255 } Eyedropper;
256
257 static bool eyedropper_init(bContext *C, wmOperator *op)
258 {
259         Scene *scene = CTX_data_scene(C);
260         Eyedropper *eye;
261
262         op->customdata = eye = MEM_callocN(sizeof(Eyedropper), "Eyedropper");
263
264         UI_context_active_but_prop_get(C, &eye->ptr, &eye->prop, &eye->index);
265
266         if ((eye->ptr.data == NULL) ||
267             (eye->prop == NULL) ||
268             (RNA_property_editable(&eye->ptr, eye->prop) == false) ||
269             (RNA_property_array_length(&eye->ptr, eye->prop) < 3) ||
270             (RNA_property_type(eye->prop) != PROP_FLOAT))
271         {
272                 return false;
273         }
274
275         if (RNA_property_subtype(eye->prop) != PROP_COLOR) {
276                 const char *display_device;
277                 float col[4];
278
279                 display_device = scene->display_settings.display_device;
280                 eye->display = IMB_colormanagement_display_get_named(display_device);
281
282                 /* store inital color */
283                 RNA_property_float_get_array(&eye->ptr, eye->prop, col);
284                 if (eye->display) {
285                         IMB_colormanagement_display_to_scene_linear_v3(col, eye->display);
286                 }
287                 copy_v3_v3(eye->init_col, col);
288         }
289
290         return true;
291 }
292
293 static void eyedropper_exit(bContext *C, wmOperator *op)
294 {
295         WM_cursor_modal_restore(CTX_wm_window(C));
296
297         if (op->customdata) {
298                 MEM_freeN(op->customdata);
299                 op->customdata = NULL;
300         }
301 }
302
303 /* *** eyedropper_color_ helper functions *** */
304
305 /**
306  * \brief get the color from the screen.
307  *
308  * Special check for image or nodes where we MAY have HDR pixels which don't display.
309  */
310 static void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3])
311 {
312         /* we could use some clever */
313         bScreen *screen = CTX_wm_screen(C);
314         ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
315         const char *display_device = CTX_data_scene(C)->display_settings.display_device;
316         struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
317
318         if (sa) {
319                 if (sa->spacetype == SPACE_IMAGE) {
320                         ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
321                         if (ar) {
322                                 SpaceImage *sima = sa->spacedata.first;
323                                 int mval[2] = {mx - ar->winrct.xmin,
324                                                my - ar->winrct.ymin};
325
326                                 if (ED_space_image_color_sample(sima, ar, mval, r_col)) {
327                                         return;
328                                 }
329                         }
330                 }
331                 else if (sa->spacetype == SPACE_NODE) {
332                         ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
333                         if (ar) {
334                                 SpaceNode *snode = sa->spacedata.first;
335                                 int mval[2] = {mx - ar->winrct.xmin,
336                                                my - ar->winrct.ymin};
337
338                                 if (ED_space_node_color_sample(snode, ar, mval, r_col)) {
339                                         return;
340                                 }
341                         }
342                 }
343                 else if (sa->spacetype == SPACE_CLIP) {
344                         ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
345                         if (ar) {
346                                 SpaceClip *sc = sa->spacedata.first;
347                                 int mval[2] = {mx - ar->winrct.xmin,
348                                                my - ar->winrct.ymin};
349
350                                 if (ED_space_clip_color_sample(sc, ar, mval, r_col)) {
351                                         return;
352                                 }
353                         }
354                 }
355         }
356
357         /* fallback to simple opengl picker */
358         glReadBuffer(GL_FRONT);
359         glReadPixels(mx, my, 1, 1, GL_RGB, GL_FLOAT, r_col);
360         glReadBuffer(GL_BACK);
361         
362         IMB_colormanagement_display_to_scene_linear_v3(r_col, display);
363 }
364
365 /* sets the sample color RGB, maintaining A */
366 static void eyedropper_color_set(bContext *C, Eyedropper *eye, const float col[3])
367 {
368         float col_conv[4];
369
370         /* to maintain alpha */
371         RNA_property_float_get_array(&eye->ptr, eye->prop, col_conv);
372
373         /* convert from linear rgb space to display space */
374         if (eye->display) {
375                 copy_v3_v3(col_conv, col);
376                 IMB_colormanagement_scene_linear_to_display_v3(col_conv, eye->display);
377         }
378         else {
379                 copy_v3_v3(col_conv, col);
380         }
381
382         RNA_property_float_set_array(&eye->ptr, eye->prop, col_conv);
383
384         RNA_property_update(C, &eye->ptr, eye->prop);
385 }
386
387 /* set sample from accumulated values */
388 static void eyedropper_color_set_accum(bContext *C, Eyedropper *eye)
389 {
390         float col[3];
391         mul_v3_v3fl(col, eye->accum_col, 1.0f / (float)eye->accum_tot);
392         eyedropper_color_set(C, eye, col);
393 }
394
395 /* single point sample & set */
396 static void eyedropper_color_sample(bContext *C, Eyedropper *eye, int mx, int my)
397 {
398         float col[3];
399         eyedropper_color_sample_fl(C, mx, my, col);
400         eyedropper_color_set(C, eye, col);
401 }
402
403 static void eyedropper_color_sample_accum(bContext *C, Eyedropper *eye, int mx, int my)
404 {
405         float col[3];
406         eyedropper_color_sample_fl(C, mx, my, col);
407         /* delay linear conversion */
408         add_v3_v3(eye->accum_col, col);
409         eye->accum_tot++;
410 }
411
412 static void eyedropper_cancel(bContext *C, wmOperator *op)
413 {
414         Eyedropper *eye = op->customdata;
415         eyedropper_color_set(C, eye, eye->init_col);
416         eyedropper_exit(C, op);
417 }
418
419 /* main modal status check */
420 static int eyedropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
421 {
422         Eyedropper *eye = (Eyedropper *)op->customdata;
423
424         /* handle modal keymap */
425         if (event->type == EVT_MODAL_MAP) {
426                 switch (event->val) {
427                         case EYE_MODAL_CANCEL:
428                                 eyedropper_cancel(C, op);
429                                 return OPERATOR_CANCELLED;
430                         case EYE_MODAL_SAMPLE_CONFIRM:
431                                 if (eye->accum_tot == 0) {
432                                         eyedropper_color_sample(C, eye, event->x, event->y);
433                                 }
434                                 else {
435                                         eyedropper_color_set_accum(C, eye);
436                                 }
437                                 eyedropper_exit(C, op);
438                                 return OPERATOR_FINISHED;
439                         case EYE_MODAL_SAMPLE_BEGIN:
440                                 /* enable accum and make first sample */
441                                 eye->accum_start = true;
442                                 eyedropper_color_sample_accum(C, eye, event->x, event->y);
443                                 break;
444                         case EYE_MODAL_SAMPLE_RESET:
445                                 eye->accum_tot = 0;
446                                 zero_v3(eye->accum_col);
447                                 eyedropper_color_sample_accum(C, eye, event->x, event->y);
448                                 eyedropper_color_set_accum(C, eye);
449                                 break;
450                 }
451         }
452         else if (event->type == MOUSEMOVE) {
453                 if (eye->accum_start) {
454                         /* button is pressed so keep sampling */
455                         eyedropper_color_sample_accum(C, eye, event->x, event->y);
456                         eyedropper_color_set_accum(C, eye);
457                 }
458         }
459
460         return OPERATOR_RUNNING_MODAL;
461 }
462
463 /* Modal Operator init */
464 static int eyedropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
465 {
466         /* init */
467         if (eyedropper_init(C, op)) {
468                 WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
469
470                 /* add temp handler */
471                 WM_event_add_modal_handler(C, op);
472
473                 return OPERATOR_RUNNING_MODAL;
474         }
475         else {
476                 eyedropper_exit(C, op);
477                 return OPERATOR_CANCELLED;
478         }
479 }
480
481 /* Repeat operator */
482 static int eyedropper_exec(bContext *C, wmOperator *op)
483 {
484         /* init */
485         if (eyedropper_init(C, op)) {
486
487                 /* do something */
488
489                 /* cleanup */
490                 eyedropper_exit(C, op);
491
492                 return OPERATOR_FINISHED;
493         }
494         else {
495                 return OPERATOR_CANCELLED;
496         }
497 }
498
499 static int eyedropper_poll(bContext *C)
500 {
501         PointerRNA ptr;
502         PropertyRNA *prop;
503         int index_dummy;
504         uiBut *but;
505
506         /* Only color buttons */
507         if ((CTX_wm_window(C) != NULL) &&
508             (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
509             (but->type == UI_BTYPE_COLOR))
510         {
511                 return 1;
512         }
513
514         return 0;
515 }
516
517 void UI_OT_eyedropper_color(wmOperatorType *ot)
518 {
519         /* identifiers */
520         ot->name = "Eyedropper";
521         ot->idname = "UI_OT_eyedropper_color";
522         ot->description = "Sample a color from the Blender Window to store in a property";
523
524         /* api callbacks */
525         ot->invoke = eyedropper_invoke;
526         ot->modal = eyedropper_modal;
527         ot->cancel = eyedropper_cancel;
528         ot->exec = eyedropper_exec;
529         ot->poll = eyedropper_poll;
530
531         /* flags */
532         ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
533
534         /* properties */
535 }
536
537 /** \} */
538
539 /* -------------------------------------------------------------------- */
540 /** \name Eyedropper (RGB Color Band)
541  *
542  * Operates by either:
543  * - Dragging a straight line, sampling pixels formed by the line to extract a gradient.
544  * - Clicking on points, adding each color to the end of the color-band.
545  * \{ */
546
547 typedef struct Colorband_RNAUpdateCb {
548         PointerRNA ptr;
549         PropertyRNA *prop;
550 } Colorband_RNAUpdateCb;
551
552 typedef struct EyedropperColorband {
553         int last_x, last_y;
554         /* Alpha is currently fixed at 1.0, may support in future. */
555         float (*color_buffer)[4];
556         int     color_buffer_alloc;
557         int     color_buffer_len;
558         bool sample_start;
559         ColorBand init_color_band;
560         ColorBand *color_band;
561         PointerRNA ptr;
562         PropertyRNA *prop;
563 } EyedropperColorband;
564
565 /* For user-data only. */
566 struct EyedropperColorband_Context {
567         bContext *context;
568         EyedropperColorband *eye;
569 };
570
571 static bool eyedropper_colorband_init(bContext *C, wmOperator *op)
572 {
573         ColorBand *band = NULL;
574         EyedropperColorband *eye;
575
576         uiBut *but = UI_context_active_but_get(C);
577
578         if (but == NULL) {
579                 /* pass */
580         }
581         else if (but->type == UI_BTYPE_COLORBAND) {
582                 /* When invoked with a hotkey, we can find the band in 'but->poin'. */
583                 band = (ColorBand *)but->poin;
584         }
585         else {
586                 /* When invoked from a button it's in custom_data field. */
587                 band = (ColorBand *)but->custom_data;
588         }
589
590         if (!band)
591                 return false;
592
593         op->customdata = eye = MEM_callocN(sizeof(EyedropperColorband), __func__);
594         eye->color_buffer_alloc = 16;
595         eye->color_buffer = MEM_mallocN(sizeof(*eye->color_buffer) * eye->color_buffer_alloc, __func__);
596         eye->color_buffer_len = 0;
597         eye->color_band = band;
598         eye->init_color_band = *eye->color_band;
599         eye->ptr = ((Colorband_RNAUpdateCb *)but->func_argN)->ptr;
600         eye->prop  = ((Colorband_RNAUpdateCb *)but->func_argN)->prop;
601
602         return true;
603 }
604
605 static void eyedropper_colorband_sample_point(bContext *C, EyedropperColorband *eye, int mx, int my)
606 {
607         if (eye->last_x != mx || eye->last_y != my) {
608                 float col[4];
609                 col[3] = 1.0f;  /* TODO: sample alpha */
610                 eyedropper_color_sample_fl(C, mx, my, col);
611                 if (eye->color_buffer_len + 1 == eye->color_buffer_alloc) {
612                         eye->color_buffer_alloc *= 2;
613                         eye->color_buffer = MEM_reallocN(eye->color_buffer, sizeof(*eye->color_buffer) * eye->color_buffer_alloc);
614                 }
615                 copy_v4_v4(eye->color_buffer[eye->color_buffer_len], col);
616                 eye->color_buffer_len += 1;
617                 eye->last_x = mx;
618                 eye->last_y = my;
619         }
620 }
621
622 static bool eyedropper_colorband_sample_callback(int mx, int my, void *userdata)
623 {
624         struct EyedropperColorband_Context *data = userdata;
625         bContext *C = data->context;
626         EyedropperColorband *eye = data->eye;
627         eyedropper_colorband_sample_point(C, eye, mx, my);
628         return true;
629 }
630
631 static void eyedropper_colorband_sample_segment(bContext *C, EyedropperColorband *eye, int mx, int my)
632 {
633         /* Since the mouse tends to move rather rapidly we use #BLI_bitmap_draw_2d_line_v2v2i
634          * to interpolate between the reported coordinates */
635         struct EyedropperColorband_Context userdata = {C, eye};
636         int p1[2] = {eye->last_x, eye->last_y};
637         int p2[2] = {mx, my};
638         BLI_bitmap_draw_2d_line_v2v2i(p1, p2, eyedropper_colorband_sample_callback, &userdata);
639 }
640
641 static void eyedropper_colorband_exit(bContext *C, wmOperator *op)
642 {
643         WM_cursor_modal_restore(CTX_wm_window(C));
644
645         if (op->customdata) {
646                 EyedropperColorband *eye = op->customdata;
647                 MEM_freeN(eye->color_buffer);
648                 MEM_freeN(eye);
649                 op->customdata = NULL;
650         }
651 }
652
653 static void eyedropper_colorband_apply(bContext *C, wmOperator *op)
654 {
655         EyedropperColorband *eye = op->customdata;
656         BKE_colorband_init_from_table_rgba(eye->color_band, eye->color_buffer, eye->color_buffer_len);
657         RNA_property_update(C, &eye->ptr, eye->prop);
658 }
659
660 static void eyedropper_colorband_cancel(bContext *C, wmOperator *op)
661 {
662         EyedropperColorband *eye = op->customdata;
663         *eye->color_band = eye->init_color_band;
664         RNA_property_update(C, &eye->ptr, eye->prop);
665         eyedropper_colorband_exit(C, op);
666 }
667
668 /* main modal status check */
669 static int eyedropper_colorband_modal(bContext *C, wmOperator *op, const wmEvent *event)
670 {
671         EyedropperColorband *eye = op->customdata;
672         /* handle modal keymap */
673         if (event->type == EVT_MODAL_MAP) {
674                 switch (event->val) {
675                         case EYE_MODAL_CANCEL:
676                                 eyedropper_colorband_cancel(C, op);
677                                 return OPERATOR_CANCELLED;
678                         case EYE_MODAL_SAMPLE_CONFIRM:
679                                 eyedropper_colorband_sample_segment(C, eye, event->x, event->y);
680                                 eyedropper_colorband_apply(C, op);
681                                 eyedropper_colorband_exit(C, op);
682                                 return OPERATOR_FINISHED;
683                         case EYE_MODAL_SAMPLE_BEGIN:
684                                 /* enable accum and make first sample */
685                                 eye->sample_start = true;
686                                 eyedropper_colorband_sample_point(C, eye, event->x, event->y);
687                                 eyedropper_colorband_apply(C, op);
688                                 eye->last_x = event->x;
689                                 eye->last_y = event->y;
690                                 break;
691                         case EYE_MODAL_SAMPLE_RESET:
692                                 break;
693                 }
694         }
695         else if (event->type == MOUSEMOVE) {
696                 if (eye->sample_start) {
697                         eyedropper_colorband_sample_segment(C, eye, event->x, event->y);
698                         eyedropper_colorband_apply(C, op);
699                 }
700         }
701         return OPERATOR_RUNNING_MODAL;
702 }
703
704 static int eyedropper_colorband_point_modal(bContext *C, wmOperator *op, const wmEvent *event)
705 {
706         EyedropperColorband *eye = op->customdata;
707         /* handle modal keymap */
708         if (event->type == EVT_MODAL_MAP) {
709                 switch (event->val) {
710                         case EYE_MODAL_POINT_CANCEL:
711                                 eyedropper_colorband_cancel(C, op);
712                                 return OPERATOR_CANCELLED;
713                         case EYE_MODAL_POINT_CONFIRM:
714                                 eyedropper_colorband_apply(C, op);
715                                 eyedropper_colorband_exit(C, op);
716                                 return OPERATOR_FINISHED;
717                         case EYE_MODAL_POINT_REMOVE_LAST:
718                                 if (eye->color_buffer_len > 0) {
719                                         eye->color_buffer_len -= 1;
720                                         eyedropper_colorband_apply(C, op);
721                                 }
722                                 break;
723                         case EYE_MODAL_POINT_SAMPLE:
724                                 eyedropper_colorband_sample_point(C, eye, event->x, event->y);
725                                 eyedropper_colorband_apply(C, op);
726                                 if (eye->color_buffer_len == MAXCOLORBAND ) {
727                                         eyedropper_colorband_exit(C, op);
728                                         return OPERATOR_FINISHED;
729                                 }
730                                 break;
731                         case EYE_MODAL_SAMPLE_RESET:
732                                 *eye->color_band = eye->init_color_band;
733                                 RNA_property_update(C, &eye->ptr, eye->prop);
734                                 eye->color_buffer_len = 0;
735                                 break;
736                 }
737         }
738         return OPERATOR_RUNNING_MODAL;
739 }
740
741
742 /* Modal Operator init */
743 static int eyedropper_colorband_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
744 {
745         /* init */
746         if (eyedropper_colorband_init(C, op)) {
747                 WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
748
749                 /* add temp handler */
750                 WM_event_add_modal_handler(C, op);
751
752                 return OPERATOR_RUNNING_MODAL;
753         }
754         else {
755                 eyedropper_colorband_exit(C, op);
756                 return OPERATOR_CANCELLED;
757         }
758 }
759
760 /* Repeat operator */
761 static int eyedropper_colorband_exec(bContext *C, wmOperator *op)
762 {
763         /* init */
764         if (eyedropper_colorband_init(C, op)) {
765
766                 /* do something */
767
768                 /* cleanup */
769                 eyedropper_colorband_exit(C, op);
770
771                 return OPERATOR_FINISHED;
772         }
773         else {
774                 return OPERATOR_CANCELLED;
775         }
776 }
777
778 void UI_OT_eyedropper_colorband(wmOperatorType *ot)
779 {
780         /* identifiers */
781         ot->name = "Eyedropper colorband";
782         ot->idname = "UI_OT_eyedropper_colorband";
783         ot->description = "Sample a color band";
784
785         /* api callbacks */
786         ot->invoke = eyedropper_colorband_invoke;
787         ot->modal = eyedropper_colorband_modal;
788         ot->cancel = eyedropper_colorband_cancel;
789         ot->exec = eyedropper_colorband_exec;
790
791         /* flags */
792         ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
793
794         /* properties */
795 }
796
797 void UI_OT_eyedropper_colorband_point(wmOperatorType *ot)
798 {
799         /* identifiers */
800         ot->name = "Eyedropper colorband (points)";
801         ot->idname = "UI_OT_eyedropper_colorband_point";
802         ot->description = "Pointsample a color band";
803
804         /* api callbacks */
805         ot->invoke = eyedropper_colorband_invoke;
806         ot->modal = eyedropper_colorband_point_modal;
807         ot->cancel = eyedropper_colorband_cancel;
808         ot->exec = eyedropper_colorband_exec;
809
810         /* flags */
811         ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
812
813         /* properties */
814 }
815
816 /** \} */
817
818 /* -------------------------------------------------------------------- */
819 /* Data Dropper */
820
821 /** \name Eyedropper (ID data-blocks)
822  *
823  * \note: datadropper is only internal name to avoid confusion in this file.
824  * \{ */
825
826 typedef struct DataDropper {
827         PointerRNA ptr;
828         PropertyRNA *prop;
829         short idcode;
830         const char *idcode_name;
831
832         ID *init_id; /* for resetting on cancel */
833
834         ARegionType *art;
835         void *draw_handle_pixel;
836         char name[200];
837 } DataDropper;
838
839
840 static void datadropper_draw_cb(const struct bContext *C, ARegion *ar, void *arg)
841 {
842         DataDropper *ddr = arg;
843         eyedropper_draw_cursor_text(C, ar, ddr->name);
844 }
845
846
847 static int datadropper_init(bContext *C, wmOperator *op)
848 {
849         DataDropper *ddr;
850         int index_dummy;
851         StructRNA *type;
852
853         SpaceType *st;
854         ARegionType *art;
855
856         st = BKE_spacetype_from_id(SPACE_VIEW3D);
857         art = BKE_regiontype_from_id(st, RGN_TYPE_WINDOW);
858
859         op->customdata = ddr = MEM_callocN(sizeof(DataDropper), "DataDropper");
860
861         UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &index_dummy);
862
863         if ((ddr->ptr.data == NULL) ||
864             (ddr->prop == NULL) ||
865             (RNA_property_editable(&ddr->ptr, ddr->prop) == false) ||
866             (RNA_property_type(ddr->prop) != PROP_POINTER))
867         {
868                 return false;
869         }
870
871         ddr->art = art;
872         ddr->draw_handle_pixel = ED_region_draw_cb_activate(art, datadropper_draw_cb, ddr, REGION_DRAW_POST_PIXEL);
873
874         type = RNA_property_pointer_type(&ddr->ptr, ddr->prop);
875         ddr->idcode = RNA_type_to_ID_code(type);
876         BLI_assert(ddr->idcode != 0);
877         /* Note we can translate here (instead of on draw time), because this struct has very short lifetime. */
878         ddr->idcode_name = TIP_(BKE_idcode_to_name(ddr->idcode));
879
880         PointerRNA ptr = RNA_property_pointer_get(&ddr->ptr, ddr->prop);
881         ddr->init_id = ptr.id.data;
882
883         return true;
884 }
885
886 static void datadropper_exit(bContext *C, wmOperator *op)
887 {
888         WM_cursor_modal_restore(CTX_wm_window(C));
889
890         if (op->customdata) {
891                 DataDropper *ddr = (DataDropper *)op->customdata;
892
893                 if (ddr->art) {
894                         ED_region_draw_cb_exit(ddr->art, ddr->draw_handle_pixel);
895                 }
896
897                 MEM_freeN(op->customdata);
898
899                 op->customdata = NULL;
900         }
901
902         WM_event_add_mousemove(C);
903 }
904
905 /* *** datadropper id helper functions *** */
906 /**
907  * \brief get the ID from the screen.
908  *
909  */
910 static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int my, ID **r_id)
911 {
912         /* we could use some clever */
913         bScreen *screen = CTX_wm_screen(C);
914         ScrArea *sa = BKE_screen_find_area_xy(screen, -1, mx, my);
915
916         ScrArea *area_prev = CTX_wm_area(C);
917         ARegion *ar_prev = CTX_wm_region(C);
918
919         ddr->name[0] = '\0';
920
921         if (sa) {
922                 if (sa->spacetype == SPACE_VIEW3D) {
923                         ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
924                         if (ar) {
925                                 const int mval[2] = {
926                                     mx - ar->winrct.xmin,
927                                     my - ar->winrct.ymin};
928                                 Base *base;
929
930                                 CTX_wm_area_set(C, sa);
931                                 CTX_wm_region_set(C, ar);
932
933                                 /* grr, always draw else we leave stale text */
934                                 ED_region_tag_redraw(ar);
935
936                                 base = ED_view3d_give_base_under_cursor(C, mval);
937                                 if (base) {
938                                         Object *ob = base->object;
939                                         ID *id = NULL;
940                                         if (ddr->idcode == ID_OB) {
941                                                 id = (ID *)ob;
942                                         }
943                                         else if (ob->data) {
944                                                 if (GS(((ID *)ob->data)->name) == ddr->idcode) {
945                                                         id = (ID *)ob->data;
946                                                 }
947                                                 else {
948                                                         BLI_snprintf(ddr->name, sizeof(ddr->name), "Incompatible, expected a %s",
949                                                                      ddr->idcode_name);
950                                                 }
951                                         }
952
953                                         if (id) {
954                                                 BLI_snprintf(ddr->name, sizeof(ddr->name), "%s: %s",
955                                                              ddr->idcode_name, id->name + 2);
956                                                 *r_id = id;
957                                         }
958                                 }
959                         }
960                 }
961         }
962
963         CTX_wm_area_set(C, area_prev);
964         CTX_wm_region_set(C, ar_prev);
965 }
966
967 /* sets the ID, returns success */
968 static bool datadropper_id_set(bContext *C, DataDropper *ddr, ID *id)
969 {
970         PointerRNA ptr_value;
971
972         RNA_id_pointer_create(id, &ptr_value);
973
974         RNA_property_pointer_set(&ddr->ptr, ddr->prop, ptr_value);
975
976         RNA_property_update(C, &ddr->ptr, ddr->prop);
977
978         ptr_value = RNA_property_pointer_get(&ddr->ptr, ddr->prop);
979
980         return (ptr_value.id.data == id);
981 }
982
983 /* single point sample & set */
984 static bool datadropper_id_sample(bContext *C, DataDropper *ddr, int mx, int my)
985 {
986         ID *id = NULL;
987
988         datadropper_id_sample_pt(C, ddr, mx, my, &id);
989         return datadropper_id_set(C, ddr, id);
990 }
991
992 static void datadropper_cancel(bContext *C, wmOperator *op)
993 {
994         DataDropper *ddr = op->customdata;
995         datadropper_id_set(C, ddr, ddr->init_id);
996         datadropper_exit(C, op);
997 }
998
999 /* main modal status check */
1000 static int datadropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
1001 {
1002         DataDropper *ddr = (DataDropper *)op->customdata;
1003
1004         /* handle modal keymap */
1005         if (event->type == EVT_MODAL_MAP) {
1006                 switch (event->val) {
1007                         case EYE_MODAL_CANCEL:
1008                                 datadropper_cancel(C, op);
1009                                 return OPERATOR_CANCELLED;
1010                         case EYE_MODAL_SAMPLE_CONFIRM:
1011                         {
1012                                 bool success;
1013
1014                                 success = datadropper_id_sample(C, ddr, event->x, event->y);
1015                                 datadropper_exit(C, op);
1016
1017                                 if (success) {
1018                                         return OPERATOR_FINISHED;
1019                                 }
1020                                 else {
1021                                         BKE_report(op->reports, RPT_WARNING, "Failed to set value");
1022                                         return OPERATOR_CANCELLED;
1023                                 }
1024                         }
1025                 }
1026         }
1027         else if (event->type == MOUSEMOVE) {
1028                 ID *id = NULL;
1029                 datadropper_id_sample_pt(C, ddr, event->x, event->y, &id);
1030         }
1031
1032         return OPERATOR_RUNNING_MODAL;
1033 }
1034
1035 /* Modal Operator init */
1036 static int datadropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1037 {
1038         /* init */
1039         if (datadropper_init(C, op)) {
1040                 WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
1041
1042                 /* add temp handler */
1043                 WM_event_add_modal_handler(C, op);
1044
1045                 return OPERATOR_RUNNING_MODAL;
1046         }
1047         else {
1048                 datadropper_exit(C, op);
1049                 return OPERATOR_CANCELLED;
1050         }
1051 }
1052
1053 /* Repeat operator */
1054 static int datadropper_exec(bContext *C, wmOperator *op)
1055 {
1056         /* init */
1057         if (datadropper_init(C, op)) {
1058                 /* cleanup */
1059                 datadropper_exit(C, op);
1060
1061                 return OPERATOR_FINISHED;
1062         }
1063         else {
1064                 return OPERATOR_CANCELLED;
1065         }
1066 }
1067
1068 static int datadropper_poll(bContext *C)
1069 {
1070         PointerRNA ptr;
1071         PropertyRNA *prop;
1072         int index_dummy;
1073         uiBut *but;
1074
1075         /* data dropper only supports object data */
1076         if ((CTX_wm_window(C) != NULL) &&
1077             (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
1078             (but->type == UI_BTYPE_SEARCH_MENU) &&
1079             (but->flag & UI_BUT_VALUE_CLEAR))
1080         {
1081                 if (prop && RNA_property_type(prop) == PROP_POINTER) {
1082                         StructRNA *type = RNA_property_pointer_type(&ptr, prop);
1083                         const short idcode = RNA_type_to_ID_code(type);
1084                         if ((idcode == ID_OB) || OB_DATA_SUPPORT_ID(idcode)) {
1085                                 return 1;
1086                         }
1087                 }
1088         }
1089
1090         return 0;
1091 }
1092
1093 void UI_OT_eyedropper_id(wmOperatorType *ot)
1094 {
1095         /* identifiers */
1096         ot->name = "Eyedropper Data-Block";
1097         ot->idname = "UI_OT_eyedropper_id";
1098         ot->description = "Sample a data-block from the 3D View to store in a property";
1099
1100         /* api callbacks */
1101         ot->invoke = datadropper_invoke;
1102         ot->modal = datadropper_modal;
1103         ot->cancel = datadropper_cancel;
1104         ot->exec = datadropper_exec;
1105         ot->poll = datadropper_poll;
1106
1107         /* flags */
1108         ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
1109
1110         /* properties */
1111 }
1112
1113 /** \} */
1114
1115
1116 /* -------------------------------------------------------------------- */
1117 /* Depth Dropper */
1118
1119 /** \name Eyedropper (Depth)
1120  *
1121  * \note: depthdropper is only internal name to avoid confusion in this file.
1122  * \{ */
1123
1124 typedef struct DepthDropper {
1125         PointerRNA ptr;
1126         PropertyRNA *prop;
1127
1128         float init_depth; /* for resetting on cancel */
1129
1130         bool  accum_start; /* has mouse been presed */
1131         float accum_depth;
1132         int   accum_tot;
1133
1134         ARegionType *art;
1135         void *draw_handle_pixel;
1136         char name[200];
1137 } DepthDropper;
1138
1139
1140 static void depthdropper_draw_cb(const struct bContext *C, ARegion *ar, void *arg)
1141 {
1142         DepthDropper *ddr = arg;
1143         eyedropper_draw_cursor_text(C, ar, ddr->name);
1144 }
1145
1146
1147 static int depthdropper_init(bContext *C, wmOperator *op)
1148 {
1149         DepthDropper *ddr;
1150         int index_dummy;
1151
1152         SpaceType *st;
1153         ARegionType *art;
1154
1155         st = BKE_spacetype_from_id(SPACE_VIEW3D);
1156         art = BKE_regiontype_from_id(st, RGN_TYPE_WINDOW);
1157
1158         op->customdata = ddr = MEM_callocN(sizeof(DepthDropper), "DepthDropper");
1159
1160         UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &index_dummy);
1161
1162         /* fallback to the active camera's dof */
1163         if (ddr->prop == NULL) {
1164                 RegionView3D *rv3d = CTX_wm_region_view3d(C);
1165                 if (rv3d && rv3d->persp == RV3D_CAMOB) {
1166                         View3D *v3d = CTX_wm_view3d(C);
1167                         if (v3d->camera && v3d->camera->data && !ID_IS_LINKED(v3d->camera->data)) {
1168                                 RNA_id_pointer_create(v3d->camera->data, &ddr->ptr);
1169                                 ddr->prop = RNA_struct_find_property(&ddr->ptr, "dof_distance");
1170                         }
1171                 }
1172         }
1173
1174         if ((ddr->ptr.data == NULL) ||
1175             (ddr->prop == NULL) ||
1176             (RNA_property_editable(&ddr->ptr, ddr->prop) == false) ||
1177             (RNA_property_type(ddr->prop) != PROP_FLOAT))
1178         {
1179                 return false;
1180         }
1181
1182         ddr->art = art;
1183         ddr->draw_handle_pixel = ED_region_draw_cb_activate(art, depthdropper_draw_cb, ddr, REGION_DRAW_POST_PIXEL);
1184         ddr->init_depth = RNA_property_float_get(&ddr->ptr, ddr->prop);
1185
1186         return true;
1187 }
1188
1189 static void depthdropper_exit(bContext *C, wmOperator *op)
1190 {
1191         WM_cursor_modal_restore(CTX_wm_window(C));
1192
1193         if (op->customdata) {
1194                 DepthDropper *ddr = (DepthDropper *)op->customdata;
1195
1196                 if (ddr->art) {
1197                         ED_region_draw_cb_exit(ddr->art, ddr->draw_handle_pixel);
1198                 }
1199
1200                 MEM_freeN(op->customdata);
1201
1202                 op->customdata = NULL;
1203         }
1204 }
1205
1206 /* *** depthdropper id helper functions *** */
1207 /**
1208  * \brief get the ID from the screen.
1209  *
1210  */
1211 static void depthdropper_depth_sample_pt(bContext *C, DepthDropper *ddr, int mx, int my, float *r_depth)
1212 {
1213         /* we could use some clever */
1214         bScreen *screen = CTX_wm_screen(C);
1215         ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
1216         Scene *scene = CTX_data_scene(C);
1217         UnitSettings *unit = &scene->unit;
1218         const bool do_split = (unit->flag & USER_UNIT_OPT_SPLIT) != 0;
1219
1220         ScrArea *area_prev = CTX_wm_area(C);
1221         ARegion *ar_prev = CTX_wm_region(C);
1222
1223         ddr->name[0] = '\0';
1224
1225         if (sa) {
1226                 if (sa->spacetype == SPACE_VIEW3D) {
1227                         ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
1228                         if (ar) {
1229                                 struct Depsgraph *graph = CTX_data_depsgraph(C);
1230                                 View3D *v3d = sa->spacedata.first;
1231                                 RegionView3D *rv3d = ar->regiondata;
1232                                 /* weak, we could pass in some reference point */
1233                                 const float *view_co = v3d->camera ? v3d->camera->obmat[3] : rv3d->viewinv[3];
1234                                 const int mval[2] = {
1235                                     mx - ar->winrct.xmin,
1236                                     my - ar->winrct.ymin};
1237                                 float co[3];
1238
1239                                 EvaluationContext eval_ctx;
1240                                 CTX_data_eval_ctx(C, &eval_ctx);
1241
1242                                 CTX_wm_area_set(C, sa);
1243                                 CTX_wm_region_set(C, ar);
1244
1245                                 /* grr, always draw else we leave stale text */
1246                                 ED_region_tag_redraw(ar);
1247
1248                                 view3d_operator_needs_opengl(C);
1249
1250                                 if (ED_view3d_autodist(&eval_ctx, graph, ar, v3d, mval, co, true, NULL)) {
1251                                         const float mval_center_fl[2] = {
1252                                             (float)ar->winx / 2,
1253                                             (float)ar->winy / 2};
1254                                         float co_align[3];
1255
1256                                         /* quick way to get view-center aligned point */
1257                                         ED_view3d_win_to_3d(v3d, ar, co, mval_center_fl, co_align);
1258
1259                                         *r_depth = len_v3v3(view_co, co_align);
1260
1261                                         bUnit_AsString(ddr->name, sizeof(ddr->name),
1262                                                        (double)*r_depth,
1263                                                        4, unit->system, B_UNIT_LENGTH, do_split, false);
1264                                 }
1265                                 else {
1266                                         BLI_strncpy(ddr->name, "Nothing under cursor", sizeof(ddr->name));
1267                                 }
1268                         }
1269                 }
1270         }
1271
1272         CTX_wm_area_set(C, area_prev);
1273         CTX_wm_region_set(C, ar_prev);
1274 }
1275
1276 /* sets the sample depth RGB, maintaining A */
1277 static void depthdropper_depth_set(bContext *C, DepthDropper *ddr, const float depth)
1278 {
1279         RNA_property_float_set(&ddr->ptr, ddr->prop, depth);
1280         RNA_property_update(C, &ddr->ptr, ddr->prop);
1281 }
1282
1283 /* set sample from accumulated values */
1284 static void depthdropper_depth_set_accum(bContext *C, DepthDropper *ddr)
1285 {
1286         float depth = ddr->accum_depth;
1287         if (ddr->accum_tot) {
1288                 depth /= (float)ddr->accum_tot;
1289         }
1290         depthdropper_depth_set(C, ddr, depth);
1291 }
1292
1293 /* single point sample & set */
1294 static void depthdropper_depth_sample(bContext *C, DepthDropper *ddr, int mx, int my)
1295 {
1296         float depth = -1.0f;
1297         if (depth != -1.0f) {
1298                 depthdropper_depth_sample_pt(C, ddr, mx, my, &depth);
1299                 depthdropper_depth_set(C, ddr, depth);
1300         }
1301 }
1302
1303 static void depthdropper_depth_sample_accum(bContext *C, DepthDropper *ddr, int mx, int my)
1304 {
1305         float depth = -1.0f;
1306         depthdropper_depth_sample_pt(C, ddr, mx, my, &depth);
1307         if (depth != -1.0f) {
1308                 ddr->accum_depth += depth;
1309                 ddr->accum_tot++;
1310         }
1311 }
1312
1313 static void depthdropper_cancel(bContext *C, wmOperator *op)
1314 {
1315         DepthDropper *ddr = op->customdata;
1316         depthdropper_depth_set(C, ddr, ddr->init_depth);
1317         depthdropper_exit(C, op);
1318 }
1319
1320 /* main modal status check */
1321 static int depthdropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
1322 {
1323         DepthDropper *ddr = (DepthDropper *)op->customdata;
1324
1325         /* handle modal keymap */
1326         if (event->type == EVT_MODAL_MAP) {
1327                 switch (event->val) {
1328                         case EYE_MODAL_CANCEL:
1329                                 depthdropper_cancel(C, op);
1330                                 return OPERATOR_CANCELLED;
1331                         case EYE_MODAL_SAMPLE_CONFIRM:
1332                                 if (ddr->accum_tot == 0) {
1333                                         depthdropper_depth_sample(C, ddr, event->x, event->y);
1334                                 }
1335                                 else {
1336                                         depthdropper_depth_set_accum(C, ddr);
1337                                 }
1338                                 depthdropper_exit(C, op);
1339                                 return OPERATOR_FINISHED;
1340                         case EYE_MODAL_SAMPLE_BEGIN:
1341                                 /* enable accum and make first sample */
1342                                 ddr->accum_start = true;
1343                                 depthdropper_depth_sample_accum(C, ddr, event->x, event->y);
1344                                 break;
1345                         case EYE_MODAL_SAMPLE_RESET:
1346                                 ddr->accum_tot = 0;
1347                                 ddr->accum_depth = 0.0f;
1348                                 depthdropper_depth_sample_accum(C, ddr, event->x, event->y);
1349                                 depthdropper_depth_set_accum(C, ddr);
1350                                 break;
1351                 }
1352         }
1353         else if (event->type == MOUSEMOVE) {
1354                 if (ddr->accum_start) {
1355                         /* button is pressed so keep sampling */
1356                         depthdropper_depth_sample_accum(C, ddr, event->x, event->y);
1357                         depthdropper_depth_set_accum(C, ddr);
1358                 }
1359         }
1360
1361         return OPERATOR_RUNNING_MODAL;
1362 }
1363
1364 /* Modal Operator init */
1365 static int depthdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1366 {
1367         /* init */
1368         if (depthdropper_init(C, op)) {
1369                 WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
1370
1371                 /* add temp handler */
1372                 WM_event_add_modal_handler(C, op);
1373
1374                 return OPERATOR_RUNNING_MODAL;
1375         }
1376         else {
1377                 depthdropper_exit(C, op);
1378                 return OPERATOR_CANCELLED;
1379         }
1380 }
1381
1382 /* Repeat operator */
1383 static int depthdropper_exec(bContext *C, wmOperator *op)
1384 {
1385         /* init */
1386         if (depthdropper_init(C, op)) {
1387                 /* cleanup */
1388                 depthdropper_exit(C, op);
1389
1390                 return OPERATOR_FINISHED;
1391         }
1392         else {
1393                 return OPERATOR_CANCELLED;
1394         }
1395 }
1396
1397 static int depthdropper_poll(bContext *C)
1398 {
1399         PointerRNA ptr;
1400         PropertyRNA *prop;
1401         int index_dummy;
1402         uiBut *but;
1403
1404         /* check if there's an active button taking depth value */
1405         if ((CTX_wm_window(C) != NULL) &&
1406             (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
1407             (but->type == UI_BTYPE_NUM) &&
1408             (prop != NULL))
1409         {
1410                 if ((RNA_property_type(prop) == PROP_FLOAT) &&
1411                     (RNA_property_subtype(prop) & PROP_UNIT_LENGTH) &&
1412                     (RNA_property_array_check(prop) == false))
1413                 {
1414                         return 1;
1415                 }
1416         }
1417         else {
1418                 RegionView3D *rv3d = CTX_wm_region_view3d(C);
1419                 if (rv3d && rv3d->persp == RV3D_CAMOB) {
1420                         View3D *v3d = CTX_wm_view3d(C);
1421                         if (v3d->camera && v3d->camera->data && !ID_IS_LINKED(v3d->camera->data)) {
1422                                 return 1;
1423                         }
1424                 }
1425         }
1426
1427         return 0;
1428 }
1429
1430 void UI_OT_eyedropper_depth(wmOperatorType *ot)
1431 {
1432         /* identifiers */
1433         ot->name = "Eyedropper Depth";
1434         ot->idname = "UI_OT_eyedropper_depth";
1435         ot->description = "Sample depth from the 3D view";
1436
1437         /* api callbacks */
1438         ot->invoke = depthdropper_invoke;
1439         ot->modal = depthdropper_modal;
1440         ot->cancel = depthdropper_cancel;
1441         ot->exec = depthdropper_exec;
1442         ot->poll = depthdropper_poll;
1443
1444         /* flags */
1445         ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
1446
1447         /* properties */
1448 }
1449
1450 /** \} */
1451
1452 /* -------------------------------------------------------------------- */
1453 /* Eyedropper
1454  */
1455  
1456 /* NOTE: This is here (instead of in drivers.c) because we need access the button internals,
1457  * which we cannot access outside of the interface module
1458  */
1459
1460 /** \name Eyedropper (Driver Target)
1461  * \{ */
1462
1463 typedef struct DriverDropper {
1464         /* Destination property (i.e. where we'll add a driver) */
1465         PointerRNA ptr;
1466         PropertyRNA *prop;
1467         int index;
1468         
1469         // TODO: new target?
1470 } DriverDropper;
1471
1472 static bool driverdropper_init(bContext *C, wmOperator *op)
1473 {
1474         DriverDropper *ddr;
1475         uiBut *but;
1476
1477         op->customdata = ddr = MEM_callocN(sizeof(DriverDropper), "DriverDropper");
1478
1479         but = UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &ddr->index);
1480
1481         if ((ddr->ptr.data == NULL) ||
1482             (ddr->prop == NULL) ||
1483             (RNA_property_editable(&ddr->ptr, ddr->prop) == false) ||
1484             (RNA_property_animateable(&ddr->ptr, ddr->prop) == false) ||
1485             (but->flag & UI_BUT_DRIVEN))
1486         {
1487                 return false;
1488         }
1489         
1490         return true;
1491 }
1492
1493 static void driverdropper_exit(bContext *C, wmOperator *op)
1494 {
1495         WM_cursor_modal_restore(CTX_wm_window(C));
1496
1497         if (op->customdata) {
1498                 MEM_freeN(op->customdata);
1499                 op->customdata = NULL;
1500         }
1501 }
1502
1503 static void driverdropper_sample(bContext *C, wmOperator *op, const wmEvent *event)
1504 {
1505         DriverDropper *ddr = (DriverDropper *)op->customdata;
1506         uiBut *but = eyedropper_get_property_button_under_mouse(C, event);
1507         
1508         short mapping_type = RNA_enum_get(op->ptr, "mapping_type");
1509         short flag = 0;
1510         
1511         /* we can only add a driver if we know what RNA property it corresponds to */
1512         if (but == NULL) {
1513                 return;
1514         }
1515         else {
1516                 /* Get paths for src... */
1517                 PointerRNA *target_ptr = &but->rnapoin;
1518                 PropertyRNA *target_prop = but->rnaprop;
1519                 int target_index = but->rnaindex;
1520                 
1521                 char *target_path = RNA_path_from_ID_to_property(target_ptr, target_prop);
1522                 
1523                 /* ... and destination */
1524                 char *dst_path    = BKE_animdata_driver_path_hack(C, &ddr->ptr, ddr->prop, NULL);
1525                 
1526                 /* Now create driver(s) */
1527                 if (target_path && dst_path) {
1528                         int success = ANIM_add_driver_with_target(op->reports,
1529                                                                   ddr->ptr.id.data, dst_path, ddr->index,
1530                                                                   target_ptr->id.data, target_path, target_index,
1531                                                                   flag, DRIVER_TYPE_PYTHON, mapping_type);
1532                         
1533                         if (success) {
1534                                 /* send updates */
1535                                 UI_context_update_anim_flag(C);
1536                                 DEG_relations_tag_update(CTX_data_main(C));
1537                                 DEG_id_tag_update(ddr->ptr.id.data, OB_RECALC_OB | OB_RECALC_DATA);
1538                                 WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL);  // XXX
1539                         }
1540                 }
1541                 
1542                 /* cleanup */
1543                 if (target_path)
1544                         MEM_freeN(target_path);
1545                 if (dst_path)
1546                         MEM_freeN(dst_path);
1547         }
1548 }
1549
1550 static void driverdropper_cancel(bContext *C, wmOperator *op)
1551 {
1552         driverdropper_exit(C, op);
1553 }
1554
1555 /* main modal status check */
1556 static int driverdropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
1557 {
1558         /* handle modal keymap */
1559         if (event->type == EVT_MODAL_MAP) {
1560                 switch (event->val) {
1561                         case EYE_MODAL_CANCEL:
1562                                 driverdropper_cancel(C, op);
1563                                 return OPERATOR_CANCELLED;
1564                                 
1565                         case EYE_MODAL_SAMPLE_CONFIRM:
1566                                 driverdropper_sample(C, op, event);
1567                                 driverdropper_exit(C, op);
1568                                 
1569                                 return OPERATOR_FINISHED;
1570                 }
1571         }
1572         
1573         return OPERATOR_RUNNING_MODAL;
1574 }
1575
1576 /* Modal Operator init */
1577 static int driverdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1578 {
1579         /* init */
1580         if (driverdropper_init(C, op)) {
1581                 WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
1582                 
1583                 /* add temp handler */
1584                 WM_event_add_modal_handler(C, op);
1585                 
1586                 return OPERATOR_RUNNING_MODAL;
1587         }
1588         else {
1589                 driverdropper_exit(C, op);
1590                 return OPERATOR_CANCELLED;
1591         }
1592 }
1593
1594 /* Repeat operator */
1595 static int driverdropper_exec(bContext *C, wmOperator *op)
1596 {
1597         /* init */
1598         if (driverdropper_init(C, op)) {
1599                 /* cleanup */
1600                 driverdropper_exit(C, op);
1601                 
1602                 return OPERATOR_FINISHED;
1603         }
1604         else {
1605                 return OPERATOR_CANCELLED;
1606         }
1607 }
1608
1609 static int driverdropper_poll(bContext *C)
1610 {
1611         if (!CTX_wm_window(C)) return 0;
1612         else return 1;
1613 }
1614
1615 void UI_OT_eyedropper_driver(wmOperatorType *ot)
1616 {
1617         /* identifiers */
1618         ot->name = "Eyedropper Driver";
1619         ot->idname = "UI_OT_eyedropper_driver";
1620         ot->description = "Pick a property to use as a driver target";
1621         
1622         /* api callbacks */
1623         ot->invoke = driverdropper_invoke;
1624         ot->modal = driverdropper_modal;
1625         ot->cancel = driverdropper_cancel;
1626         ot->exec = driverdropper_exec;
1627         ot->poll = driverdropper_poll;
1628         
1629         /* flags */
1630         ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL | OPTYPE_UNDO;
1631         
1632         /* properties */
1633         RNA_def_enum(ot->srna, "mapping_type", prop_driver_create_mapping_types, 0,
1634                      "Mapping Type", "Method used to match target and driven properties");
1635 }
1636
1637 /** \} */