f1ff23d41084857e85da79de8c1f772759f363e7
[blender.git] / source / blender / editors / interface / interface_anim.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
17 /** \file
18  * \ingroup edinterface
19  */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include "MEM_guardedalloc.h"
26
27 #include "DNA_anim_types.h"
28 #include "DNA_scene_types.h"
29 #include "DNA_screen_types.h"
30
31 #include "BLI_string.h"
32 #include "BLI_string_utf8.h"
33 #include "BLI_utildefines.h"
34
35 #include "BKE_context.h"
36 #include "BKE_fcurve.h"
37 #include "BKE_global.h"
38 #include "BKE_main.h"
39 #include "BKE_nla.h"
40
41 #include "DEG_depsgraph.h"
42 #include "DEG_depsgraph_build.h"
43
44 #include "ED_keyframing.h"
45
46 #include "UI_interface.h"
47
48 #include "RNA_access.h"
49
50 #include "WM_api.h"
51 #include "WM_types.h"
52
53 #include "interface_intern.h"
54
55 static FCurve *ui_but_get_fcurve(
56     uiBut *but, AnimData **adt, bAction **action, bool *r_driven, bool *r_special)
57 {
58   /* for entire array buttons we check the first component, it's not perfect
59    * but works well enough in typical cases */
60   int rnaindex = (but->rnaindex == -1) ? 0 : but->rnaindex;
61
62   return rna_get_fcurve_context_ui(
63       but->block->evil_C, &but->rnapoin, but->rnaprop, rnaindex, adt, action, r_driven, r_special);
64 }
65
66 void ui_but_anim_flag(uiBut *but, float cfra)
67 {
68   AnimData *adt;
69   bAction *act;
70   FCurve *fcu;
71   bool driven;
72   bool special;
73
74   but->flag &= ~(UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN);
75   but->drawflag &= ~UI_BUT_ANIMATED_CHANGED;
76
77   /* NOTE: "special" is reserved for special F-Curves stored on the animation data
78    *        itself (which are used to animate properties of the animation data).
79    *        We count those as "animated" too for now
80    */
81   fcu = ui_but_get_fcurve(but, &adt, &act, &driven, &special);
82
83   if (fcu) {
84     if (!driven) {
85       /* Empty curves are ignored by the animation evaluation system. */
86       if (BKE_fcurve_is_empty(fcu)) {
87         return;
88       }
89
90       but->flag |= UI_BUT_ANIMATED;
91
92       /* T41525 - When the active action is a NLA strip being edited,
93        * we need to correct the frame number to "look inside" the
94        * remapped action
95        */
96       if (adt) {
97         cfra = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP);
98       }
99
100       if (fcurve_frame_has_keyframe(fcu, cfra, 0)) {
101         but->flag |= UI_BUT_ANIMATED_KEY;
102       }
103
104       /* XXX: this feature is totally broken and useless with NLA */
105       if (adt == NULL || adt->nla_tracks.first == NULL) {
106         if (fcurve_is_changed(but->rnapoin, but->rnaprop, fcu, cfra)) {
107           but->drawflag |= UI_BUT_ANIMATED_CHANGED;
108         }
109       }
110     }
111     else {
112       but->flag |= UI_BUT_DRIVEN;
113     }
114   }
115 }
116
117 void ui_but_anim_decorate_update_from_flag(uiBut *but)
118 {
119   BLI_assert(UI_but_is_decorator(but) && but->prev);
120   int flag = but->prev->flag;
121   if (flag & UI_BUT_DRIVEN) {
122     but->icon = ICON_DECORATE_DRIVER;
123   }
124   else if (flag & UI_BUT_ANIMATED_KEY) {
125     but->icon = ICON_DECORATE_KEYFRAME;
126   }
127   else if (flag & UI_BUT_ANIMATED) {
128     but->icon = ICON_DECORATE_ANIMATE;
129   }
130   else if (flag & UI_BUT_OVERRIDEN) {
131     but->icon = ICON_DECORATE_OVERRIDE;
132   }
133   else {
134     but->icon = ICON_DECORATE;
135   }
136
137   const int flag_copy = (UI_BUT_DISABLED | UI_BUT_INACTIVE);
138   but->flag = (but->flag & ~flag_copy) | (flag & flag_copy);
139 }
140
141 /**
142  * \a str can be NULL to only perform check if \a but has an expression at all.
143  * \return if button has an expression.
144  */
145 bool ui_but_anim_expression_get(uiBut *but, char *str, size_t maxlen)
146 {
147   FCurve *fcu;
148   ChannelDriver *driver;
149   bool driven, special;
150
151   fcu = ui_but_get_fcurve(but, NULL, NULL, &driven, &special);
152
153   if (fcu && driven) {
154     driver = fcu->driver;
155
156     if (driver && driver->type == DRIVER_TYPE_PYTHON) {
157       if (str) {
158         BLI_strncpy(str, driver->expression, maxlen);
159       }
160       return true;
161     }
162   }
163
164   return false;
165 }
166
167 bool ui_but_anim_expression_set(uiBut *but, const char *str)
168 {
169   FCurve *fcu;
170   ChannelDriver *driver;
171   bool driven, special;
172
173   fcu = ui_but_get_fcurve(but, NULL, NULL, &driven, &special);
174
175   if (fcu && driven) {
176     driver = fcu->driver;
177
178     if (driver && (driver->type == DRIVER_TYPE_PYTHON)) {
179       bContext *C = but->block->evil_C;
180
181       BLI_strncpy_utf8(driver->expression, str, sizeof(driver->expression));
182
183       /* tag driver as needing to be recompiled */
184       BKE_driver_invalidate_expression(driver, true, false);
185
186       /* clear invalid flags which may prevent this from working */
187       driver->flag &= ~DRIVER_FLAG_INVALID;
188       fcu->flag &= ~FCURVE_DISABLED;
189
190       /* this notifier should update the Graph Editor and trigger depsgraph refresh? */
191       WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME, NULL);
192
193       DEG_relations_tag_update(CTX_data_main(C));
194
195       return true;
196     }
197   }
198
199   return false;
200 }
201
202 /* create new expression for button (i.e. a "scripted driver"), if it can be created... */
203 bool ui_but_anim_expression_create(uiBut *but, const char *str)
204 {
205   bContext *C = but->block->evil_C;
206   ID *id;
207   FCurve *fcu;
208   char *path;
209   bool ok = false;
210
211   /* button must have RNA-pointer to a numeric-capable property */
212   if (ELEM(NULL, but->rnapoin.data, but->rnaprop)) {
213     if (G.debug & G_DEBUG) {
214       printf("ERROR: create expression failed - button has no RNA info attached\n");
215     }
216     return false;
217   }
218
219   if (RNA_property_array_check(but->rnaprop) != 0) {
220     if (but->rnaindex == -1) {
221       if (G.debug & G_DEBUG) {
222         printf("ERROR: create expression failed - can't create expression for entire array\n");
223       }
224       return false;
225     }
226   }
227
228   /* make sure we have animdata for this */
229   /* FIXME: until materials can be handled by depsgraph,
230    * don't allow drivers to be created for them */
231   id = (ID *)but->rnapoin.id.data;
232   if ((id == NULL) || (GS(id->name) == ID_MA) || (GS(id->name) == ID_TE)) {
233     if (G.debug & G_DEBUG) {
234       printf("ERROR: create expression failed - invalid data-block for adding drivers (%p)\n", id);
235     }
236     return false;
237   }
238
239   /* get path */
240   path = RNA_path_from_ID_to_property(&but->rnapoin, but->rnaprop);
241   if (path == NULL) {
242     return false;
243   }
244
245   /* create driver */
246   fcu = verify_driver_fcurve(id, path, but->rnaindex, 1);
247   if (fcu) {
248     ChannelDriver *driver = fcu->driver;
249
250     if (driver) {
251       /* set type of driver */
252       driver->type = DRIVER_TYPE_PYTHON;
253
254       /* set the expression */
255       /* TODO: need some way of identifying variables used */
256       BLI_strncpy_utf8(driver->expression, str, sizeof(driver->expression));
257
258       /* updates */
259       BKE_driver_invalidate_expression(driver, true, false);
260       DEG_relations_tag_update(CTX_data_main(C));
261       WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME, NULL);
262       ok = true;
263     }
264   }
265
266   MEM_freeN(path);
267
268   return ok;
269 }
270
271 void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra)
272 {
273   Main *bmain = CTX_data_main(C);
274   ID *id;
275   bAction *action;
276   FCurve *fcu;
277   bool driven;
278   bool special;
279
280   fcu = ui_but_get_fcurve(but, NULL, &action, &driven, &special);
281
282   if (fcu == NULL) {
283     return;
284   }
285
286   if (special) {
287     /* NLA Strip property */
288     if (IS_AUTOKEY_ON(scene)) {
289       ReportList *reports = CTX_wm_reports(C);
290       ToolSettings *ts = scene->toolsettings;
291
292       insert_keyframe_direct(
293           reports, but->rnapoin, but->rnaprop, fcu, cfra, ts->keyframe_type, NULL, 0);
294       WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
295     }
296   }
297   else if (driven) {
298     /* Driver - Try to insert keyframe using the driver's input as the frame,
299      * making it easier to set up corrective drivers
300      */
301     if (IS_AUTOKEY_ON(scene)) {
302       ReportList *reports = CTX_wm_reports(C);
303       ToolSettings *ts = scene->toolsettings;
304
305       insert_keyframe_direct(reports,
306                              but->rnapoin,
307                              but->rnaprop,
308                              fcu,
309                              cfra,
310                              ts->keyframe_type,
311                              NULL,
312                              INSERTKEY_DRIVER);
313       WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
314     }
315   }
316   else {
317     id = but->rnapoin.id.data;
318
319     /* TODO: this should probably respect the keyingset only option for anim */
320     if (autokeyframe_cfra_can_key(scene, id)) {
321       Depsgraph *depsgraph = CTX_data_depsgraph(C);
322       ReportList *reports = CTX_wm_reports(C);
323       ToolSettings *ts = scene->toolsettings;
324       short flag = ANIM_get_keyframing_flags(scene, 1);
325
326       fcu->flag &= ~FCURVE_SELECTED;
327
328       /* Note: We use but->rnaindex instead of fcu->array_index,
329        *       because a button may control all items of an array at once.
330        *       E.g., color wheels (see T42567). */
331       BLI_assert((fcu->array_index == but->rnaindex) || (but->rnaindex == -1));
332       insert_keyframe(bmain,
333                       depsgraph,
334                       reports,
335                       id,
336                       action,
337                       ((fcu->grp) ? (fcu->grp->name) : (NULL)),
338                       fcu->rna_path,
339                       but->rnaindex,
340                       cfra,
341                       ts->keyframe_type,
342                       NULL,
343                       flag);
344
345       WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
346     }
347   }
348 }
349
350 void ui_but_anim_copy_driver(bContext *C)
351 {
352   /* this operator calls UI_context_active_but_prop_get */
353   WM_operator_name_call(C, "ANIM_OT_copy_driver_button", WM_OP_INVOKE_DEFAULT, NULL);
354 }
355
356 void ui_but_anim_paste_driver(bContext *C)
357 {
358   /* this operator calls UI_context_active_but_prop_get */
359   WM_operator_name_call(C, "ANIM_OT_paste_driver_button", WM_OP_INVOKE_DEFAULT, NULL);
360 }
361
362 void ui_but_anim_decorate_cb(bContext *C, void *arg_but, void *UNUSED(arg_dummy))
363 {
364   wmWindowManager *wm = CTX_wm_manager(C);
365   uiBut *but = arg_but;
366   but = but->prev;
367
368   /* FIXME(campbell), swapping active pointer is weak. */
369   SWAP(struct uiHandleButtonData *, but->active, but->next->active);
370   wm->op_undo_depth++;
371
372   if (but->flag & UI_BUT_DRIVEN) {
373     /* pass */
374     /* TODO: report? */
375   }
376   else if (but->flag & UI_BUT_ANIMATED_KEY) {
377     PointerRNA props_ptr;
378     wmOperatorType *ot = WM_operatortype_find("ANIM_OT_keyframe_delete_button", false);
379     WM_operator_properties_create_ptr(&props_ptr, ot);
380     RNA_boolean_set(&props_ptr, "all", but->rnaindex == -1);
381     WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr);
382     WM_operator_properties_free(&props_ptr);
383   }
384   else {
385     PointerRNA props_ptr;
386     wmOperatorType *ot = WM_operatortype_find("ANIM_OT_keyframe_insert_button", false);
387     WM_operator_properties_create_ptr(&props_ptr, ot);
388     RNA_boolean_set(&props_ptr, "all", but->rnaindex == -1);
389     WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr);
390     WM_operator_properties_free(&props_ptr);
391   }
392
393   SWAP(struct uiHandleButtonData *, but->active, but->next->active);
394   wm->op_undo_depth--;
395 }