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