doxygen: add newline after \file
[blender.git] / source / blender / editors / interface / interface_eyedropper_driver.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2009 Blender Foundation.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup edinterface
22  *
23  * Eyedropper (Animation Driver Targets).
24  *
25  * Defines:
26  * - #UI_OT_eyedropper_driver
27  */
28
29 #include "MEM_guardedalloc.h"
30
31 #include "DNA_anim_types.h"
32 #include "DNA_screen_types.h"
33 #include "DNA_object_types.h"
34
35
36 #include "BKE_context.h"
37 #include "BKE_animsys.h"
38
39 #include "DEG_depsgraph.h"
40 #include "DEG_depsgraph_build.h"
41
42 #include "RNA_access.h"
43 #include "RNA_define.h"
44
45 #include "UI_interface.h"
46
47 #include "WM_api.h"
48 #include "WM_types.h"
49
50 #include "ED_keyframing.h"
51
52 #include "interface_intern.h"
53 #include "interface_eyedropper_intern.h"
54
55 typedef struct DriverDropper {
56         /* Destination property (i.e. where we'll add a driver) */
57         PointerRNA ptr;
58         PropertyRNA *prop;
59         int index;
60         bool is_undo;
61
62         // TODO: new target?
63 } DriverDropper;
64
65 static bool driverdropper_init(bContext *C, wmOperator *op)
66 {
67         DriverDropper *ddr = MEM_callocN(sizeof(DriverDropper), __func__);
68
69         uiBut *but = UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &ddr->index);
70
71         if ((ddr->ptr.data == NULL) ||
72             (ddr->prop == NULL) ||
73             (RNA_property_editable(&ddr->ptr, ddr->prop) == false) ||
74             (RNA_property_animateable(&ddr->ptr, ddr->prop) == false) ||
75             (but->flag & UI_BUT_DRIVEN))
76         {
77                 MEM_freeN(ddr);
78                 return false;
79         }
80         op->customdata = ddr;
81
82         ddr->is_undo = UI_but_flag_is_set(but, UI_BUT_UNDO);
83
84         return true;
85 }
86
87 static void driverdropper_exit(bContext *C, wmOperator *op)
88 {
89         WM_cursor_modal_restore(CTX_wm_window(C));
90
91         if (op->customdata) {
92                 MEM_freeN(op->customdata);
93                 op->customdata = NULL;
94         }
95 }
96
97 static void driverdropper_sample(bContext *C, wmOperator *op, const wmEvent *event)
98 {
99         DriverDropper *ddr = (DriverDropper *)op->customdata;
100         uiBut *but = eyedropper_get_property_button_under_mouse(C, event);
101
102         short mapping_type = RNA_enum_get(op->ptr, "mapping_type");
103         short flag = 0;
104
105         /* we can only add a driver if we know what RNA property it corresponds to */
106         if (but == NULL) {
107                 return;
108         }
109         else {
110                 /* Get paths for src... */
111                 PointerRNA *target_ptr = &but->rnapoin;
112                 PropertyRNA *target_prop = but->rnaprop;
113                 int target_index = but->rnaindex;
114
115                 char *target_path = RNA_path_from_ID_to_property(target_ptr, target_prop);
116
117                 /* ... and destination */
118                 char *dst_path    = BKE_animdata_driver_path_hack(C, &ddr->ptr, ddr->prop, NULL);
119
120                 /* Now create driver(s) */
121                 if (target_path && dst_path) {
122                         int success = ANIM_add_driver_with_target(op->reports,
123                                                                   ddr->ptr.id.data, dst_path, ddr->index,
124                                                                   target_ptr->id.data, target_path, target_index,
125                                                                   flag, DRIVER_TYPE_PYTHON, mapping_type);
126
127                         if (success) {
128                                 /* send updates */
129                                 UI_context_update_anim_flag(C);
130                                 DEG_relations_tag_update(CTX_data_main(C));
131                                 DEG_id_tag_update(ddr->ptr.id.data, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
132                                 WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL);  // XXX
133                         }
134                 }
135
136                 /* cleanup */
137                 if (target_path)
138                         MEM_freeN(target_path);
139                 if (dst_path)
140                         MEM_freeN(dst_path);
141         }
142 }
143
144 static void driverdropper_cancel(bContext *C, wmOperator *op)
145 {
146         driverdropper_exit(C, op);
147 }
148
149 /* main modal status check */
150 static int driverdropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
151 {
152         DriverDropper *ddr = op->customdata;
153
154         /* handle modal keymap */
155         if (event->type == EVT_MODAL_MAP) {
156                 switch (event->val) {
157                         case EYE_MODAL_CANCEL:
158                         {
159                                 driverdropper_cancel(C, op);
160                                 return OPERATOR_CANCELLED;
161                         }
162                         case EYE_MODAL_SAMPLE_CONFIRM:
163                         {
164                                 const bool is_undo = ddr->is_undo;
165                                 driverdropper_sample(C, op, event);
166                                 driverdropper_exit(C, op);
167                                 /* Could support finished & undo-skip. */
168                                 return is_undo ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
169                         }
170                 }
171         }
172
173         return OPERATOR_RUNNING_MODAL;
174 }
175
176 /* Modal Operator init */
177 static int driverdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
178 {
179         /* init */
180         if (driverdropper_init(C, op)) {
181                 WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
182
183                 /* add temp handler */
184                 WM_event_add_modal_handler(C, op);
185
186                 return OPERATOR_RUNNING_MODAL;
187         }
188         else {
189                 return OPERATOR_CANCELLED;
190         }
191 }
192
193 /* Repeat operator */
194 static int driverdropper_exec(bContext *C, wmOperator *op)
195 {
196         /* init */
197         if (driverdropper_init(C, op)) {
198                 /* cleanup */
199                 driverdropper_exit(C, op);
200
201                 return OPERATOR_FINISHED;
202         }
203         else {
204                 return OPERATOR_CANCELLED;
205         }
206 }
207
208 static bool driverdropper_poll(bContext *C)
209 {
210         if (!CTX_wm_window(C)) return 0;
211         else return 1;
212 }
213
214 void UI_OT_eyedropper_driver(wmOperatorType *ot)
215 {
216         /* identifiers */
217         ot->name = "Eyedropper Driver";
218         ot->idname = "UI_OT_eyedropper_driver";
219         ot->description = "Pick a property to use as a driver target";
220
221         /* api callbacks */
222         ot->invoke = driverdropper_invoke;
223         ot->modal = driverdropper_modal;
224         ot->cancel = driverdropper_cancel;
225         ot->exec = driverdropper_exec;
226         ot->poll = driverdropper_poll;
227
228         /* flags */
229         ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_INTERNAL;
230
231         /* properties */
232         RNA_def_enum(ot->srna, "mapping_type", prop_driver_create_mapping_types, 0,
233                      "Mapping Type", "Method used to match target and driven properties");
234 }