Blender V4.3
editors/animation/keyframing.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2009 Blender Authors, Joshua Leung. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <cstddef>
10#include <cstdio>
11
12#include <fmt/format.h>
13
14#include "MEM_guardedalloc.h"
15
16#include "BLI_blenlib.h"
17
18#include "BLT_translation.hh"
19
20#include "DNA_ID.h"
21#include "DNA_action_types.h"
22#include "DNA_anim_types.h"
23#include "DNA_armature_types.h"
24#include "DNA_object_types.h"
25#include "DNA_scene_types.h"
26
27#include "BKE_action.hh"
28#include "BKE_anim_data.hh"
29#include "BKE_animsys.h"
30#include "BKE_armature.hh"
31#include "BKE_context.hh"
32#include "BKE_fcurve.hh"
33#include "BKE_global.hh"
34#include "BKE_idtype.hh"
35#include "BKE_lib_id.hh"
36#include "BKE_nla.hh"
37#include "BKE_report.hh"
38#include "BKE_scene.hh"
39
40#include "DEG_depsgraph.hh"
42
43#include "ED_anim_api.hh"
44#include "ED_keyframing.hh"
45#include "ED_object.hh"
46#include "ED_screen.hh"
47
48#include "ANIM_action.hh"
50#include "ANIM_action_legacy.hh"
51#include "ANIM_animdata.hh"
53#include "ANIM_driver.hh"
54#include "ANIM_fcurve.hh"
55#include "ANIM_keyframing.hh"
56#include "ANIM_keyingsets.hh"
57#include "ANIM_rna.hh"
58
59#include "UI_interface.hh"
60#include "UI_resources.hh"
61
62#include "WM_api.hh"
63#include "WM_types.hh"
64
65#include "RNA_access.hh"
66#include "RNA_define.hh"
67#include "RNA_enum_types.hh"
68#include "RNA_path.hh"
69#include "RNA_prototypes.hh"
70
71#include "anim_intern.hh"
72
74 PropertyRNA *prop,
75 Scene *scene);
76
78
79/* ******************************************* */
80/* Animation Data Validation */
81
83{
84 PointerRNA tmp_ptr;
85 PropertyRNA *prop;
86 int old_flag = fcu->flag;
87
88 if ((ptr->owner_id == nullptr) && (ptr->data == nullptr)) {
89 BKE_report(reports, RPT_ERROR, "No RNA pointer available to retrieve values for this F-curve");
90 return;
91 }
92
93 /* try to get property we should be affecting */
94 if (RNA_path_resolve_property(ptr, fcu->rna_path, &tmp_ptr, &prop) == false) {
95 /* property not found... */
96 const char *idname = (ptr->owner_id) ? ptr->owner_id->name : RPT_("<No ID pointer>");
97
98 BKE_reportf(reports,
100 "Could not update flags for this F-curve, as RNA path is invalid for the given ID "
101 "(ID = %s, path = %s)",
102 idname,
103 fcu->rna_path);
104 return;
105 }
106
107 /* update F-Curve flags */
109
110 if (old_flag != fcu->flag) {
111 /* Same as if keyframes had been changed */
113 }
114}
115
116/* ------------------------- Insert Key API ------------------------- */
117
118void ED_keyframes_add(FCurve *fcu, int num_keys_to_add)
119{
120 BLI_assert_msg(num_keys_to_add >= 0, "cannot remove keyframes with this function");
121
122 if (num_keys_to_add == 0) {
123 return;
124 }
125
126 fcu->bezt = static_cast<BezTriple *>(
127 MEM_recallocN(fcu->bezt, sizeof(BezTriple) * (fcu->totvert + num_keys_to_add)));
128 BezTriple *bezt = fcu->bezt + fcu->totvert; /* Pointer to the first new one. '*/
129
130 fcu->totvert += num_keys_to_add;
131
132 /* Iterate over the new keys to update their settings. */
133 while (num_keys_to_add--) {
134 /* Defaults, ignoring user-preference gives predictable results for API. */
135 bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
136 bezt->ipo = BEZT_IPO_BEZ;
137 bezt->h1 = bezt->h2 = HD_AUTO_ANIM;
138 bezt++;
139 }
140}
141
142/* ******************************************* */
143/* KEYFRAME MODIFICATION */
144
145/* mode for commonkey_modifykey */
146enum {
149} /*eCommonModifyKey_Modes*/;
150
157{
158 ScrArea *area = CTX_wm_area(C);
159 Scene *scene = CTX_data_scene(C);
160
161 /* if no area or active scene */
162 if (ELEM(nullptr, area, scene)) {
163 return false;
164 }
165
166 /* should be fine */
167 return true;
168}
169
170/* Insert Key Operator ------------------------ */
171
173{
174 Scene *scene = CTX_data_scene(C);
175 Object *obedit = CTX_data_edit_object(C);
176 bool ob_edit_mode = false;
177
178 const float cfra = BKE_scene_frame_get(scene);
179 const bool confirm = op->flag & OP_IS_INVOKE;
180 /* exit the edit mode to make sure that those object data properties that have been
181 * updated since the last switching to the edit mode will be keyframed correctly
182 */
183 if (obedit && ANIM_keyingset_find_id(ks, (ID *)obedit->data)) {
185 ob_edit_mode = true;
186 }
187
188 /* try to insert keyframes for the channels specified by KeyingSet */
189 const int num_channels = ANIM_apply_keyingset(
190 C, nullptr, ks, blender::animrig::ModifyKeyMode::INSERT, cfra);
191 if (G.debug & G_DEBUG) {
193 RPT_INFO,
194 "Keying set '%s' - successfully added %d keyframes",
195 ks->name,
196 num_channels);
197 }
198
199 /* restore the edit mode if necessary */
200 if (ob_edit_mode) {
202 }
203
204 /* report failure or do updates? */
205 if (num_channels < 0) {
206 BKE_report(op->reports, RPT_ERROR, "No suitable context info for active keying set");
207 return OPERATOR_CANCELLED;
208 }
209
210 if (num_channels > 0) {
211 /* send notifiers that keyframes have been changed */
213 }
214
215 if (confirm) {
216 /* if called by invoke (from the UI), make a note that we've inserted keyframes */
217 if (num_channels > 0) {
219 RPT_INFO,
220 "Successfully added %d keyframes for keying set '%s'",
221 num_channels,
222 ks->name);
223 }
224 else {
225 BKE_report(op->reports, RPT_WARNING, "Keying set failed to insert any keyframes");
226 }
227 }
228
229 return OPERATOR_FINISHED;
230}
231
233{
234 /* While you can cast the IDProperty* to a PropertyRNA* and pass it to the functions, this
235 * does not work because it will not have the right flags set. Instead the resolved
236 * PointerRNA and PropertyRNA need to be passed. */
237 if (!RNA_property_anim_editable(ptr, prop)) {
238 return false;
239 }
240
241 if (ELEM(id_prop->type,
242 eIDPropertyType::IDP_BOOLEAN,
243 eIDPropertyType::IDP_INT,
244 eIDPropertyType::IDP_FLOAT,
245 eIDPropertyType::IDP_DOUBLE))
246 {
247 return true;
248 }
249
250 if (id_prop->type == eIDPropertyType::IDP_ARRAY) {
251 if (ELEM(id_prop->subtype,
252 eIDPropertyType::IDP_BOOLEAN,
253 eIDPropertyType::IDP_INT,
254 eIDPropertyType::IDP_FLOAT,
255 eIDPropertyType::IDP_DOUBLE))
256 {
257 return true;
258 }
259 }
260
261 return false;
262}
263
265{
266 eRotationModes rotation_mode;
267 IDProperty *properties;
269
270 if (ptr->type == &RNA_PoseBone) {
271 bPoseChannel *pchan = static_cast<bPoseChannel *>(ptr->data);
272 rotation_mode = eRotationModes(pchan->rotmode);
273 properties = pchan->prop;
274 }
275 else if (ptr->type == &RNA_Object) {
276 Object *ob = static_cast<Object *>(ptr->data);
277 rotation_mode = eRotationModes(ob->rotmode);
278 properties = ob->id.properties;
279 }
280 else {
281 /* Pointer type not supported. */
282 return paths;
283 }
284
285 eKeyInsertChannels insert_channel_flags = eKeyInsertChannels(U.key_insert_channels);
286 if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_LOCATION) {
287 paths.append({"location"});
288 }
289 if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_ROTATION) {
290 switch (rotation_mode) {
291 case ROT_MODE_QUAT:
292 paths.append({"rotation_quaternion"});
293 break;
295 paths.append({"rotation_axis_angle"});
296 break;
297 case ROT_MODE_XYZ:
298 case ROT_MODE_XZY:
299 case ROT_MODE_YXZ:
300 case ROT_MODE_YZX:
301 case ROT_MODE_ZXY:
302 case ROT_MODE_ZYX:
303 paths.append({"rotation_euler"});
304 default:
305 break;
306 }
307 }
308 if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_SCALE) {
309 paths.append({"scale"});
310 }
311 if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_ROTATION_MODE) {
312 paths.append({"rotation_mode"});
313 }
314 if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_CUSTOM_PROPERTIES) {
315 if (properties) {
316 LISTBASE_FOREACH (IDProperty *, id_prop, &properties->data.group) {
317 PointerRNA resolved_ptr;
318 PropertyRNA *resolved_prop;
319 std::string path = id_prop->name;
320 /* Resolving the path twice, once as RNA property (without brackets, `"propname"`),
321 * and once as ID property (with brackets, `["propname"]`).
322 * This is required to support IDProperties that have been defined as part of an add-on.
323 * Those need to be animated through an RNA path without the brackets. */
324 bool is_resolved = RNA_path_resolve_property(
325 ptr, path.c_str(), &resolved_ptr, &resolved_prop);
326 if (!is_resolved) {
327 char name_escaped[MAX_IDPROP_NAME * 2];
328 BLI_str_escape(name_escaped, id_prop->name, sizeof(name_escaped));
329 path = fmt::format("[\"{}\"]", name_escaped);
330 is_resolved = RNA_path_resolve_property(
331 ptr, path.c_str(), &resolved_ptr, &resolved_prop);
332 }
333 if (!is_resolved) {
334 continue;
335 }
336 if (is_idproperty_keyable(id_prop, &resolved_ptr, resolved_prop)) {
337 paths.append({path});
338 }
339 }
340 }
341 }
342 return paths;
343}
344
345/* Fill the list with items depending on the mode of the context. */
347{
348 const eContextObjectMode context_mode = CTX_data_mode_enum(C);
349
350 switch (context_mode) {
351 case CTX_MODE_OBJECT: {
352 CTX_data_selected_objects(C, r_selection);
353 break;
354 }
355 case CTX_MODE_POSE: {
356 CTX_data_selected_pose_bones(C, r_selection);
357 break;
358 }
359 default:
360 return false;
361 }
362
363 return true;
364}
365
366static int insert_key(bContext *C, wmOperator *op)
367{
368 using namespace blender;
369
371 const bool found_selection = get_selection(C, &selection);
372 if (!found_selection) {
373 BKE_reportf(op->reports, RPT_ERROR, "Unsupported context mode");
374 return OPERATOR_CANCELLED;
375 }
376
377 if (selection.is_empty()) {
378 BKE_reportf(op->reports, RPT_WARNING, "Nothing selected to key");
379 return OPERATOR_CANCELLED;
380 }
381
382 Main *bmain = CTX_data_main(C);
383 Scene *scene = CTX_data_scene(C);
384 const float scene_frame = BKE_scene_frame_get(scene);
385
386 const eInsertKeyFlags insert_key_flags = animrig::get_keyframing_flags(scene);
388 scene->toolsettings->keyframe_type);
392
393 animrig::CombinedKeyingResult combined_result;
395 for (PointerRNA &id_ptr : selection) {
396 ID *selected_id = id_ptr.owner_id;
397 ids.add(selected_id);
398 if (!id_can_have_animdata(selected_id)) {
400 RPT_ERROR,
401 "Could not insert keyframe, as this type does not support animation data (ID = "
402 "%s)",
403 selected_id->name);
404 continue;
405 }
406 if (!BKE_id_is_editable(bmain, selected_id)) {
407 BKE_reportf(op->reports, RPT_ERROR, "'%s' is not editable", selected_id->name + 2);
408 continue;
409 }
410 Vector<RNAPath> rna_paths = construct_rna_paths(&id_ptr);
411
412 combined_result.merge(animrig::insert_keyframes(bmain,
413 &id_ptr,
414 std::nullopt,
415 rna_paths.as_span(),
416 scene_frame,
417 anim_eval_context,
418 key_type,
419 insert_key_flags));
420 }
421
422 if (combined_result.get_count(animrig::SingleKeyingResult::SUCCESS) == 0) {
423 combined_result.generate_reports(op->reports);
424 }
425
426 for (ID *id : ids) {
428 }
429
431
432 return OPERATOR_FINISHED;
433}
434
436{
438
439 Scene *scene = CTX_data_scene(C);
440 /* Use the active keying set if there is one. */
441 const int type = RNA_enum_get(op->ptr, "type");
443 if (ks) {
444 return insert_key_with_keyingset(C, op, ks);
445 }
446 return insert_key(C, op);
447}
448
449static int insert_key_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
450{
451 /* The depsgraph needs to be in an evaluated state to ensure the values we get from the
452 * properties are actually the values of the current frame. However we cannot do that in the exec
453 * function, as that would mean every call to the operator via python has to re-evaluate the
454 * depsgraph, causing performance regressions.*/
456 return insert_key_exec(C, op);
457}
458
460{
461 /* identifiers */
462 ot->name = "Insert Keyframe";
463 ot->idname = "ANIM_OT_keyframe_insert";
464 ot->description =
465 "Insert keyframes on the current frame using either the active keying set, or the user "
466 "preferences if no keying set is active";
467
468 /* callbacks */
472
473 /* flags */
475
476 /* Allows passing in a keying set when using the Python operator. */
478 ot->srna, "type", rna_enum_dummy_DEFAULT_items, 0, "Keying Set", "The Keying Set to use");
481 ot->prop = prop;
482}
483
485{
487
488 Scene *scene = CTX_data_scene(C);
490 if (ks == nullptr) {
491 return OPERATOR_CANCELLED;
492 }
493 return insert_key_with_keyingset(C, op, ks);
494}
495
497{
498 PropertyRNA *prop;
499
500 /* identifiers */
501 ot->name = "Insert Keyframe (by name)";
502 ot->idname = "ANIM_OT_keyframe_insert_by_name";
503 ot->description = "Alternate access to 'Insert Keyframe' for keymaps to use";
504
505 /* callbacks */
508
509 /* flags */
511
512 /* keyingset to use (idname) */
513 prop = RNA_def_string(
514 ot->srna, "type", nullptr, MAX_ID_NAME - 2, "Keying Set", "The Keying Set to use");
518 ot->prop = prop;
519}
520
521/* Insert Key Operator (With Menu) ------------------------ */
522/* This operator checks if a menu should be shown for choosing the KeyingSet to use,
523 * then calls the menu if necessary before
524 */
525
526static int insert_key_menu_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
527{
528 Scene *scene = CTX_data_scene(C);
529
530 /* When there is an active keying set and no request to prompt, keyframe immediately. */
531 if ((scene->active_keyingset != 0) && !RNA_boolean_get(op->ptr, "always_prompt")) {
532 /* Just call the exec() on the active keying-set. */
533 RNA_enum_set(op->ptr, "type", 0);
534 return op->type->exec(C, op);
535 }
536
537 /* Show a menu listing all keying-sets, the enum is expanded here to make use of the
538 * operator that accesses the keying-set by name. This is important for the ability
539 * to assign shortcuts to arbitrarily named keying sets. See #89560.
540 * These menu items perform the key-frame insertion (not this operator)
541 * hence the #OPERATOR_INTERFACE return. */
543 C, WM_operatortype_name(op->type, op->ptr).c_str(), ICON_NONE);
544 uiLayout *layout = UI_popup_menu_layout(pup);
545
546 /* Even though `ANIM_OT_keyframe_insert_menu` can show a menu in one line,
547 * prefer `ANIM_OT_keyframe_insert_by_name` so users can bind keys to specific
548 * keying sets by name in the key-map instead of the index which isn't stable. */
549 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "type");
550 const EnumPropertyItem *item_array = nullptr;
551 int totitem;
552 bool free;
553
554 RNA_property_enum_items_gettexted(C, op->ptr, prop, &item_array, &totitem, &free);
555
556 for (int i = 0; i < totitem; i++) {
557 const EnumPropertyItem *item = &item_array[i];
558 if (item->identifier[0] != '\0') {
559 uiItemStringO(layout,
560 item->name,
561 item->icon,
562 "ANIM_OT_keyframe_insert_by_name",
563 "type",
564 item->identifier);
565 }
566 else {
567 /* This enum shouldn't contain headings, assert there are none.
568 * NOTE: If in the future the enum includes them, additional layout code can be
569 * added to show them - although that doesn't seem likely. */
570 BLI_assert(item->name == nullptr);
571 uiItemS(layout);
572 }
573 }
574
575 if (free) {
576 MEM_freeN((void *)item_array);
577 }
578
579 UI_popup_menu_end(C, pup);
580
581 return OPERATOR_INTERFACE;
582}
583
585{
586 PropertyRNA *prop;
587
588 /* identifiers */
589 ot->name = "Insert Keyframe Menu";
590 ot->idname = "ANIM_OT_keyframe_insert_menu";
591 ot->description =
592 "Insert Keyframes for specified Keying Set, with menu of available Keying Sets if undefined";
593
594 /* callbacks */
598
599 /* flags */
601
602 /* keyingset to use (dynamic enum) */
603 prop = RNA_def_enum(
604 ot->srna, "type", rna_enum_dummy_DEFAULT_items, 0, "Keying Set", "The Keying Set to use");
607 ot->prop = prop;
608
609 /* whether the menu should always be shown
610 * - by default, the menu should only be shown when there is no active Keying Set (2.5 behavior),
611 * although in some cases it might be useful to always shown (pre 2.5 behavior)
612 */
613 prop = RNA_def_boolean(ot->srna, "always_prompt", false, "Always Show Menu", "");
615}
616
617/* Delete Key Operator ------------------------ */
618
620{
621 Scene *scene = CTX_data_scene(C);
623 if (ks == nullptr) {
624 return OPERATOR_CANCELLED;
625 }
626
627 return delete_key_using_keying_set(C, op, ks);
628}
629
631{
632 Scene *scene = CTX_data_scene(C);
633 float cfra = BKE_scene_frame_get(scene);
634 int num_channels;
635 const bool confirm = op->flag & OP_IS_INVOKE;
636
637 /* try to delete keyframes for the channels specified by KeyingSet */
638 num_channels = ANIM_apply_keyingset(
639 C, nullptr, ks, blender::animrig::ModifyKeyMode::DELETE, cfra);
640 if (G.debug & G_DEBUG) {
641 printf("KeyingSet '%s' - Successfully removed %d Keyframes\n", ks->name, num_channels);
642 }
643
644 /* report failure or do updates? */
645 if (num_channels < 0) {
646 BKE_report(op->reports, RPT_ERROR, "No suitable context info for active keying set");
647 return OPERATOR_CANCELLED;
648 }
649
650 if (num_channels > 0) {
652 }
653
654 if (confirm) {
655 /* if called by invoke (from the UI), make a note that we've removed keyframes */
656 if (num_channels > 0) {
658 RPT_INFO,
659 "Successfully removed %d keyframes for keying set '%s'",
660 num_channels,
661 ks->name);
662 }
663 else {
664 BKE_report(op->reports, RPT_WARNING, "Keying set failed to remove any keyframes");
665 }
666 }
667 return OPERATOR_FINISHED;
668}
669
671{
672 PropertyRNA *prop;
673
674 /* identifiers */
675 ot->name = "Delete Keying-Set Keyframe";
676 ot->idname = "ANIM_OT_keyframe_delete";
677 ot->description =
678 "Delete keyframes on the current frame for all properties in the specified Keying Set";
679
680 /* callbacks */
683
684 /* flags */
686
687 /* keyingset to use (dynamic enum) */
688 prop = RNA_def_enum(
689 ot->srna, "type", rna_enum_dummy_DEFAULT_items, 0, "Keying Set", "The Keying Set to use");
692 ot->prop = prop;
693}
694
696{
697 PropertyRNA *prop;
698
699 /* identifiers */
700 ot->name = "Delete Keying-Set Keyframe (by name)";
701 ot->idname = "ANIM_OT_keyframe_delete_by_name";
702 ot->description = "Alternate access to 'Delete Keyframe' for keymaps to use";
703
704 /* callbacks */
707
708 /* flags */
710
711 /* keyingset to use (idname) */
712 prop = RNA_def_string(
713 ot->srna, "type", nullptr, MAX_ID_NAME - 2, "Keying Set", "The Keying Set to use");
717 ot->prop = prop;
718}
719
720/* Delete Key Operator ------------------------ */
721/* NOTE: Although this version is simpler than the more generic version for KeyingSets,
722 * it is more useful for animators working in the 3D view.
723 */
724
725/* While in pose mode, the selection of bones has to be considered. */
726static bool can_delete_fcurve(FCurve *fcu, Object *ob)
727{
728 bool can_delete = false;
729 /* in pose mode, only delete the F-Curve if it belongs to a selected bone */
730 if (ob->mode & OB_MODE_POSE) {
731 if (fcu->rna_path) {
732 /* Get bone-name, and check if this bone is selected. */
733 bPoseChannel *pchan = nullptr;
734 char bone_name[sizeof(pchan->name)];
735 if (BLI_str_quoted_substr(fcu->rna_path, "pose.bones[", bone_name, sizeof(bone_name))) {
736 pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
737 /* Delete if bone is selected. */
738 if ((pchan) && (pchan->bone)) {
739 if (pchan->bone->flag & BONE_SELECTED) {
740 can_delete = true;
741 }
742 }
743 }
744 }
745 }
746 else {
747 /* object mode - all of Object's F-Curves are affected */
748 /* TODO: this logic isn't solid. Only delete FCurves of the object, not of bones in this case.
749 */
750 can_delete = true;
751 }
752
753 return can_delete;
754}
755
757{
758 using namespace blender::animrig;
759 bool changed = false;
760
761 CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
762 /* just those in active action... */
763 if ((ob->adt) && (ob->adt->action)) {
764 AnimData *adt = ob->adt;
765 bAction *dna_action = adt->action;
766 FCurve *fcu, *fcn;
767
768 Action &action = dna_action->wrap();
769 if (action.is_action_layered()) {
770 blender::Vector<FCurve *> fcurves_to_delete;
771 foreach_fcurve_in_action_slot(action, adt->slot_handle, [&](FCurve &fcurve) {
772 if (can_delete_fcurve(&fcurve, ob)) {
773 fcurves_to_delete.append(&fcurve);
774 }
775 });
776 for (FCurve *fcurve : fcurves_to_delete) {
777 action_fcurve_remove(action, *fcurve);
778 }
779 }
780 else {
781 for (fcu = static_cast<FCurve *>(dna_action->curves.first); fcu; fcu = fcn) {
782 fcn = fcu->next;
783 /* delete F-Curve completely */
784 if (can_delete_fcurve(fcu, ob)) {
787 changed = true;
788 }
789 }
790 }
791
792 /* Delete the action itself if it is empty. */
794 changed = true;
795 }
796 }
797 }
799
800 if (!changed) {
801 return OPERATOR_CANCELLED;
802 }
803
804 /* send updates */
806
807 return OPERATOR_FINISHED;
808}
809
810static int clear_anim_v3d_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
811{
812 if (RNA_boolean_get(op->ptr, "confirm")) {
813 return WM_operator_confirm_ex(C,
814 op,
815 IFACE_("Remove animation from selected objects?"),
816 nullptr,
819 false);
820 }
821 return clear_anim_v3d_exec(C, op);
822}
823
825{
826 /* identifiers */
827 ot->name = "Remove Animation";
828 ot->description = "Remove all keyframe animation for selected objects";
829 ot->idname = "ANIM_OT_keyframe_clear_v3d";
830
831 /* callbacks */
834
836
837 /* flags */
840}
841
842static bool can_delete_key(FCurve *fcu, Object *ob, ReportList *reports)
843{
844 /* don't touch protected F-Curves */
845 if (BKE_fcurve_is_protected(fcu)) {
846 BKE_reportf(reports,
848 "Not deleting keyframe for locked F-Curve '%s', object '%s'",
849 fcu->rna_path,
850 ob->id.name + 2);
851 return false;
852 }
853
854 /* Special exception for bones, as this makes this operator more convenient to use
855 * NOTE: This is only done in pose mode.
856 * In object mode, we're dealing with the entire object.
857 * TODO: While this means bone animation is not deleted of all bones while in pose mode. Running
858 * the code on the armature object WILL delete keys of all bones.
859 */
860 if (ob->mode & OB_MODE_POSE) {
861 bPoseChannel *pchan = nullptr;
862
863 /* Get bone-name, and check if this bone is selected. */
864 char bone_name[sizeof(pchan->name)];
865 if (!BLI_str_quoted_substr(fcu->rna_path, "pose.bones[", bone_name, sizeof(bone_name))) {
866 return false;
867 }
868 pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
869
870 /* skip if bone is not selected */
871 if ((pchan) && (pchan->bone)) {
872 /* bones are only selected/editable if visible... */
873 bArmature *arm = (bArmature *)ob->data;
874
875 /* skipping - not visible on currently visible layers */
876 if (!ANIM_bonecoll_is_visible_pchan(arm, pchan)) {
877 return false;
878 }
879 /* skipping - is currently hidden */
880 if (pchan->bone->flag & BONE_HIDDEN_P) {
881 return false;
882 }
883
884 /* selection flag... */
885 if ((pchan->bone->flag & BONE_SELECTED) == 0) {
886 return false;
887 }
888 }
889 }
890
891 return true;
892}
893
895{
896 using namespace blender::animrig;
897 Scene *scene = CTX_data_scene(C);
898 const float cfra = BKE_scene_frame_get(scene);
899
900 int selected_objects_len = 0;
901 int selected_objects_success_len = 0;
902 int success_multi = 0;
903
904 const bool confirm = op->flag & OP_IS_INVOKE;
905
906 CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
907 int success = 0;
908
909 selected_objects_len += 1;
910
911 /* just those in active action... */
912 if ((ob->adt) && (ob->adt->action)) {
913 AnimData *adt = ob->adt;
914 bAction *act = adt->action;
915 const float cfra_unmap = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP);
916
917 Action &action = act->wrap();
918 if (action.is_action_layered()) {
919 blender::Vector<FCurve *> modified_fcurves;
920 foreach_fcurve_in_action_slot(action, adt->slot_handle, [&](FCurve &fcurve) {
921 if (!can_delete_key(&fcurve, ob, op->reports)) {
922 return;
923 }
924 if (blender::animrig::fcurve_delete_keyframe_at_time(&fcurve, cfra_unmap)) {
925 modified_fcurves.append(&fcurve);
926 }
927 });
928
929 success += modified_fcurves.size();
930 for (FCurve *fcurve : modified_fcurves) {
931 if (BKE_fcurve_is_empty(fcurve)) {
932 action_fcurve_remove(action, *fcurve);
933 }
934 }
935 }
936 else {
937 FCurve *fcn;
938 for (FCurve *fcu = static_cast<FCurve *>(act->curves.first); fcu; fcu = fcn) {
939 fcn = fcu->next;
940 if (!can_delete_key(fcu, ob, op->reports)) {
941 continue;
942 }
943 /* Delete keyframes on current frame
944 * WARNING: this can delete the next F-Curve, hence the "fcn" copying.
945 */
946 success += delete_keyframe_fcurve_legacy(adt, fcu, cfra_unmap);
947 }
948 }
949
950 if (ob->adt->action) {
951 /* The Action might have been unassigned, if it is legacy and the last
952 * F-Curve was removed. */
953 DEG_id_tag_update(&ob->adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH);
954 }
955 }
956
957 /* Only for reporting. */
958 if (success) {
959 selected_objects_success_len += 1;
960 success_multi += success;
961 }
962
964 }
966
967 if (selected_objects_success_len) {
968 /* send updates */
970 }
971
972 if (confirm) {
973 /* if called by invoke (from the UI), make a note that we've removed keyframes */
974 if (selected_objects_success_len) {
975 BKE_reportf(op->reports,
976 RPT_INFO,
977 "%d object(s) successfully had %d keyframes removed",
978 selected_objects_success_len,
979 success_multi);
980 }
981 else {
983 op->reports, RPT_ERROR, "No keyframes removed from %d object(s)", selected_objects_len);
984 }
985 }
986 return OPERATOR_FINISHED;
987}
988
990{
991 Scene *scene = CTX_data_scene(C);
993
994 if (ks == nullptr) {
996 }
997
998 return delete_key_using_keying_set(C, op, ks);
999}
1000
1001static int delete_key_v3d_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
1002{
1003 if (RNA_boolean_get(op->ptr, "confirm")) {
1004 return WM_operator_confirm_ex(C,
1005 op,
1006 IFACE_("Delete keyframes from selected objects?"),
1007 nullptr,
1008 IFACE_("Delete"),
1010 false);
1011 }
1012 return delete_key_v3d_exec(C, op);
1013}
1014
1016{
1017 /* identifiers */
1018 ot->name = "Delete Keyframe";
1019 ot->description = "Remove keyframes on current frame for selected objects and bones";
1020 ot->idname = "ANIM_OT_keyframe_delete_v3d";
1021
1022 /* callbacks */
1025
1027
1028 /* flags */
1031}
1032
1033/* Insert Key Button Operator ------------------------ */
1034
1036{
1037 using namespace blender::animrig;
1038 Main *bmain = CTX_data_main(C);
1039 Scene *scene = CTX_data_scene(C);
1040 ToolSettings *ts = scene->toolsettings;
1041 PointerRNA ptr = {nullptr};
1042 PropertyRNA *prop = nullptr;
1043 uiBut *but;
1046 bool changed = false;
1047 int index;
1048 const bool all = RNA_boolean_get(op->ptr, "all");
1050
1051 flag = get_keyframing_flags(scene);
1052
1053 if (!(but = UI_context_active_but_prop_get(C, &ptr, &prop, &index))) {
1054 /* pass event on if no active button found */
1056 }
1057
1058 if ((ptr.owner_id && ptr.data && prop) && RNA_property_anim_editable(&ptr, prop)) {
1059 if (ptr.type == &RNA_NlaStrip) {
1060 /* Handle special properties for NLA Strips, whose F-Curves are stored on the
1061 * strips themselves. These are stored separately or else the properties will
1062 * not have any effect.
1063 */
1064 NlaStrip *strip = static_cast<NlaStrip *>(ptr.data);
1065 FCurve *fcu = BKE_fcurve_find(&strip->fcurves, RNA_property_identifier(prop), index);
1066
1067 if (fcu) {
1068 changed = insert_keyframe_direct(op->reports,
1069 ptr,
1070 prop,
1071 fcu,
1072 &anim_eval_context,
1074 nullptr,
1075 eInsertKeyFlags(0));
1076 }
1077 else {
1078 BKE_report(op->reports,
1079 RPT_ERROR,
1080 "This property cannot be animated as it will not get updated correctly");
1081 }
1082 }
1083 else if (UI_but_flag_is_set(but, UI_BUT_DRIVEN)) {
1084 /* Driven property - Find driver */
1085 FCurve *fcu;
1086 bool driven, special;
1087
1089 C, &ptr, prop, index, nullptr, nullptr, &driven, &special);
1090
1091 if (fcu && driven) {
1092 const float driver_frame = evaluate_driver_from_rna_pointer(
1093 &anim_eval_context, &ptr, prop, fcu);
1095 CTX_data_depsgraph_pointer(C), driver_frame);
1096 changed = insert_keyframe_direct(op->reports,
1097 ptr,
1098 prop,
1099 fcu,
1100 &remapped_context,
1102 nullptr,
1104 }
1105 }
1106 else {
1107 /* standard properties */
1108 if (const std::optional<std::string> path = RNA_path_from_ID_to_property(&ptr, prop)) {
1109 const char *identifier = RNA_property_identifier(prop);
1110 const std::optional<blender::StringRefNull> group = default_channel_group_for_path(
1111 &ptr, identifier);
1112
1114
1115 /* NOTE: `index == -1` is a magic number, meaning either "operate on all
1116 * elements" or "not an array property". */
1117 const std::optional<int> array_index = (all || index < 0) ? std::nullopt :
1118 std::optional(index);
1120 CombinedKeyingResult result = insert_keyframes(bmain,
1121 &owner_ptr,
1122 group,
1123 {{*path, {}, array_index}},
1124 std::nullopt,
1125 anim_eval_context,
1127 flag);
1128 changed = result.get_count(SingleKeyingResult::SUCCESS) != 0;
1129 }
1130 else {
1131 BKE_report(op->reports,
1133 "Failed to resolve path to property, "
1134 "try manually specifying this using a Keying Set instead");
1135 }
1136 }
1137 }
1138 else {
1139 if (prop && !RNA_property_anim_editable(&ptr, prop)) {
1140 BKE_reportf(op->reports,
1142 "\"%s\" property cannot be animated",
1144 }
1145 else {
1146 BKE_reportf(op->reports,
1148 "Button doesn't appear to have any property information attached (ptr.data = "
1149 "%p, prop = %p)",
1150 ptr.data,
1151 (void *)prop);
1152 }
1153 }
1154
1155 if (changed) {
1156 ID *id = ptr.owner_id;
1157 AnimData *adt = BKE_animdata_from_id(id);
1158 if (adt->action != nullptr) {
1160 }
1162
1163 /* send updates */
1165
1166 /* send notifiers that keyframes have been changed */
1168 }
1169
1170 return (changed) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1171}
1172
1174{
1175 /* identifiers */
1176 ot->name = "Insert Keyframe (Buttons)";
1177 ot->idname = "ANIM_OT_keyframe_insert_button";
1178 ot->description = "Insert a keyframe for current UI-active property";
1179
1180 /* callbacks */
1183
1184 /* flags */
1186
1187 /* properties */
1188 RNA_def_boolean(ot->srna, "all", true, "All", "Insert a keyframe for all element of the array");
1189}
1190
1191/* Delete Key Button Operator ------------------------ */
1192
1194{
1195 Scene *scene = CTX_data_scene(C);
1196 PointerRNA ptr = {nullptr};
1197 PropertyRNA *prop = nullptr;
1198 Main *bmain = CTX_data_main(C);
1199 const float cfra = BKE_scene_frame_get(scene);
1200 bool changed = false;
1201 int index;
1202 const bool all = RNA_boolean_get(op->ptr, "all");
1203
1204 if (!UI_context_active_but_prop_get(C, &ptr, &prop, &index)) {
1205 /* pass event on if no active button found */
1207 }
1208
1209 if (ptr.owner_id && ptr.data && prop) {
1211 /* Handle special properties for NLA Strips, whose F-Curves are stored on the
1212 * strips themselves. These are stored separately or else the properties will
1213 * not have any effect.
1214 */
1215 ID *id = ptr.owner_id;
1216 NlaStrip *strip = static_cast<NlaStrip *>(ptr.data);
1217 FCurve *fcu = BKE_fcurve_find(&strip->fcurves, RNA_property_identifier(prop), 0);
1218
1219 if (fcu) {
1220 if (BKE_fcurve_is_protected(fcu)) {
1222 op->reports,
1224 "Not deleting keyframe for locked F-Curve for NLA Strip influence on %s - %s '%s'",
1225 strip->name,
1226 BKE_idtype_idcode_to_name(GS(id->name)),
1227 id->name + 2);
1228 }
1229 else {
1230 /* remove the keyframe directly
1231 * NOTE: cannot use delete_keyframe_fcurve(), as that will free the curve,
1232 * and delete_keyframe() expects the FCurve to be part of an action
1233 */
1234 bool found = false;
1235 int i;
1236
1237 /* try to find index of beztriple to get rid of */
1238 i = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, cfra, fcu->totvert, &found);
1239 if (found) {
1240 /* delete the key at the index (will sanity check + do recalc afterwards) */
1241 BKE_fcurve_delete_key(fcu, i);
1243 changed = true;
1244 }
1245 }
1246 }
1247 }
1248 else {
1249 /* standard properties */
1250 if (const std::optional<std::string> path = RNA_path_from_ID_to_property(&ptr, prop)) {
1251 RNAPath rna_path = {path->c_str(), std::nullopt, index};
1252 if (all) {
1253 /* nullopt indicates operating on the entire array (or the property itself otherwise). */
1254 rna_path.index = std::nullopt;
1255 }
1256
1258 bmain, op->reports, ptr.owner_id, rna_path, cfra) != 0;
1259 }
1260 else if (G.debug & G_DEBUG) {
1261 printf("Button Delete-Key: no path to property\n");
1262 }
1263 }
1264 }
1265 else if (G.debug & G_DEBUG) {
1266 printf("ptr.data = %p, prop = %p\n", ptr.data, (void *)prop);
1267 }
1268
1269 if (changed) {
1270 /* send updates */
1272
1273 /* send notifiers that keyframes have been changed */
1275 }
1276
1277 return (changed) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1278}
1279
1281{
1282 /* identifiers */
1283 ot->name = "Delete Keyframe (Buttons)";
1284 ot->idname = "ANIM_OT_keyframe_delete_button";
1285 ot->description = "Delete current keyframe of current UI-active property";
1286
1287 /* callbacks */
1290
1291 /* flags */
1293
1294 /* properties */
1295 RNA_def_boolean(ot->srna, "all", true, "All", "Delete keyframes from all elements of the array");
1296}
1297
1298/* Clear Key Button Operator ------------------------ */
1299
1301{
1302 PointerRNA ptr = {nullptr};
1303 PropertyRNA *prop = nullptr;
1304 Main *bmain = CTX_data_main(C);
1305 bool changed = false;
1306 int index;
1307 const bool all = RNA_boolean_get(op->ptr, "all");
1308
1309 if (!UI_context_active_but_prop_get(C, &ptr, &prop, &index)) {
1310 /* pass event on if no active button found */
1312 }
1313
1314 if (ptr.owner_id && ptr.data && prop) {
1315 if (const std::optional<std::string> path = RNA_path_from_ID_to_property(&ptr, prop)) {
1316 RNAPath rna_path = {path->c_str(), std::nullopt, index};
1317 if (all) {
1318 /* nullopt indicates operating on the entire array (or the property itself otherwise). */
1319 rna_path.index = std::nullopt;
1320 }
1321
1322 changed |= (blender::animrig::clear_keyframe(bmain, op->reports, ptr.owner_id, rna_path) !=
1323 0);
1324 }
1325 else if (G.debug & G_DEBUG) {
1326 printf("Button Clear-Key: no path to property\n");
1327 }
1328 }
1329 else if (G.debug & G_DEBUG) {
1330 printf("ptr.data = %p, prop = %p\n", ptr.data, (void *)prop);
1331 }
1332
1333 if (changed) {
1334 /* send updates */
1336
1337 /* send notifiers that keyframes have been changed */
1339 }
1340
1341 return (changed) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1342}
1343
1345{
1346 /* identifiers */
1347 ot->name = "Clear Keyframe (Buttons)";
1348 ot->idname = "ANIM_OT_keyframe_clear_button";
1349 ot->description = "Clear all keyframes on the currently active property";
1350
1351 /* callbacks */
1354
1355 /* flags */
1357
1358 /* properties */
1359 RNA_def_boolean(ot->srna, "all", true, "All", "Clear keyframes from all elements of the array");
1360}
1361
1362/* ******************************************* */
1363/* KEYFRAME DETECTION */
1364
1365/* --------------- API/Per-Datablock Handling ------------------- */
1366
1367bool fcurve_frame_has_keyframe(const FCurve *fcu, float frame)
1368{
1369 /* quick sanity check */
1370 if (ELEM(nullptr, fcu, fcu->bezt)) {
1371 return false;
1372 }
1373
1374 if ((fcu->flag & FCURVE_MUTED) == 0) {
1375 bool replace;
1376 int i = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, frame, fcu->totvert, &replace);
1377
1378 /* BKE_fcurve_bezt_binarysearch_index will set replace to be 0 or 1
1379 * - obviously, 1 represents a match
1380 */
1381 if (replace) {
1382 /* sanity check: 'i' may in rare cases exceed arraylen */
1383 if ((i >= 0) && (i < fcu->totvert)) {
1384 return true;
1385 }
1386 }
1387 }
1388
1389 return false;
1390}
1391
1393 PropertyRNA *prop,
1394 FCurve *fcu,
1395 const AnimationEvalContext *anim_eval_context)
1396{
1397 PathResolvedRNA anim_rna;
1398 anim_rna.ptr = ptr;
1399 anim_rna.prop = prop;
1400 anim_rna.prop_index = fcu->array_index;
1401
1402 int index = fcu->array_index;
1404
1405 float fcurve_val = calculate_fcurve(&anim_rna, fcu, anim_eval_context);
1406 float cur_val = (index >= 0 && index < values.size()) ? values[index] : 0.0f;
1407
1408 return !compare_ff_relative(fcurve_val, cur_val, FLT_EPSILON, 64);
1409}
1410
1418static bool assigned_action_has_keyframe_at(AnimData &adt, float frame)
1419{
1420 /* can only find if there is data */
1421 if (adt.action == nullptr) {
1422 return false;
1423 }
1424
1425 if (adt.action->flag & ACT_MUTED) {
1426 return false;
1427 }
1428
1429 /* loop over F-Curves, using binary-search to try to find matches
1430 * - this assumes that keyframes are only beztriples
1431 */
1433 /* only check if there are keyframes (currently only of type BezTriple) */
1434 if (fcu->bezt && fcu->totvert) {
1435 if (fcurve_frame_has_keyframe(fcu, frame)) {
1436 return true;
1437 }
1438 }
1439 }
1440
1441 /* nothing found */
1442 return false;
1443}
1444
1445/* Checks whether an Object has a keyframe for a given frame */
1446static bool object_frame_has_keyframe(Object *ob, float frame)
1447{
1448 /* error checking */
1449 if (ob == nullptr) {
1450 return false;
1451 }
1452
1453 /* check its own animation data - specifically, the action it contains */
1454 if ((ob->adt) && (ob->adt->action)) {
1455 /* #41525 - When the active action is a NLA strip being edited,
1456 * we need to correct the frame number to "look inside" the
1457 * remapped action
1458 */
1459 float ob_frame = BKE_nla_tweakedit_remap(ob->adt, frame, NLATIME_CONVERT_UNMAP);
1460
1461 if (assigned_action_has_keyframe_at(*ob->adt, ob_frame)) {
1462 return true;
1463 }
1464 }
1465
1466 /* nothing found */
1467 return false;
1468}
1469
1470/* --------------- API ------------------- */
1471
1472bool id_frame_has_keyframe(ID *id, float frame)
1473{
1474 /* sanity checks */
1475 if (id == nullptr) {
1476 return false;
1477 }
1478
1479 /* perform special checks for 'macro' types */
1480 switch (GS(id->name)) {
1481 case ID_OB: /* object */
1482 return object_frame_has_keyframe((Object *)id, frame);
1483#if 0
1484 /* XXX TODO... for now, just use 'normal' behavior */
1485 case ID_SCE: /* scene */
1486 break;
1487#endif
1488 default: /* 'normal type' */
1489 {
1490 AnimData *adt = BKE_animdata_from_id(id);
1491
1492 /* only check keyframes in active action */
1493 if (adt) {
1494 return assigned_action_has_keyframe_at(*adt, frame);
1495 }
1496 break;
1497 }
1498 }
1499
1500 /* no keyframe found */
1501 return false;
1502}
1503
1504/* -------------------------------------------------------------------- */
1510{
1511 KeyingSet *ks = nullptr;
1512 const int prop_type = RNA_property_type(prop);
1513 if (prop_type == PROP_ENUM) {
1514 int type = RNA_property_enum_get(op->ptr, prop);
1515 ks = ANIM_keyingset_get_from_enum_type(scene, type);
1516 if (ks == nullptr) {
1517 BKE_report(op->reports, RPT_ERROR, "No active Keying Set");
1518 }
1519 }
1520 else if (prop_type == PROP_STRING) {
1521 char type_id[MAX_ID_NAME - 2];
1522 RNA_property_string_get(op->ptr, prop, type_id);
1523
1524 if (STREQ(type_id, "__ACTIVE__")) {
1525 ks = ANIM_keyingset_get_from_enum_type(scene, scene->active_keyingset);
1526 }
1527 else {
1528 ks = ANIM_keyingset_get_from_idname(scene, type_id);
1529 }
1530
1531 if (ks == nullptr) {
1532 BKE_reportf(op->reports, RPT_ERROR, "Keying set '%s' not found", type_id);
1533 }
1534 }
1535 else {
1536 BLI_assert(0);
1537 }
1538 return ks;
1539}
1540
Functions and classes to work with Actions.
Functionality to iterate an Action in various ways.
Functions for backward compatibility with the legacy Action API.
Functions to work with AnimData.
C++ functions to deal with Armature collections (i.e. the successor of bone layers).
bool ANIM_bonecoll_is_visible_pchan(const bArmature *armature, const bPoseChannel *pchan)
Functions to work with drivers.
Functions to modify FCurves.
Functions to insert, delete or modify keyframes.
Functionality to interact with keying sets.
Helper functions for animation to interact with the RNA system.
Blender kernel action and pose functionality.
bPoseChannel * BKE_pose_channel_find_name(const bPose *pose, const char *name)
bool id_can_have_animdata(const ID *id)
Definition anim_data.cc:79
AnimData * BKE_animdata_from_id(const ID *id)
Definition anim_data.cc:89
AnimationEvalContext BKE_animsys_eval_context_construct(struct Depsgraph *depsgraph, float eval_time) ATTR_WARN_UNUSED_RESULT
Definition anim_sys.cc:734
#define CTX_DATA_BEGIN(C, Type, instance, member)
eContextObjectMode
@ CTX_MODE_OBJECT
@ CTX_MODE_POSE
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Object * CTX_data_edit_object(const bContext *C)
bool CTX_data_selected_objects(const bContext *C, blender::Vector< PointerRNA > *list)
Main * CTX_data_main(const bContext *C)
bool CTX_data_selected_pose_bones(const bContext *C, blender::Vector< PointerRNA > *list)
#define CTX_DATA_END
enum eContextObjectMode CTX_data_mode_enum(const bContext *C)
int BKE_fcurve_bezt_binarysearch_index(const BezTriple array[], float frame, int arraylen, bool *r_replace)
void BKE_fcurve_handles_recalc(FCurve *fcu)
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)
FCurve * BKE_fcurve_find(ListBase *list, const char rna_path[], int array_index)
bool BKE_fcurve_is_empty(const FCurve *fcu)
bool BKE_fcurve_is_protected(const FCurve *fcu)
float calculate_fcurve(PathResolvedRNA *anim_rna, FCurve *fcu, const AnimationEvalContext *anim_eval_context)
void BKE_fcurve_delete_key(FCurve *fcu, int index)
@ G_DEBUG
const char * BKE_idtype_idcode_to_name(short idcode)
Definition idtype.cc:168
bool BKE_id_is_editable(const Main *bmain, const ID *id)
Definition lib_id.cc:2456
float BKE_nla_tweakedit_remap(AnimData *adt, float cframe, short mode)
@ NLATIME_CONVERT_UNMAP
Definition BKE_nla.hh:513
bool BKE_nlastrip_has_curves_for_property(const PointerRNA *ptr, const PropertyRNA *prop)
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:125
float BKE_scene_frame_get(const Scene *scene)
Definition scene.cc:2331
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
void BLI_kdtree_nd_ free(KDTree *tree)
#define LISTBASE_FOREACH(type, var, list)
MINLINE int compare_ff_relative(float a, float b, float max_diff, int max_ulps)
bool bool BLI_str_quoted_substr(const char *__restrict str, const char *__restrict prefix, char *result, size_t result_maxncpy)
Definition string.c:517
size_t BLI_str_escape(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
#define ELEM(...)
#define STREQ(a, b)
#define RPT_(msgid)
#define CTX_IFACE_(context, msgid)
#define BLT_I18NCONTEXT_OPERATOR_DEFAULT
#define IFACE_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
ID and Library types, which are fundamental for SDNA.
@ ID_RECALC_TRANSFORM
Definition DNA_ID.h:1021
@ ID_RECALC_ANIMATION_NO_FLUSH
Definition DNA_ID.h:1143
#define MAX_ID_NAME
Definition DNA_ID.h:377
#define MAX_IDPROP_NAME
Definition DNA_ID.h:185
@ ID_SCE
@ ID_OB
@ ACT_MUTED
eRotationModes
@ ROT_MODE_XZY
@ ROT_MODE_QUAT
@ ROT_MODE_ZXY
@ ROT_MODE_AXISANGLE
@ ROT_MODE_ZYX
@ ROT_MODE_XYZ
@ ROT_MODE_YXZ
@ ROT_MODE_YZX
eInsertKeyFlags
@ INSERTKEY_NOFLAGS
@ FCURVE_MUTED
@ BONE_SELECTED
@ BONE_HIDDEN_P
@ HD_AUTO_ANIM
@ BEZT_IPO_BEZ
eBezTriple_KeyframeType
@ OB_MODE_EDIT
@ OB_MODE_POSE
@ OB_MODE_OBJECT
Object is a sort of wrapper for general info.
eKeyInsertChannels
@ USER_ANIM_KEY_CHANNEL_ROTATION_MODE
@ USER_ANIM_KEY_CHANNEL_SCALE
@ USER_ANIM_KEY_CHANNEL_ROTATION
@ USER_ANIM_KEY_CHANNEL_LOCATION
@ USER_ANIM_KEY_CHANNEL_CUSTOM_PROPERTIES
@ OPERATOR_PASS_THROUGH
bool ED_operator_areaactive(bContext *C)
Read Guarded memory(de)allocation.
#define MEM_recallocN(vmemh, len)
@ PROP_STRING_SEARCH_SUGGESTION
Definition RNA_types.hh:584
@ PROP_ENUM
Definition RNA_types.hh:69
@ PROP_STRING
Definition RNA_types.hh:68
@ PROP_HIDDEN
Definition RNA_types.hh:239
void UI_context_update_anim_flag(const bContext *C)
void UI_popup_menu_end(bContext *C, uiPopupMenu *pup)
void uiItemS(uiLayout *layout)
uiPopupMenu * UI_popup_menu_begin(bContext *C, const char *title, int icon) ATTR_NONNULL()
uiBut * UI_context_active_but_prop_get(const bContext *C, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
uiLayout * UI_popup_menu_layout(uiPopupMenu *pup)
void uiItemStringO(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, const char *value)
bool UI_but_flag_is_set(uiBut *but, int flag)
@ UI_BUT_DRIVEN
@ ALERT_ICON_NONE
@ OPTYPE_INTERNAL
Definition WM_types.hh:182
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define NC_ANIMATION
Definition WM_types.hh:355
#define NA_ADDED
Definition WM_types.hh:552
#define NA_EDITED
Definition WM_types.hh:550
#define NA_REMOVED
Definition WM_types.hh:553
#define ND_KEYS
Definition WM_types.hh:430
#define ND_KEYFRAME
Definition WM_types.hh:461
#define NC_OBJECT
Definition WM_types.hh:346
void ANIM_deselect_keys_in_animation_editors(bContext *C)
Definition anim_deps.cc:472
unsigned int U
Definition btGjkEpa3.h:78
bool add(const Key &key)
Definition BLI_set.hh:248
void append(const T &value)
void merge(const CombinedKeyingResult &other)
int get_count(const SingleKeyingResult result) const
void generate_reports(ReportList *reports, eReportType report_level=RPT_ERROR)
#define printf
#define SELECT
const Depsgraph * depsgraph
static bool is_idproperty_keyable(IDProperty *id_prop, PointerRNA *ptr, PropertyRNA *prop)
void ANIM_OT_keyframe_insert_menu(wmOperatorType *ot)
static int delete_key_v3d_invoke(bContext *C, wmOperator *op, const wmEvent *)
bool fcurve_is_changed(PointerRNA ptr, PropertyRNA *prop, FCurve *fcu, const AnimationEvalContext *anim_eval_context)
Lesser Keyframe Checking API call.
static int clear_anim_v3d_invoke(bContext *C, wmOperator *op, const wmEvent *)
static int insert_key_exec(bContext *C, wmOperator *op)
static int delete_key_exec(bContext *C, wmOperator *op)
static int insert_key_button_exec(bContext *C, wmOperator *op)
void ANIM_OT_keyframe_insert(wmOperatorType *ot)
static int delete_key_button_exec(bContext *C, wmOperator *op)
void ANIM_OT_keyframe_clear_button(wmOperatorType *ot)
void ANIM_OT_keyframe_insert_by_name(wmOperatorType *ot)
static int clear_key_button_exec(bContext *C, wmOperator *op)
void ANIM_OT_keyframe_delete(wmOperatorType *ot)
void ED_keyframes_add(FCurve *fcu, int num_keys_to_add)
static int insert_key_invoke(bContext *C, wmOperator *op, const wmEvent *)
void ANIM_OT_keyframe_clear_v3d(wmOperatorType *ot)
static bool can_delete_key(FCurve *fcu, Object *ob, ReportList *reports)
bool fcurve_frame_has_keyframe(const FCurve *fcu, float frame)
Lesser Keyframe Checking API call.
void ANIM_OT_keyframe_insert_button(wmOperatorType *ot)
static bool object_frame_has_keyframe(Object *ob, float frame)
static KeyingSet * keyingset_get_from_op_with_error(wmOperator *op, PropertyRNA *prop, Scene *scene)
void update_autoflags_fcurve(FCurve *fcu, bContext *C, ReportList *reports, PointerRNA *ptr)
Lesser Key-framing API call.
static int insert_key_menu_invoke(bContext *C, wmOperator *op, const wmEvent *)
static int keyframe_insert_with_keyingset_exec(bContext *C, wmOperator *op)
static bool get_selection(bContext *C, blender::Vector< PointerRNA > *r_selection)
static bool modify_key_op_poll(bContext *C)
static int clear_anim_v3d_exec(bContext *C, wmOperator *)
static int insert_key_with_keyingset(bContext *C, wmOperator *op, KeyingSet *ks)
void ANIM_OT_keyframe_delete_v3d(wmOperatorType *ot)
static blender::Vector< RNAPath > construct_rna_paths(PointerRNA *ptr)
static bool assigned_action_has_keyframe_at(AnimData &adt, float frame)
static int delete_key_v3d_without_keying_set(bContext *C, wmOperator *op)
static bool can_delete_fcurve(FCurve *fcu, Object *ob)
void ANIM_OT_keyframe_delete_button(wmOperatorType *ot)
bool id_frame_has_keyframe(ID *id, float frame)
Main Keyframe Checking API call.
void ANIM_OT_keyframe_delete_by_name(wmOperatorType *ot)
static int delete_key_using_keying_set(bContext *C, wmOperator *op, KeyingSet *ks)
static int delete_key_v3d_exec(bContext *C, wmOperator *op)
static int insert_key(bContext *C, wmOperator *op)
#define GS(x)
Definition iris.cc:202
void ANIM_keyingset_visit_for_search_no_poll(const bContext *C, PointerRNA *, PropertyRNA *, const char *, blender::FunctionRef< void(StringPropertySearchVisitParams)> visit_fn)
bool ANIM_keyingset_find_id(KeyingSet *keyingset, ID *id)
KeyingSet * ANIM_scene_get_active_keyingset(const Scene *scene)
KeyingSet * ANIM_keyingset_get_from_idname(Scene *scene, const char *idname)
KeyingSet * ANIM_keyingset_get_from_enum_type(Scene *scene, int type)
const EnumPropertyItem * ANIM_keying_sets_enum_itemf(bContext *C, PointerRNA *, PropertyRNA *, bool *r_free)
int ANIM_apply_keyingset(bContext *C, blender::Vector< PointerRNA > *sources, KeyingSet *keyingset, const blender::animrig::ModifyKeyMode mode, const float cfra)
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
#define G(x, y, z)
Vector< FCurve * > fcurves_for_assigned_action(AnimData *adt)
void update_autoflags_fcurve_direct(FCurve *fcu, PropertyRNA *prop)
Vector< float > get_rna_values(PointerRNA *ptr, PropertyRNA *prop)
Definition anim_rna.cc:16
int clear_keyframe(Main *bmain, ReportList *reports, ID *id, const RNAPath &rna_path)
int delete_keyframe(Main *bmain, ReportList *reports, ID *id, const RNAPath &rna_path, float cfra)
Main Delete Key-Framing API call.
bool fcurve_delete_keyframe_at_time(FCurve *fcurve, float time)
bool animdata_remove_empty_action(AnimData *adt)
Definition animdata.cc:317
void animdata_fcurve_delete(bAnimContext *ac, AnimData *adt, FCurve *fcu)
Definition animdata.cc:253
bool mode_set(bContext *C, eObjectMode mode)
GPU_SHADER_INTERFACE_INFO(overlay_edit_curve_handle_iface, "vert").flat(Type pos vertex_in(1, Type::UINT, "data") .vertex_out(overlay_edit_curve_handle_iface) .geometry_layout(PrimitiveIn Frequency::GEOMETRY storage_buf(1, Qualifier::READ, "uint", "data[]", Frequency::GEOMETRY) .push_constant(Type Frequency::GEOMETRY selection[]
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
PropertyType RNA_property_type(PropertyRNA *prop)
void RNA_property_enum_items_gettexted(bContext *C, PointerRNA *ptr, PropertyRNA *prop, const EnumPropertyItem **r_item, int *r_totitem, bool *r_free)
bool RNA_property_anim_editable(const PointerRNA *ptr, PropertyRNA *prop_orig)
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
std::string RNA_property_string_get(PointerRNA *ptr, PropertyRNA *prop)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
void RNA_enum_set(PointerRNA *ptr, const char *name, int value)
int RNA_enum_get(PointerRNA *ptr, const char *name)
const char * RNA_property_identifier(const PropertyRNA *prop)
PointerRNA RNA_id_pointer_create(ID *id)
PropertyRNA * RNA_def_string(StructOrFunctionRNA *cont_, const char *identifier, const char *default_value, const int maxlen, const char *ui_name, const char *ui_description)
void RNA_def_property_string_search_func_runtime(PropertyRNA *prop, StringPropertySearchFunc search_fn, const eStringPropertySearchFlag search_flag)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc)
std::optional< std::string > RNA_path_from_ID_to_property(const PointerRNA *ptr, PropertyRNA *prop)
Definition rna_path.cc:1166
bool RNA_path_resolve_property(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
Definition rna_path.cc:553
const EnumPropertyItem rna_enum_dummy_DEFAULT_items[]
Definition rna_rna.cc:35
bAction * action
int32_t slot_handle
const char * identifier
Definition RNA_types.hh:506
const char * name
Definition RNA_types.hh:510
struct FCurve * next
char * rna_path
BezTriple * bezt
int array_index
unsigned int totvert
ListBase group
Definition DNA_ID.h:146
IDPropertyData data
Definition DNA_ID.h:168
char subtype
Definition DNA_ID.h:159
char type
Definition DNA_ID.h:154
Definition DNA_ID.h:413
IDProperty * properties
Definition DNA_ID.h:456
char name[66]
Definition DNA_ID.h:425
char name[64]
ListBase fcurves
char name[64]
struct bPose * pose
struct AnimData * adt
PointerRNA ptr
Definition RNA_types.hh:56
PropertyRNA * prop
Definition RNA_types.hh:57
ID * owner_id
Definition RNA_types.hh:40
StructRNA * type
Definition RNA_types.hh:41
void * data
Definition RNA_types.hh:42
const char * name
std::optional< int > index
Definition RNA_path.hh:66
IDProperty * prop
struct Bone * bone
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
const char * idname
Definition WM_types.hh:992
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
PropertyRNA * prop
Definition WM_types.hh:1092
StructRNA * srna
Definition WM_types.hh:1080
struct ReportList * reports
struct wmOperatorType * type
struct PointerRNA * ptr
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition wm_files.cc:4126
wmOperatorType * ot
Definition wm_files.cc:4125
void WM_operator_properties_confirm_or_exec(wmOperatorType *ot)
std::string WM_operatortype_name(wmOperatorType *ot, PointerRNA *properties)
int WM_operator_confirm_ex(bContext *C, wmOperator *op, const char *title, const char *message, const char *confirm_text, int icon, bool cancel_default)
uint8_t flag
Definition wm_window.cc:138