Blender V4.5
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
8
9#include <cstdio>
10
11#include <fmt/format.h>
12
13#include "MEM_guardedalloc.h"
14
15#include "BLI_string.h"
16
17#include "BLT_translation.hh"
18
19#include "DNA_ID.h"
20#include "DNA_anim_types.h"
21#include "DNA_armature_types.h"
22#include "DNA_scene_types.h"
23
24#include "BKE_action.hh"
25#include "BKE_anim_data.hh"
26#include "BKE_animsys.h"
27#include "BKE_armature.hh"
28#include "BKE_context.hh"
29#include "BKE_fcurve.hh"
30#include "BKE_global.hh"
31#include "BKE_idtype.hh"
32#include "BKE_lib_id.hh"
33#include "BKE_nla.hh"
34#include "BKE_report.hh"
35#include "BKE_scene.hh"
36
37#include "DEG_depsgraph.hh"
39
40#include "ED_anim_api.hh"
41#include "ED_keyframing.hh"
42#include "ED_object.hh"
43#include "ED_screen.hh"
44
45#include "ANIM_action.hh"
47#include "ANIM_animdata.hh"
48#include "ANIM_armature.hh"
50#include "ANIM_driver.hh"
51#include "ANIM_fcurve.hh"
52#include "ANIM_keyframing.hh"
53#include "ANIM_keyingsets.hh"
54#include "ANIM_rna.hh"
55
56#include "UI_interface.hh"
57#include "UI_resources.hh"
58
59#include "WM_api.hh"
60#include "WM_types.hh"
61
62#include "RNA_access.hh"
63#include "RNA_define.hh"
64#include "RNA_enum_types.hh"
65#include "RNA_prototypes.hh"
66
67#include "anim_intern.hh"
68
70 PropertyRNA *prop,
71 Scene *scene);
72
74
75/* ******************************************* */
76/* Animation Data Validation */
77
79{
80 PointerRNA tmp_ptr;
81 PropertyRNA *prop;
82 int old_flag = fcu->flag;
83
84 if ((ptr->owner_id == nullptr) && (ptr->data == nullptr)) {
85 BKE_report(reports, RPT_ERROR, "No RNA pointer available to retrieve values for this F-curve");
86 return;
87 }
88
89 /* try to get property we should be affecting */
90 if (RNA_path_resolve_property(ptr, fcu->rna_path, &tmp_ptr, &prop) == false) {
91 /* property not found... */
92 const char *idname = (ptr->owner_id) ? ptr->owner_id->name : RPT_("<No ID pointer>");
93
96 "Could not update flags for this F-curve, as RNA path is invalid for the given ID "
97 "(ID = %s, path = %s)",
98 idname,
99 fcu->rna_path);
100 return;
101 }
102
103 /* update F-Curve flags */
105
106 if (old_flag != fcu->flag) {
107 /* Same as if keyframes had been changed */
109 }
110}
111
112/* ------------------------- Insert Key API ------------------------- */
113
114void ED_keyframes_add(FCurve *fcu, int num_keys_to_add)
115{
116 BLI_assert_msg(num_keys_to_add >= 0, "cannot remove keyframes with this function");
117
118 if (num_keys_to_add == 0) {
119 return;
120 }
121
122 fcu->bezt = static_cast<BezTriple *>(
123 MEM_recallocN(fcu->bezt, sizeof(BezTriple) * (fcu->totvert + num_keys_to_add)));
124 BezTriple *bezt = fcu->bezt + fcu->totvert; /* Pointer to the first new one. */
125
126 fcu->totvert += num_keys_to_add;
127
128 /* Iterate over the new keys to update their settings. */
129 while (num_keys_to_add--) {
130 /* Defaults, ignoring user-preference gives predictable results for API. */
131 bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
132 bezt->ipo = BEZT_IPO_BEZ;
133 bezt->h1 = bezt->h2 = HD_AUTO_ANIM;
134 bezt++;
135 }
136}
137
138/* ******************************************* */
139/* KEYFRAME MODIFICATION */
140
141/* mode for commonkey_modifykey */
142enum {
145} /*eCommonModifyKey_Modes*/;
146
153{
154 ScrArea *area = CTX_wm_area(C);
155 Scene *scene = CTX_data_scene(C);
156
157 /* if no area or active scene */
158 if (ELEM(nullptr, area, scene)) {
159 return false;
160 }
161
162 /* should be fine */
163 return true;
164}
165
166/* Insert Key Operator ------------------------ */
167
169{
170 Scene *scene = CTX_data_scene(C);
171 Object *obedit = CTX_data_edit_object(C);
172 bool ob_edit_mode = false;
173
174 const float cfra = BKE_scene_frame_get(scene);
175 const bool confirm = op->flag & OP_IS_INVOKE;
176 /* exit the edit mode to make sure that those object data properties that have been
177 * updated since the last switching to the edit mode will be keyframed correctly
178 */
179 if (obedit && blender::animrig::keyingset_find_id(ks, static_cast<ID *>(obedit->data))) {
181 ob_edit_mode = true;
182 }
183
184 /* try to insert keyframes for the channels specified by KeyingSet */
185 const int num_channels = blender::animrig::apply_keyingset(
186 C, nullptr, ks, blender::animrig::ModifyKeyMode::INSERT, cfra);
187 if (G.debug & G_DEBUG) {
189 RPT_INFO,
190 "Keying set '%s' - successfully added %d keyframes",
191 ks->name,
192 num_channels);
193 }
194
195 /* restore the edit mode if necessary */
196 if (ob_edit_mode) {
198 }
199
200 /* report failure or do updates? */
201 if (num_channels < 0) {
202 BKE_report(op->reports, RPT_ERROR, "No suitable context info for active keying set");
203 return OPERATOR_CANCELLED;
204 }
205
206 if (num_channels > 0) {
207 /* send notifiers that keyframes have been changed */
209 }
210
211 if (confirm) {
212 /* if called by invoke (from the UI), make a note that we've inserted keyframes */
213 if (num_channels > 0) {
215 RPT_INFO,
216 "Successfully added %d keyframes for keying set '%s'",
217 num_channels,
218 ks->name);
219 }
220 else {
221 BKE_report(op->reports, RPT_WARNING, "Keying set failed to insert any keyframes");
222 }
223 }
224
225 return OPERATOR_FINISHED;
226}
227
229{
230 eRotationModes rotation_mode;
232
233 if (ptr->type == &RNA_PoseBone) {
234 bPoseChannel *pchan = static_cast<bPoseChannel *>(ptr->data);
235 rotation_mode = eRotationModes(pchan->rotmode);
236 }
237 else if (ptr->type == &RNA_Object) {
238 Object *ob = static_cast<Object *>(ptr->data);
239 rotation_mode = eRotationModes(ob->rotmode);
240 }
241 else {
242 /* Pointer type not supported. */
243 return paths;
244 }
245
246 eKeyInsertChannels insert_channel_flags = eKeyInsertChannels(U.key_insert_channels);
247 if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_LOCATION) {
248 paths.append({"location"});
249 }
250 if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_ROTATION) {
251 switch (rotation_mode) {
252 case ROT_MODE_QUAT:
253 paths.append({"rotation_quaternion"});
254 break;
256 paths.append({"rotation_axis_angle"});
257 break;
258 case ROT_MODE_XYZ:
259 case ROT_MODE_XZY:
260 case ROT_MODE_YXZ:
261 case ROT_MODE_YZX:
262 case ROT_MODE_ZXY:
263 case ROT_MODE_ZYX:
264 paths.append({"rotation_euler"});
265 default:
266 break;
267 }
268 }
269 if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_SCALE) {
270 paths.append({"scale"});
271 }
272 if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_ROTATION_MODE) {
273 paths.append({"rotation_mode"});
274 }
275
276 if (insert_channel_flags & USER_ANIM_KEY_CHANNEL_CUSTOM_PROPERTIES) {
278 }
279 return paths;
280}
281
282/* Fill the list with items depending on the mode of the context. */
284{
285 const eContextObjectMode context_mode = CTX_data_mode_enum(C);
286
287 switch (context_mode) {
288 case CTX_MODE_OBJECT: {
289 CTX_data_selected_objects(C, r_selection);
290 break;
291 }
292 case CTX_MODE_POSE: {
293 CTX_data_selected_pose_bones(C, r_selection);
294 break;
295 }
296 default:
297 return false;
298 }
299
300 return true;
301}
302
304{
305 using namespace blender;
306
308 const bool found_selection = get_selection(C, &selection);
309 if (!found_selection) {
310 BKE_reportf(op->reports, RPT_ERROR, "Unsupported context mode");
311 return OPERATOR_CANCELLED;
312 }
313
314 if (selection.is_empty()) {
315 BKE_reportf(op->reports, RPT_WARNING, "Nothing selected to key");
316 return OPERATOR_CANCELLED;
317 }
318
319 Main *bmain = CTX_data_main(C);
320 Scene *scene = CTX_data_scene(C);
321 const float scene_frame = BKE_scene_frame_get(scene);
322
323 const eInsertKeyFlags insert_key_flags = animrig::get_keyframing_flags(scene);
329
330 animrig::CombinedKeyingResult combined_result;
332 for (PointerRNA &id_ptr : selection) {
333 ID *selected_id = id_ptr.owner_id;
334 ids.add(selected_id);
335 if (!id_can_have_animdata(selected_id)) {
337 RPT_ERROR,
338 "Could not insert keyframe, as this type does not support animation data (ID = "
339 "%s)",
340 selected_id->name);
341 continue;
342 }
343 if (!BKE_id_is_editable(bmain, selected_id)) {
344 BKE_reportf(op->reports, RPT_ERROR, "'%s' is not editable", selected_id->name + 2);
345 continue;
346 }
347 Vector<RNAPath> rna_paths = construct_rna_paths(&id_ptr);
348
349 combined_result.merge(animrig::insert_keyframes(bmain,
350 &id_ptr,
351 std::nullopt,
352 rna_paths.as_span(),
353 scene_frame,
354 anim_eval_context,
355 key_type,
356 insert_key_flags));
357 }
358
359 if (combined_result.get_count(animrig::SingleKeyingResult::SUCCESS) == 0) {
360 combined_result.generate_reports(op->reports);
361 }
362
363 for (ID *id : ids) {
365 }
366
368
369 return OPERATOR_FINISHED;
370}
371
373{
375
376 Scene *scene = CTX_data_scene(C);
377 /* Use the active keying set if there is one. */
378 const int type = RNA_enum_get(op->ptr, "type");
380 if (ks) {
381 return insert_key_with_keyingset(C, op, ks);
382 }
383 return insert_key(C, op);
384}
385
387{
388 /* The depsgraph needs to be in an evaluated state to ensure the values we get from the
389 * properties are actually the values of the current frame. However we cannot do that in the exec
390 * function, as that would mean every call to the operator via python has to re-evaluate the
391 * depsgraph, causing performance regressions. */
393 return insert_key_exec(C, op);
394}
395
397{
398 /* identifiers */
399 ot->name = "Insert Keyframe";
400 ot->idname = "ANIM_OT_keyframe_insert";
401 ot->description =
402 "Insert keyframes on the current frame using either the active keying set, or the user "
403 "preferences if no keying set is active";
404
405 /* callbacks */
406 ot->invoke = insert_key_invoke;
407 ot->exec = insert_key_exec;
408 ot->poll = modify_key_op_poll;
409
410 /* flags */
412
413 /* Allows passing in a keying set when using the Python operator. */
415 ot->srna, "type", rna_enum_dummy_DEFAULT_items, 0, "Keying Set", "The Keying Set to use");
418 ot->prop = prop;
419}
420
422{
424
425 Scene *scene = CTX_data_scene(C);
427 if (ks == nullptr) {
428 return OPERATOR_CANCELLED;
429 }
430 return insert_key_with_keyingset(C, op, ks);
431}
432
434{
435 PropertyRNA *prop;
436
437 /* identifiers */
438 ot->name = "Insert Keyframe (by name)";
439 ot->idname = "ANIM_OT_keyframe_insert_by_name";
440 ot->description = "Alternate access to 'Insert Keyframe' for keymaps to use";
441
442 /* callbacks */
444 ot->poll = modify_key_op_poll;
445
446 /* flags */
448
449 /* keyingset to use (idname) */
450 prop = RNA_def_string(
451 ot->srna, "type", nullptr, MAX_ID_NAME - 2, "Keying Set", "The Keying Set to use");
455 ot->prop = prop;
456}
457
458/* Insert Key Operator (With Menu) ------------------------ */
459/* This operator checks if a menu should be shown for choosing the KeyingSet to use,
460 * then calls the menu if necessary before
461 */
462
464 wmOperator *op,
465 const wmEvent * /*event*/)
466{
467 Scene *scene = CTX_data_scene(C);
468
469 /* When there is an active keying set and no request to prompt, keyframe immediately. */
470 if ((scene->active_keyingset != 0) && !RNA_boolean_get(op->ptr, "always_prompt")) {
471 /* Just call the exec() on the active keying-set. */
472 RNA_enum_set(op->ptr, "type", 0);
473 return op->type->exec(C, op);
474 }
475
476 /* Show a menu listing all keying-sets, the enum is expanded here to make use of the
477 * operator that accesses the keying-set by name. This is important for the ability
478 * to assign shortcuts to arbitrarily named keying sets. See #89560.
479 * These menu items perform the key-frame insertion (not this operator)
480 * hence the #OPERATOR_INTERFACE return. */
482 C, WM_operatortype_name(op->type, op->ptr).c_str(), ICON_NONE);
483 uiLayout *layout = UI_popup_menu_layout(pup);
484
485 /* Even though `ANIM_OT_keyframe_insert_menu` can show a menu in one line,
486 * prefer `ANIM_OT_keyframe_insert_by_name` so users can bind keys to specific
487 * keying sets by name in the key-map instead of the index which isn't stable. */
488 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "type");
489 const EnumPropertyItem *item_array = nullptr;
490 int totitem;
491 bool free;
492
493 RNA_property_enum_items_gettexted(C, op->ptr, prop, &item_array, &totitem, &free);
494
495 for (int i = 0; i < totitem; i++) {
496 const EnumPropertyItem *item = &item_array[i];
497 if (item->identifier[0] != '\0') {
498 PointerRNA op_ptr = layout->op("ANIM_OT_keyframe_insert_by_name", item->name, item->icon);
499 RNA_string_set(&op_ptr, "type", item->identifier);
500 }
501 else {
502 /* This enum shouldn't contain headings, assert there are none.
503 * NOTE: If in the future the enum includes them, additional layout code can be
504 * added to show them - although that doesn't seem likely. */
505 BLI_assert(item->name == nullptr);
506 layout->separator();
507 }
508 }
509
510 if (free) {
511 MEM_freeN(item_array);
512 }
513
514 UI_popup_menu_end(C, pup);
515
516 return OPERATOR_INTERFACE;
517}
518
520{
521 PropertyRNA *prop;
522
523 /* identifiers */
524 ot->name = "Insert Keyframe Menu";
525 ot->idname = "ANIM_OT_keyframe_insert_menu";
526 ot->description =
527 "Insert Keyframes for specified Keying Set, with menu of available Keying Sets if undefined";
528
529 /* callbacks */
530 ot->invoke = insert_key_menu_invoke;
533
534 /* flags */
536
537 /* keyingset to use (dynamic enum) */
538 prop = RNA_def_enum(
539 ot->srna, "type", rna_enum_dummy_DEFAULT_items, 0, "Keying Set", "The Keying Set to use");
542 ot->prop = prop;
543
544 /* whether the menu should always be shown
545 * - by default, the menu should only be shown when there is no active Keying Set (2.5 behavior),
546 * although in some cases it might be useful to always shown (pre 2.5 behavior)
547 */
548 prop = RNA_def_boolean(ot->srna, "always_prompt", false, "Always Show Menu", "");
550}
551
552/* Delete Key Operator ------------------------ */
553
555{
556 Scene *scene = CTX_data_scene(C);
558 if (ks == nullptr) {
559 return OPERATOR_CANCELLED;
560 }
561
562 return delete_key_using_keying_set(C, op, ks);
563}
564
566{
567 Scene *scene = CTX_data_scene(C);
568 float cfra = BKE_scene_frame_get(scene);
569 int num_channels;
570 const bool confirm = op->flag & OP_IS_INVOKE;
571
572 /* try to delete keyframes for the channels specified by KeyingSet */
575 if (G.debug & G_DEBUG) {
576 printf("KeyingSet '%s' - Successfully removed %d Keyframes\n", ks->name, num_channels);
577 }
578
579 /* report failure or do updates? */
580 if (num_channels < 0) {
581 BKE_report(op->reports, RPT_ERROR, "No suitable context info for active keying set");
582 return OPERATOR_CANCELLED;
583 }
584
585 if (num_channels > 0) {
587 }
588
589 if (confirm) {
590 /* if called by invoke (from the UI), make a note that we've removed keyframes */
591 if (num_channels > 0) {
593 RPT_INFO,
594 "Successfully removed %d keyframes for keying set '%s'",
595 num_channels,
596 ks->name);
597 }
598 else {
599 BKE_report(op->reports, RPT_WARNING, "Keying set failed to remove any keyframes");
600 }
601 }
602 return OPERATOR_FINISHED;
603}
604
606{
607 PropertyRNA *prop;
608
609 /* identifiers */
610 ot->name = "Delete Keying-Set Keyframe";
611 ot->idname = "ANIM_OT_keyframe_delete";
612 ot->description =
613 "Delete keyframes on the current frame for all properties in the specified Keying Set";
614
615 /* callbacks */
616 ot->exec = delete_key_exec;
617 ot->poll = modify_key_op_poll;
618
619 /* flags */
621
622 /* keyingset to use (dynamic enum) */
623 prop = RNA_def_enum(
624 ot->srna, "type", rna_enum_dummy_DEFAULT_items, 0, "Keying Set", "The Keying Set to use");
627 ot->prop = prop;
628}
629
631{
632 PropertyRNA *prop;
633
634 /* identifiers */
635 ot->name = "Delete Keying-Set Keyframe (by name)";
636 ot->idname = "ANIM_OT_keyframe_delete_by_name";
637 ot->description = "Alternate access to 'Delete Keyframe' for keymaps to use";
638
639 /* callbacks */
640 ot->exec = delete_key_exec;
641 ot->poll = modify_key_op_poll;
642
643 /* flags */
645
646 /* keyingset to use (idname) */
647 prop = RNA_def_string(
648 ot->srna, "type", nullptr, MAX_ID_NAME - 2, "Keying Set", "The Keying Set to use");
652 ot->prop = prop;
653}
654
655/* Delete Key Operator ------------------------ */
656/* NOTE: Although this version is simpler than the more generic version for KeyingSets,
657 * it is more useful for animators working in the 3D view.
658 */
659
660/* While in pose mode, the selection of bones has to be considered. */
661static bool can_delete_fcurve(FCurve *fcu, Object *ob)
662{
663 bool can_delete = false;
664 /* in pose mode, only delete the F-Curve if it belongs to a selected bone */
665 if (ob->mode & OB_MODE_POSE) {
666 if (fcu->rna_path) {
667 /* Get bone-name, and check if this bone is selected. */
668 bPoseChannel *pchan = nullptr;
669 char bone_name[sizeof(pchan->name)];
670 if (BLI_str_quoted_substr(fcu->rna_path, "pose.bones[", bone_name, sizeof(bone_name))) {
671 pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
672 /* Delete if bone is selected. */
673 if ((pchan) && (pchan->bone)) {
674 if (pchan->bone->flag & BONE_SELECTED) {
675 can_delete = true;
676 }
677 }
678 }
679 }
680 }
681 else {
682 /* object mode - all of Object's F-Curves are affected */
683 /* TODO: this logic isn't solid. Only delete FCurves of the object, not of bones in this case.
684 */
685 can_delete = true;
686 }
687
688 return can_delete;
689}
690
692{
693 using namespace blender::animrig;
694 bool changed = false;
695
696 CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
697 /* just those in active action... */
698 if ((ob->adt) && (ob->adt->action)) {
699 AnimData *adt = ob->adt;
700 bAction *dna_action = adt->action;
701 FCurve *fcu, *fcn;
702
703 Action &action = dna_action->wrap();
704 if (action.is_action_layered()) {
705 blender::Vector<FCurve *> fcurves_to_delete;
706 foreach_fcurve_in_action_slot(action, adt->slot_handle, [&](FCurve &fcurve) {
707 if (can_delete_fcurve(&fcurve, ob)) {
708 fcurves_to_delete.append(&fcurve);
709 }
710 });
711 for (FCurve *fcurve : fcurves_to_delete) {
712 action_fcurve_remove(action, *fcurve);
714 changed = true;
715 }
716 DEG_id_tag_update(&ob->adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH);
717 }
718 else {
719 for (fcu = static_cast<FCurve *>(dna_action->curves.first); fcu; fcu = fcn) {
720 fcn = fcu->next;
721 /* delete F-Curve completely */
722 if (can_delete_fcurve(fcu, ob)) {
725 changed = true;
726 }
727 }
728 }
729
730 /* Delete the action itself if it is empty. */
731 if (action.is_action_legacy() && blender::animrig::animdata_remove_empty_action(adt)) {
732 changed = true;
733 }
734 }
735 }
737
738 if (!changed) {
739 return OPERATOR_CANCELLED;
740 }
741
742 /* send updates */
744
745 return OPERATOR_FINISHED;
746}
747
749 wmOperator *op,
750 const wmEvent * /*event*/)
751{
752 if (RNA_boolean_get(op->ptr, "confirm")) {
754 op,
755 IFACE_("Remove animation from selected objects?"),
756 nullptr,
759 false);
760 }
761 return clear_anim_v3d_exec(C, op);
762}
763
765{
766 /* identifiers */
767 ot->name = "Remove Animation";
768 ot->description = "Remove all keyframe animation for selected objects";
769 ot->idname = "ANIM_OT_keyframe_clear_v3d";
770
771 /* callbacks */
772 ot->invoke = clear_anim_v3d_invoke;
773 ot->exec = clear_anim_v3d_exec;
774
776
777 /* flags */
780}
781
783{
784 /* don't touch protected F-Curves */
785 if (BKE_fcurve_is_protected(fcu)) {
788 "Not deleting keyframe for locked F-Curve '%s', object '%s'",
789 fcu->rna_path,
790 ob->id.name + 2);
791 return false;
792 }
793
794 /* Special exception for bones, as this makes this operator more convenient to use
795 * NOTE: This is only done in pose mode.
796 * In object mode, we're dealing with the entire object.
797 * TODO: While this means bone animation is not deleted of all bones while in pose mode. Running
798 * the code on the armature object WILL delete keys of all bones.
799 */
800 if (ob->mode & OB_MODE_POSE) {
801 bPoseChannel *pchan = nullptr;
802
803 /* Get bone-name, and check if this bone is selected. */
804 char bone_name[sizeof(pchan->name)];
805 if (!BLI_str_quoted_substr(fcu->rna_path, "pose.bones[", bone_name, sizeof(bone_name))) {
806 return false;
807 }
808 pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
809
810 /* skip if bone is not selected */
811 if ((pchan) && (pchan->bone)) {
812 bArmature *arm = static_cast<bArmature *>(ob->data);
813
814 /* Invisible bones should not be modified. */
816 return false;
817 }
818
819 /* selection flag... */
820 if ((pchan->bone->flag & BONE_SELECTED) == 0) {
821 return false;
822 }
823 }
824 }
825
826 return true;
827}
828
830{
831 using namespace blender::animrig;
832 Scene *scene = CTX_data_scene(C);
833 const float cfra = BKE_scene_frame_get(scene);
834
835 int selected_objects_len = 0;
836 int selected_objects_success_len = 0;
837 int success_multi = 0;
838
839 const bool confirm = op->flag & OP_IS_INVOKE;
840
841 CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
842 int success = 0;
843
844 selected_objects_len += 1;
845
846 /* just those in active action... */
847 if ((ob->adt) && (ob->adt->action)) {
848 AnimData *adt = ob->adt;
849 bAction *act = adt->action;
850 const float cfra_unmap = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP);
851
852 Action &action = act->wrap();
853 if (action.is_action_layered()) {
854 blender::Vector<FCurve *> modified_fcurves;
855 foreach_fcurve_in_action_slot(action, adt->slot_handle, [&](FCurve &fcurve) {
856 if (!can_delete_key(&fcurve, ob, op->reports)) {
857 return;
858 }
860 modified_fcurves.append(&fcurve);
861 }
862 });
863
864 success += modified_fcurves.size();
865 for (FCurve *fcurve : modified_fcurves) {
866 if (BKE_fcurve_is_empty(fcurve)) {
867 action_fcurve_remove(action, *fcurve);
868 }
869 }
870 }
871 else {
872 FCurve *fcn;
873 for (FCurve *fcu = static_cast<FCurve *>(act->curves.first); fcu; fcu = fcn) {
874 fcn = fcu->next;
875 if (!can_delete_key(fcu, ob, op->reports)) {
876 continue;
877 }
878 /* Delete keyframes on current frame
879 * WARNING: this can delete the next F-Curve, hence the "fcn" copying.
880 */
881 success += delete_keyframe_fcurve_legacy(adt, fcu, cfra_unmap);
882 }
883 }
884
885 if (ob->adt->action) {
886 /* The Action might have been unassigned, if it is legacy and the last
887 * F-Curve was removed. */
888 DEG_id_tag_update(&ob->adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH);
889 }
890 }
891
892 /* Only for reporting. */
893 if (success) {
894 selected_objects_success_len += 1;
895 success_multi += success;
896 }
897
899 }
901
902 if (selected_objects_success_len) {
903 /* send updates */
905 }
906
907 if (confirm) {
908 /* if called by invoke (from the UI), make a note that we've removed keyframes */
909 if (selected_objects_success_len) {
910 BKE_reportf(op->reports,
911 RPT_INFO,
912 "%d object(s) successfully had %d keyframes removed",
913 selected_objects_success_len,
914 success_multi);
915 }
916 else {
918 op->reports, RPT_ERROR, "No keyframes removed from %d object(s)", selected_objects_len);
919 }
920 }
921 return OPERATOR_FINISHED;
922}
923
925{
926 Scene *scene = CTX_data_scene(C);
928
929 if (ks == nullptr) {
931 }
932
933 return delete_key_using_keying_set(C, op, ks);
934}
935
937 wmOperator *op,
938 const wmEvent * /*event*/)
939{
940 if (RNA_boolean_get(op->ptr, "confirm")) {
942 op,
943 IFACE_("Delete keyframes from selected objects?"),
944 nullptr,
945 IFACE_("Delete"),
947 false);
948 }
949 return delete_key_v3d_exec(C, op);
950}
951
953{
954 /* identifiers */
955 ot->name = "Delete Keyframe";
956 ot->description = "Remove keyframes on current frame for selected objects and bones";
957 ot->idname = "ANIM_OT_keyframe_delete_v3d";
958
959 /* callbacks */
960 ot->invoke = delete_key_v3d_invoke;
961 ot->exec = delete_key_v3d_exec;
962
964
965 /* flags */
968}
969
970/* Insert Key Button Operator ------------------------ */
971
973{
974 using namespace blender::animrig;
975 Main *bmain = CTX_data_main(C);
976 Scene *scene = CTX_data_scene(C);
977 ToolSettings *ts = scene->toolsettings;
978 PointerRNA ptr = {};
979 PropertyRNA *prop = nullptr;
980 uiBut *but;
983 bool changed = false;
984 int index;
985 const bool all = RNA_boolean_get(op->ptr, "all");
987
988 flag = get_keyframing_flags(scene);
989
990 if (!(but = UI_context_active_but_prop_get(C, &ptr, &prop, &index))) {
991 /* pass event on if no active button found */
993 }
994
995 if ((ptr.owner_id && ptr.data && prop) && RNA_property_anim_editable(&ptr, prop)) {
996 if (ptr.type == &RNA_NlaStrip) {
997 /* Handle special properties for NLA Strips, whose F-Curves are stored on the
998 * strips themselves. These are stored separately or else the properties will
999 * not have any effect.
1000 */
1001 NlaStrip *strip = static_cast<NlaStrip *>(ptr.data);
1002 FCurve *fcu = BKE_fcurve_find(&strip->fcurves, RNA_property_identifier(prop), index);
1003
1004 if (fcu) {
1005 changed = insert_keyframe_direct(op->reports,
1006 ptr,
1007 prop,
1008 fcu,
1009 &anim_eval_context,
1011 nullptr,
1012 eInsertKeyFlags(0));
1013 }
1014 else {
1015 BKE_report(op->reports,
1016 RPT_ERROR,
1017 "This property cannot be animated as it will not get updated correctly");
1018 }
1019 }
1020 else if (UI_but_flag_is_set(but, UI_BUT_DRIVEN)) {
1021 /* Driven property - Find driver */
1022 FCurve *fcu;
1023 bool driven, special;
1024
1026 C, &ptr, prop, index, nullptr, nullptr, &driven, &special);
1027
1028 if (fcu && driven) {
1029 const float driver_frame = evaluate_driver_from_rna_pointer(
1030 &anim_eval_context, &ptr, prop, fcu);
1032 CTX_data_depsgraph_pointer(C), driver_frame);
1033 changed = insert_keyframe_direct(op->reports,
1034 ptr,
1035 prop,
1036 fcu,
1037 &remapped_context,
1039 nullptr,
1041 }
1042 }
1043 else {
1044 /* standard properties */
1045 if (const std::optional<std::string> path = RNA_path_from_ID_to_property(&ptr, prop)) {
1046 const char *identifier = RNA_property_identifier(prop);
1047 const std::optional<blender::StringRefNull> group = default_channel_group_for_path(
1048 &ptr, identifier);
1049
1051
1052 /* NOTE: `index == -1` is a magic number, meaning either "operate on all
1053 * elements" or "not an array property". */
1054 const std::optional<int> array_index = (all || index < 0) ? std::nullopt :
1055 std::optional(index);
1056 PointerRNA owner_ptr = RNA_id_pointer_create(ptr.owner_id);
1058 &owner_ptr,
1059 group,
1060 {{*path, {}, array_index}},
1061 std::nullopt,
1062 anim_eval_context,
1064 flag);
1065 changed = result.get_count(SingleKeyingResult::SUCCESS) != 0;
1066 }
1067 else {
1068 BKE_report(op->reports,
1070 "Failed to resolve path to property, "
1071 "try manually specifying this using a Keying Set instead");
1072 }
1073 }
1074 }
1075 else {
1076 if (prop && !RNA_property_anim_editable(&ptr, prop)) {
1077 BKE_reportf(op->reports,
1079 "\"%s\" property cannot be animated",
1081 }
1082 else {
1083 BKE_reportf(op->reports,
1085 "Button doesn't appear to have any property information attached (ptr.data = "
1086 "%p, prop = %p)",
1087 ptr.data,
1088 (void *)prop);
1089 }
1090 }
1091
1092 if (changed) {
1093 ID *id = ptr.owner_id;
1094 AnimData *adt = BKE_animdata_from_id(id);
1095 if (adt->action != nullptr) {
1097 }
1099
1100 /* send updates */
1102
1103 /* send notifiers that keyframes have been changed */
1105 }
1106
1107 return (changed) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1108}
1109
1111{
1112 /* identifiers */
1113 ot->name = "Insert Keyframe (Buttons)";
1114 ot->idname = "ANIM_OT_keyframe_insert_button";
1115 ot->description = "Insert a keyframe for current UI-active property";
1116
1117 /* callbacks */
1118 ot->exec = insert_key_button_exec;
1119 ot->poll = modify_key_op_poll;
1120
1121 /* flags */
1122 ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
1123
1124 /* properties */
1125 RNA_def_boolean(ot->srna, "all", true, "All", "Insert a keyframe for all element of the array");
1126}
1127
1128/* Delete Key Button Operator ------------------------ */
1129
1131{
1132 Scene *scene = CTX_data_scene(C);
1133 PointerRNA ptr = {};
1134 PropertyRNA *prop = nullptr;
1135 Main *bmain = CTX_data_main(C);
1136 const float cfra = BKE_scene_frame_get(scene);
1137 bool changed = false;
1138 int index;
1139 const bool all = RNA_boolean_get(op->ptr, "all");
1140
1141 if (!UI_context_active_but_prop_get(C, &ptr, &prop, &index)) {
1142 /* pass event on if no active button found */
1144 }
1145
1146 if (ptr.owner_id && ptr.data && prop) {
1148 /* Handle special properties for NLA Strips, whose F-Curves are stored on the
1149 * strips themselves. These are stored separately or else the properties will
1150 * not have any effect.
1151 */
1152 ID *id = ptr.owner_id;
1153 NlaStrip *strip = static_cast<NlaStrip *>(ptr.data);
1154 FCurve *fcu = BKE_fcurve_find(&strip->fcurves, RNA_property_identifier(prop), 0);
1155
1156 if (fcu) {
1157 if (BKE_fcurve_is_protected(fcu)) {
1159 op->reports,
1161 "Not deleting keyframe for locked F-Curve for NLA Strip influence on %s - %s '%s'",
1162 strip->name,
1164 id->name + 2);
1165 }
1166 else {
1167 /* remove the keyframe directly
1168 * NOTE: cannot use delete_keyframe_fcurve(), as that will free the curve,
1169 * and delete_keyframe() expects the FCurve to be part of an action
1170 */
1171 bool found = false;
1172 int i;
1173
1174 /* try to find index of beztriple to get rid of */
1175 i = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, cfra, fcu->totvert, &found);
1176 if (found) {
1177 /* delete the key at the index (will sanity check + do recalc afterwards) */
1180 changed = true;
1181 }
1182 }
1183 }
1184 }
1185 else {
1186 /* standard properties */
1187 if (const std::optional<std::string> path = RNA_path_from_ID_to_property(&ptr, prop)) {
1188 RNAPath rna_path = {*path, std::nullopt, index};
1189 if (all) {
1190 /* nullopt indicates operating on the entire array (or the property itself otherwise). */
1191 rna_path.index = std::nullopt;
1192 }
1193
1195 bmain, op->reports, ptr.owner_id, rna_path, cfra) != 0;
1196 }
1197 else if (G.debug & G_DEBUG) {
1198 printf("Button Delete-Key: no path to property\n");
1199 }
1200 }
1201 }
1202 else if (G.debug & G_DEBUG) {
1203 printf("ptr.data = %p, prop = %p\n", ptr.data, (void *)prop);
1204 }
1205
1206 if (changed) {
1207 /* send updates */
1209
1210 /* send notifiers that keyframes have been changed */
1212 }
1213
1214 return (changed) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1215}
1216
1218{
1219 /* identifiers */
1220 ot->name = "Delete Keyframe (Buttons)";
1221 ot->idname = "ANIM_OT_keyframe_delete_button";
1222 ot->description = "Delete current keyframe of current UI-active property";
1223
1224 /* callbacks */
1225 ot->exec = delete_key_button_exec;
1226 ot->poll = modify_key_op_poll;
1227
1228 /* flags */
1229 ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
1230
1231 /* properties */
1232 RNA_def_boolean(ot->srna, "all", true, "All", "Delete keyframes from all elements of the array");
1233}
1234
1235/* Clear Key Button Operator ------------------------ */
1236
1238{
1239 PointerRNA ptr = {};
1240 PropertyRNA *prop = nullptr;
1241 Main *bmain = CTX_data_main(C);
1242 bool changed = false;
1243 int index;
1244 const bool all = RNA_boolean_get(op->ptr, "all");
1245
1246 if (!UI_context_active_but_prop_get(C, &ptr, &prop, &index)) {
1247 /* pass event on if no active button found */
1249 }
1250
1251 if (ptr.owner_id && ptr.data && prop) {
1252 if (const std::optional<std::string> path = RNA_path_from_ID_to_property(&ptr, prop)) {
1253 RNAPath rna_path = {*path, std::nullopt, index};
1254 if (all) {
1255 /* nullopt indicates operating on the entire array (or the property itself otherwise). */
1256 rna_path.index = std::nullopt;
1257 }
1258
1259 changed |= (blender::animrig::clear_keyframe(bmain, op->reports, ptr.owner_id, rna_path) !=
1260 0);
1261 }
1262 else if (G.debug & G_DEBUG) {
1263 printf("Button Clear-Key: no path to property\n");
1264 }
1265 }
1266 else if (G.debug & G_DEBUG) {
1267 printf("ptr.data = %p, prop = %p\n", ptr.data, (void *)prop);
1268 }
1269
1270 if (changed) {
1271 /* send updates */
1273
1274 /* send notifiers that keyframes have been changed */
1276 }
1277
1278 return (changed) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1279}
1280
1282{
1283 /* identifiers */
1284 ot->name = "Clear Keyframe (Buttons)";
1285 ot->idname = "ANIM_OT_keyframe_clear_button";
1286 ot->description = "Clear all keyframes on the currently active property";
1287
1288 /* callbacks */
1289 ot->exec = clear_key_button_exec;
1290 ot->poll = modify_key_op_poll;
1291
1292 /* flags */
1293 ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
1294
1295 /* properties */
1296 RNA_def_boolean(ot->srna, "all", true, "All", "Clear keyframes from all elements of the array");
1297}
1298
1299/* ******************************************* */
1300/* KEYFRAME DETECTION */
1301
1302/* --------------- API/Per-Datablock Handling ------------------- */
1303
1305 PropertyRNA *prop,
1306 FCurve *fcu,
1307 const AnimationEvalContext *anim_eval_context)
1308{
1309 PathResolvedRNA anim_rna;
1310 anim_rna.ptr = ptr;
1311 anim_rna.prop = prop;
1312 anim_rna.prop_index = fcu->array_index;
1313
1314 int index = fcu->array_index;
1316
1317 float fcurve_val = calculate_fcurve(&anim_rna, fcu, anim_eval_context);
1318 float cur_val = (index >= 0 && index < values.size()) ? values[index] : 0.0f;
1319
1320 return !compare_ff_relative(fcurve_val, cur_val, FLT_EPSILON, 64);
1321}
1322
1323/* -------------------------------------------------------------------- */
1326
1329{
1330 KeyingSet *ks = nullptr;
1331 const int prop_type = RNA_property_type(prop);
1332 if (prop_type == PROP_ENUM) {
1333 int type = RNA_property_enum_get(op->ptr, prop);
1334 ks = ANIM_keyingset_get_from_enum_type(scene, type);
1335 if (ks == nullptr) {
1336 BKE_report(op->reports, RPT_ERROR, "No active Keying Set");
1337 }
1338 }
1339 else if (prop_type == PROP_STRING) {
1340 char type_id[MAX_ID_NAME - 2];
1341 RNA_property_string_get(op->ptr, prop, type_id);
1342
1343 if (STREQ(type_id, "__ACTIVE__")) {
1345 }
1346 else {
1347 ks = ANIM_keyingset_get_from_idname(scene, type_id);
1348 }
1349
1350 if (ks == nullptr) {
1351 BKE_reportf(op->reports, RPT_ERROR, "Keying set '%s' not found", type_id);
1352 }
1353 }
1354 else {
1355 BLI_assert(0);
1356 }
1357 return ks;
1358}
1359
Functions and classes to work with Actions.
Functionality to iterate an Action in various ways.
Functions to work with AnimData.
Functions to deal with Armatures.
C++ functions to deal with Armature collections (i.e. the successor of bone layers).
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:72
AnimData * BKE_animdata_from_id(const ID *id)
Definition anim_data.cc:82
AnimationEvalContext BKE_animsys_eval_context_construct(struct Depsgraph *depsgraph, float eval_time) ATTR_WARN_UNUSED_RESULT
Definition anim_sys.cc:735
#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:165
bool BKE_id_is_editable(const Main *bmain, const ID *id)
Definition lib_id.cc:2503
@ NLATIME_CONVERT_UNMAP
Definition BKE_nla.hh:540
bool BKE_nlastrip_has_curves_for_property(const PointerRNA *ptr, const PropertyRNA *prop)
float BKE_nla_tweakedit_remap(AnimData *adt, float cframe, eNlaTime_ConvertModes mode)
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:126
float BKE_scene_frame_get(const Scene *scene)
Definition scene.cc:2381
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
void BLI_kdtree_nd_ free(KDTree *tree)
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.cc:531
#define ELEM(...)
#define STREQ(a, b)
#define RPT_(msgid)
#define CTX_IFACE_(context, msgid)
#define BLT_I18NCONTEXT_OPERATOR_DEFAULT
#define IFACE_(msgid)
float[3] Vector
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:962
@ ID_RECALC_ANIMATION_NO_FLUSH
Definition DNA_ID.h:1084
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
@ BONE_SELECTED
@ HD_AUTO_ANIM
@ BEZT_IPO_BEZ
eBezTriple_KeyframeType
@ OB_MODE_EDIT
@ OB_MODE_POSE
@ OB_MODE_OBJECT
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_CANCELLED
@ OPERATOR_INTERFACE
@ OPERATOR_FINISHED
@ OPERATOR_PASS_THROUGH
bool ED_operator_areaactive(bContext *C)
Read Guarded memory(de)allocation.
@ PROP_STRING_SEARCH_SUGGESTION
Definition RNA_types.hh:701
@ PROP_ENUM
Definition RNA_types.hh:154
@ PROP_STRING
Definition RNA_types.hh:153
@ PROP_HIDDEN
Definition RNA_types.hh:324
#define C
Definition RandGen.cpp:29
void UI_context_update_anim_flag(const bContext *C)
void UI_popup_menu_end(bContext *C, uiPopupMenu *pup)
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)
@ UI_BUT_DRIVEN
bool UI_but_flag_is_set(uiBut *but, int flag)
@ ALERT_ICON_NONE
@ OPTYPE_INTERNAL
Definition WM_types.hh:202
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define NC_ANIMATION
Definition WM_types.hh:385
#define NA_ADDED
Definition WM_types.hh:583
#define NA_EDITED
Definition WM_types.hh:581
ReportList * reports
Definition WM_types.hh:1025
#define NA_REMOVED
Definition WM_types.hh:584
#define ND_KEYS
Definition WM_types.hh:460
#define ND_KEYFRAME
Definition WM_types.hh:491
#define NC_OBJECT
Definition WM_types.hh:376
void ANIM_deselect_keys_in_animation_editors(bContext *C)
Definition anim_deps.cc:478
#define U
BPy_StructRNA * depsgraph
Span< T > as_span() const
bool add(const Key &key)
Definition BLI_set.hh:248
int64_t size() const
void append(const T &value)
bool is_empty() const
void extend(Span< T > array)
void merge(const CombinedKeyingResult &other)
int get_count(const SingleKeyingResult result) const
void generate_reports(ReportList *reports, eReportType report_level=RPT_ERROR)
#define SELECT
static wmOperatorStatus delete_key_using_keying_set(bContext *C, wmOperator *op, KeyingSet *ks)
void ANIM_OT_keyframe_insert_menu(wmOperatorType *ot)
bool fcurve_is_changed(PointerRNA ptr, PropertyRNA *prop, FCurve *fcu, const AnimationEvalContext *anim_eval_context)
Lesser Keyframe Checking API call.
static wmOperatorStatus insert_key(bContext *C, wmOperator *op)
static wmOperatorStatus delete_key_v3d_invoke(bContext *C, wmOperator *op, const wmEvent *)
static wmOperatorStatus delete_key_button_exec(bContext *C, wmOperator *op)
static wmOperatorStatus insert_key_invoke(bContext *C, wmOperator *op, const wmEvent *)
void ANIM_OT_keyframe_insert(wmOperatorType *ot)
static wmOperatorStatus clear_anim_v3d_exec(bContext *C, wmOperator *)
void ANIM_OT_keyframe_clear_button(wmOperatorType *ot)
void ANIM_OT_keyframe_insert_by_name(wmOperatorType *ot)
void ANIM_OT_keyframe_delete(wmOperatorType *ot)
void ED_keyframes_add(FCurve *fcu, int num_keys_to_add)
static wmOperatorStatus insert_key_menu_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)
void ANIM_OT_keyframe_insert_button(wmOperatorType *ot)
static wmOperatorStatus clear_key_button_exec(bContext *C, wmOperator *op)
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 wmOperatorStatus delete_key_v3d_without_keying_set(bContext *C, wmOperator *op)
static bool get_selection(bContext *C, blender::Vector< PointerRNA > *r_selection)
static bool modify_key_op_poll(bContext *C)
static wmOperatorStatus delete_key_v3d_exec(bContext *C, wmOperator *op)
static wmOperatorStatus 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 wmOperatorStatus insert_key_exec(bContext *C, wmOperator *op)
static wmOperatorStatus clear_anim_v3d_invoke(bContext *C, wmOperator *op, const wmEvent *)
static wmOperatorStatus insert_key_button_exec(bContext *C, wmOperator *op)
static bool can_delete_fcurve(FCurve *fcu, Object *ob)
void ANIM_OT_keyframe_delete_button(wmOperatorType *ot)
static wmOperatorStatus delete_key_exec(bContext *C, wmOperator *op)
void ANIM_OT_keyframe_delete_by_name(wmOperatorType *ot)
static wmOperatorStatus keyframe_insert_with_keyingset_exec(bContext *C, wmOperator *op)
void ANIM_keyingset_visit_for_search_no_poll(const bContext *C, PointerRNA *, PropertyRNA *, const char *, blender::FunctionRef< void(StringPropertySearchVisitParams)> visit_fn)
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)
bool all(VecOp< bool, D >) RET
#define printf(...)
#define MEM_recallocN(vmemh, len)
#define MAX_ID_NAME
#define GS(a)
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
#define G(x, y, z)
void foreach_fcurve_in_action_slot(Action &action, slot_handle_t handle, FunctionRef< void(FCurve &fcurve)> callback)
bool action_fcurve_remove(Action &action, FCurve &fcu)
std::optional< StringRefNull > default_channel_group_for_path(const PointerRNA *animated_struct, StringRef prop_rna_path)
void animdata_fcurve_delete(AnimData *adt, FCurve *fcu)
Definition animdata.cc:251
void update_autoflags_fcurve_direct(FCurve *fcu, PropertyType prop_type)
KeyingSet * scene_get_active_keyingset(const Scene *scene)
Vector< RNAPath > get_keyable_id_property_paths(const PointerRNA &ptr)
Definition anim_rna.cc:126
Vector< float > get_rna_values(PointerRNA *ptr, PropertyRNA *prop)
Definition anim_rna.cc:25
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)
CombinedKeyingResult insert_keyframes(Main *bmain, PointerRNA *struct_pointer, std::optional< StringRefNull > channel_group, const blender::Span< RNAPath > rna_paths, std::optional< float > scene_frame, const AnimationEvalContext &anim_eval_context, eBezTriple_KeyframeType key_type, eInsertKeyFlags insert_key_flags)
Main key-frame insertion API.
bool bone_is_visible_pchan(const bArmature *armature, const bPoseChannel *pchan)
bool keyingset_find_id(KeyingSet *keyingset, ID *id)
bool delete_keyframe_fcurve_legacy(AnimData *adt, FCurve *fcu, float cfra)
bool animdata_remove_empty_action(AnimData *adt)
Definition animdata.cc:310
bool insert_keyframe_direct(ReportList *reports, PointerRNA ptr, PropertyRNA *prop, FCurve *fcu, const AnimationEvalContext *anim_eval_context, eBezTriple_KeyframeType keytype, NlaKeyframingContext *nla_context, eInsertKeyFlags flag)
Secondary Insert Key-framing API call.
int apply_keyingset(bContext *C, blender::Vector< PointerRNA > *sources, KeyingSet *keyingset, ModifyKeyMode mode, float cfra)
eInsertKeyFlags get_keyframing_flags(Scene *scene)
float evaluate_driver_from_rna_pointer(const AnimationEvalContext *anim_eval_context, PointerRNA *ptr, PropertyRNA *prop, const FCurve *fcu)
Definition driver.cc:16
bool mode_set(bContext *C, eObjectMode mode)
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
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:1173
bool RNA_path_resolve_property(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
Definition rna_path.cc:560
const EnumPropertyItem rna_enum_dummy_DEFAULT_items[]
Definition rna_rna.cc:32
bAction * action
int32_t slot_handle
const char * identifier
Definition RNA_types.hh:623
const char * name
Definition RNA_types.hh:627
struct FCurve * next
char * rna_path
BezTriple * bezt
int array_index
unsigned int totvert
Definition DNA_ID.h:404
char name[66]
Definition DNA_ID.h:415
char name[64]
ListBase fcurves
char name[64]
struct bPose * pose
PointerRNA ptr
Definition RNA_types.hh:141
PropertyRNA * prop
Definition RNA_types.hh:142
std::optional< int > index
Definition RNA_path.hh:66
int active_keyingset
struct ToolSettings * toolsettings
struct Bone * bone
PointerRNA op(wmOperatorType *ot, std::optional< blender::StringRef > name, int icon, wmOperatorCallContext context, eUI_Item_Flag flag)
void separator(float factor=1.0f, LayoutSeparatorType type=LayoutSeparatorType::Auto)
wmOperatorStatus(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1046
PropertyRNA * prop
Definition WM_types.hh:1136
struct ReportList * reports
struct wmOperatorType * type
struct PointerRNA * ptr
i
Definition text_draw.cc:230
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition wm_files.cc:4226
wmOperatorType * ot
Definition wm_files.cc:4225
void WM_operator_properties_confirm_or_exec(wmOperatorType *ot)
std::string WM_operatortype_name(wmOperatorType *ot, PointerRNA *properties)
wmOperatorStatus 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:139