Blender  V3.3
interface_anim.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 
11 #include "MEM_guardedalloc.h"
12 
13 #include "DNA_anim_types.h"
14 #include "DNA_scene_types.h"
15 #include "DNA_screen_types.h"
16 
17 #include "BLI_listbase.h"
18 #include "BLI_string.h"
19 #include "BLI_string_utf8.h"
20 #include "BLI_utildefines.h"
21 
22 #include "BKE_animsys.h"
23 #include "BKE_context.h"
24 #include "BKE_fcurve.h"
25 #include "BKE_fcurve_driver.h"
26 #include "BKE_global.h"
27 #include "BKE_main.h"
28 #include "BKE_nla.h"
29 
30 #include "DEG_depsgraph.h"
31 #include "DEG_depsgraph_build.h"
32 
33 #include "ED_keyframing.h"
34 
35 #include "UI_interface.h"
36 
37 #include "RNA_access.h"
38 #include "RNA_path.h"
39 
40 #include "WM_api.h"
41 #include "WM_types.h"
42 
43 #include "interface_intern.h"
44 
46  uiBut *but, AnimData **adt, bAction **action, bool *r_driven, bool *r_special)
47 {
48  /* for entire array buttons we check the first component, it's not perfect
49  * but works well enough in typical cases */
50  const int rnaindex = (but->rnaindex == -1) ? 0 : but->rnaindex;
51 
53  but->block->evil_C, &but->rnapoin, but->rnaprop, rnaindex, adt, action, r_driven, r_special);
54 }
55 
56 void ui_but_anim_flag(uiBut *but, const AnimationEvalContext *anim_eval_context)
57 {
58  AnimData *adt;
59  bAction *act;
60  FCurve *fcu;
61  bool driven;
62  bool special;
63 
66 
67  /* NOTE: "special" is reserved for special F-Curves stored on the animation data
68  * itself (which are used to animate properties of the animation data).
69  * We count those as "animated" too for now
70  */
71  fcu = ui_but_get_fcurve(but, &adt, &act, &driven, &special);
72 
73  if (fcu) {
74  if (!driven) {
75  /* Empty curves are ignored by the animation evaluation system. */
76  if (BKE_fcurve_is_empty(fcu)) {
77  return;
78  }
79 
80  but->flag |= UI_BUT_ANIMATED;
81 
82  /* T41525 - When the active action is a NLA strip being edited,
83  * we need to correct the frame number to "look inside" the
84  * remapped action
85  */
86  float cfra = anim_eval_context->eval_time;
87  if (adt) {
89  }
90 
91  if (fcurve_frame_has_keyframe(fcu, cfra, 0)) {
92  but->flag |= UI_BUT_ANIMATED_KEY;
93  }
94 
95  /* XXX: this feature is totally broken and useless with NLA */
96  if (adt == NULL || adt->nla_tracks.first == NULL) {
98  anim_eval_context, cfra);
99  if (fcurve_is_changed(but->rnapoin, but->rnaprop, fcu, &remapped_context)) {
101  }
102  }
103  }
104  else {
105  but->flag |= UI_BUT_DRIVEN;
106  }
107  }
108 }
109 
111 {
112  uiBut *but_iter = NULL;
113 
114  BLI_assert(UI_but_is_decorator(&but_decorate->but));
115  BLI_assert(but_decorate->rnapoin.data && but_decorate->rnaprop);
116 
118  &but_decorate->but.block->buttons, but_iter, but_decorate->but.prev) {
119  if (but_iter != (uiBut *)but_decorate &&
121  but_iter, &but_decorate->rnapoin, but_decorate->rnaprop, but_decorate->rnaindex)) {
122  return but_iter;
123  }
124  }
126  &but_decorate->but.block->buttons, but_iter, but_decorate->but.prev);
127 
128  return NULL;
129 }
130 
132 {
133  if (!decorator_but->rnapoin.data || !decorator_but->rnaprop) {
134  /* Nothing to do. */
135  return;
136  }
137 
138  const uiBut *but_anim = ui_but_anim_decorate_find_attached_button(decorator_but);
139  uiBut *but = &decorator_but->but;
140 
141  if (!but_anim) {
142  printf("Could not find button with matching property to decorate (%s.%s)\n",
143  RNA_struct_identifier(decorator_but->rnapoin.type),
144  RNA_property_identifier(decorator_but->rnaprop));
145  return;
146  }
147 
148  const int flag = but_anim->flag;
149 
150  if (flag & UI_BUT_DRIVEN) {
151  but->icon = ICON_DECORATE_DRIVER;
152  }
153  else if (flag & UI_BUT_ANIMATED_KEY) {
154  but->icon = ICON_DECORATE_KEYFRAME;
155  }
156  else if (flag & UI_BUT_ANIMATED) {
157  but->icon = ICON_DECORATE_ANIMATE;
158  }
159  else if (flag & UI_BUT_OVERRIDDEN) {
160  but->icon = ICON_DECORATE_OVERRIDE;
161  }
162  else {
163  but->icon = ICON_DECORATE;
164  }
165 
166  const int flag_copy = (UI_BUT_DISABLED | UI_BUT_INACTIVE);
167  but->flag = (but->flag & ~flag_copy) | (flag & flag_copy);
168 }
169 
170 bool ui_but_anim_expression_get(uiBut *but, char *str, size_t maxlen)
171 {
172  FCurve *fcu;
173  ChannelDriver *driver;
174  bool driven, special;
175 
176  fcu = ui_but_get_fcurve(but, NULL, NULL, &driven, &special);
177 
178  if (fcu && driven) {
179  driver = fcu->driver;
180 
181  if (driver && driver->type == DRIVER_TYPE_PYTHON) {
182  if (str) {
183  BLI_strncpy(str, driver->expression, maxlen);
184  }
185  return true;
186  }
187  }
188 
189  return false;
190 }
191 
192 bool ui_but_anim_expression_set(uiBut *but, const char *str)
193 {
194  FCurve *fcu;
195  ChannelDriver *driver;
196  bool driven, special;
197 
198  fcu = ui_but_get_fcurve(but, NULL, NULL, &driven, &special);
199 
200  if (fcu && driven) {
201  driver = fcu->driver;
202 
203  if (driver && (driver->type == DRIVER_TYPE_PYTHON)) {
204  bContext *C = but->block->evil_C;
205 
206  BLI_strncpy_utf8(driver->expression, str, sizeof(driver->expression));
207 
208  /* tag driver as needing to be recompiled */
209  BKE_driver_invalidate_expression(driver, true, false);
210 
211  /* clear invalid flags which may prevent this from working */
212  driver->flag &= ~DRIVER_FLAG_INVALID;
213  fcu->flag &= ~FCURVE_DISABLED;
214 
215  /* this notifier should update the Graph Editor and trigger depsgraph refresh? */
217 
219 
220  return true;
221  }
222  }
223 
224  return false;
225 }
226 
227 bool ui_but_anim_expression_create(uiBut *but, const char *str)
228 {
229  bContext *C = but->block->evil_C;
230  ID *id;
231  FCurve *fcu;
232  char *path;
233  bool ok = false;
234 
235  /* button must have RNA-pointer to a numeric-capable property */
236  if (ELEM(NULL, but->rnapoin.data, but->rnaprop)) {
237  if (G.debug & G_DEBUG) {
238  printf("ERROR: create expression failed - button has no RNA info attached\n");
239  }
240  return false;
241  }
242 
243  if (RNA_property_array_check(but->rnaprop) != 0) {
244  if (but->rnaindex == -1) {
245  if (G.debug & G_DEBUG) {
246  printf("ERROR: create expression failed - can't create expression for entire array\n");
247  }
248  return false;
249  }
250  }
251 
252  /* make sure we have animdata for this */
253  /* FIXME: until materials can be handled by depsgraph,
254  * don't allow drivers to be created for them */
255  id = but->rnapoin.owner_id;
256  if ((id == NULL) || (GS(id->name) == ID_MA) || (GS(id->name) == ID_TE)) {
257  if (G.debug & G_DEBUG) {
258  printf("ERROR: create expression failed - invalid data-block for adding drivers (%p)\n", id);
259  }
260  return false;
261  }
262 
263  /* get path */
264  path = RNA_path_from_ID_to_property(&but->rnapoin, but->rnaprop);
265  if (path == NULL) {
266  return false;
267  }
268 
269  /* create driver */
271  if (fcu) {
272  ChannelDriver *driver = fcu->driver;
273 
274  if (driver) {
275  /* set type of driver */
276  driver->type = DRIVER_TYPE_PYTHON;
277 
278  /* set the expression */
279  /* TODO: need some way of identifying variables used */
280  BLI_strncpy_utf8(driver->expression, str, sizeof(driver->expression));
281 
282  /* updates */
283  BKE_driver_invalidate_expression(driver, true, false);
286  ok = true;
287  }
288  }
289 
290  MEM_freeN(path);
291 
292  return ok;
293 }
294 
295 void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra)
296 {
297  ED_autokeyframe_property(C, scene, &but->rnapoin, but->rnaprop, but->rnaindex, cfra, true);
298 }
299 
301 {
302  /* this operator calls UI_context_active_but_prop_get */
303  WM_operator_name_call(C, "ANIM_OT_copy_driver_button", WM_OP_INVOKE_DEFAULT, NULL, NULL);
304 }
305 
307 {
308  /* this operator calls UI_context_active_but_prop_get */
309  WM_operator_name_call(C, "ANIM_OT_paste_driver_button", WM_OP_INVOKE_DEFAULT, NULL, NULL);
310 }
311 
312 void ui_but_anim_decorate_cb(bContext *C, void *arg_but, void *UNUSED(arg_dummy))
313 {
315  uiButDecorator *but_decorate = arg_but;
316  uiBut *but_anim = ui_but_anim_decorate_find_attached_button(but_decorate);
317 
318  if (!but_anim) {
319  return;
320  }
321 
322  /* FIXME(campbell), swapping active pointer is weak. */
323  SWAP(struct uiHandleButtonData *, but_anim->active, but_decorate->but.active);
324  wm->op_undo_depth++;
325 
326  if (but_anim->flag & UI_BUT_DRIVEN) {
327  /* pass */
328  /* TODO: report? */
329  }
330  else if (but_anim->flag & UI_BUT_ANIMATED_KEY) {
331  PointerRNA props_ptr;
332  wmOperatorType *ot = WM_operatortype_find("ANIM_OT_keyframe_delete_button", false);
334  RNA_boolean_set(&props_ptr, "all", but_anim->rnaindex == -1);
336  WM_operator_properties_free(&props_ptr);
337  }
338  else {
339  PointerRNA props_ptr;
340  wmOperatorType *ot = WM_operatortype_find("ANIM_OT_keyframe_insert_button", false);
342  RNA_boolean_set(&props_ptr, "all", but_anim->rnaindex == -1);
344  WM_operator_properties_free(&props_ptr);
345  }
346 
347  SWAP(struct uiHandleButtonData *, but_anim->active, but_decorate->but.active);
348  wm->op_undo_depth--;
349 }
AnimationEvalContext BKE_animsys_eval_context_construct_at(const AnimationEvalContext *anim_eval_context, float eval_time)
Definition: anim_sys.c:771
struct wmWindowManager * CTX_wm_manager(const bContext *C)
Definition: context.c:713
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1074
bool BKE_fcurve_is_empty(struct FCurve *fcu)
Definition: fcurve.c:2198
struct FCurve * BKE_fcurve_find_by_rna_context_ui(struct bContext *C, const struct PointerRNA *ptr, struct PropertyRNA *prop, int rnaindex, struct AnimData **r_animdata, struct bAction **r_action, bool *r_driven, bool *r_special)
void BKE_driver_invalidate_expression(struct ChannelDriver *driver, bool expr_changed, bool varname_changed)
@ G_DEBUG
Definition: BKE_global.h:174
@ NLATIME_CONVERT_UNMAP
Definition: BKE_nla.h:357
float BKE_nla_tweakedit_remap(struct AnimData *adt, float cframe, short mode)
Definition: nla.c:642
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define LISTBASE_CIRCULAR_BACKWARD_BEGIN(lb, lb_iter, lb_init)
Definition: BLI_listbase.h:325
#define LISTBASE_CIRCULAR_BACKWARD_END(lb, lb_iter, lb_init)
Definition: BLI_listbase.h:329
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
char * BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL(1
#define SWAP(type, a, b)
#define UNUSED(x)
#define ELEM(...)
void DEG_relations_tag_update(struct Main *bmain)
@ ID_TE
Definition: DNA_ID_enums.h:52
@ ID_MA
Definition: DNA_ID_enums.h:51
@ DRIVER_TYPE_PYTHON
@ DRIVER_FLAG_INVALID
@ FCURVE_DISABLED
@ DRIVER_FCURVE_KEYFRAMES
Read Guarded memory(de)allocation.
#define C
Definition: RandGen.cpp:25
@ UI_BUT_ANIMATED_CHANGED
Definition: UI_interface.h:297
@ UI_BUT_ANIMATED
Definition: UI_interface.h:198
@ UI_BUT_DISABLED
Definition: UI_interface.h:196
@ UI_BUT_INACTIVE
Definition: UI_interface.h:203
@ UI_BUT_OVERRIDDEN
Definition: UI_interface.h:231
@ UI_BUT_DRIVEN
Definition: UI_interface.h:200
@ UI_BUT_ANIMATED_KEY
Definition: UI_interface.h:199
#define UI_but_is_decorator(but)
Definition: UI_interface.h:611
#define NC_ANIMATION
Definition: WM_types.h:338
@ WM_OP_INVOKE_DEFAULT
Definition: WM_types.h:201
#define ND_KEYFRAME
Definition: WM_types.h:442
Scene scene
FCurve * verify_driver_fcurve(ID *id, const char rna_path[], const int array_index, eDriverFCurveCreationMode creation_mode)
Definition: drivers.c:50
#define str(s)
bool ui_but_rna_equals_ex(const uiBut *but, const PointerRNA *ptr, const PropertyRNA *prop, int index)
Definition: interface.cc:710
static FCurve * ui_but_get_fcurve(uiBut *but, AnimData **adt, bAction **action, bool *r_driven, bool *r_special)
bool ui_but_anim_expression_create(uiBut *but, const char *str)
void ui_but_anim_flag(uiBut *but, const AnimationEvalContext *anim_eval_context)
void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra)
void ui_but_anim_decorate_cb(bContext *C, void *arg_but, void *UNUSED(arg_dummy))
static uiBut * ui_but_anim_decorate_find_attached_button(uiButDecorator *but_decorate)
bool ui_but_anim_expression_get(uiBut *but, char *str, size_t maxlen)
void ui_but_anim_copy_driver(bContext *C)
void ui_but_anim_paste_driver(bContext *C)
void ui_but_anim_decorate_update_from_flag(uiButDecorator *decorator_but)
bool ui_but_anim_expression_set(uiBut *but, const char *str)
#define GS(x)
Definition: iris.c:225
bool fcurve_is_changed(PointerRNA ptr, PropertyRNA *prop, FCurve *fcu, const AnimationEvalContext *anim_eval_context)
Definition: keyframing.c:2909
bool fcurve_frame_has_keyframe(const FCurve *fcu, float frame, short filter)
Definition: keyframing.c:2883
bool ED_autokeyframe_property(bContext *C, Scene *scene, PointerRNA *ptr, PropertyRNA *prop, int rnaindex, float cfra, const bool only_if_property_keyed)
Definition: keyframing.c:3111
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
#define G(x, y, z)
const char * RNA_struct_identifier(const StructRNA *type)
Definition: rna_access.c:586
bool RNA_property_array_check(PropertyRNA *prop)
Definition: rna_access.c:1080
const char * RNA_property_identifier(const PropertyRNA *prop)
Definition: rna_access.c:1000
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
Definition: rna_access.c:4874
char * RNA_path_from_ID_to_property(const PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_path.cc:1127
ListBase nla_tracks
char expression[256]
ChannelDriver * driver
short flag
Definition: DNA_ID.h:368
char name[66]
Definition: DNA_ID.h:378
void * first
Definition: DNA_listBase.h:31
struct StructRNA * type
Definition: RNA_types.h:37
void * data
Definition: RNA_types.h:38
struct ID * owner_id
Definition: RNA_types.h:36
ListBase buttons
void * evil_C
struct PropertyRNA * rnaprop
struct PointerRNA rnapoin
struct uiBut * prev
struct uiHandleButtonData * active
uiBlock * block
BIFIconID icon
struct PropertyRNA * rnaprop
struct PointerRNA rnapoin
int WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
int WM_operator_name_call(bContext *C, const char *opstring, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
wmOperatorType * ot
Definition: wm_files.c:3479
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)
void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
Definition: wm_operators.c:661
void WM_operator_properties_free(PointerRNA *ptr)
Definition: wm_operators.c:783