diff --git a/source/blender/python/intern/bpy_rna_anim.cc b/source/blender/python/intern/bpy_rna_anim.cc index eab83c718a2..83fec149b9d 100644 --- a/source/blender/python/intern/bpy_rna_anim.cc +++ b/source/blender/python/intern/bpy_rna_anim.cc @@ -228,10 +228,13 @@ static int pyrna_struct_keyframe_parse(PointerRNA *ptr, int *r_index, float *r_cfra, const char **r_group_name, - int *r_options) + int *r_options, + eBezTriple_KeyframeType *r_keytype) { - static const char *kwlist[] = {"data_path", "index", "frame", "group", "options", nullptr}; + static const char *kwlist[] = { + "data_path", "index", "frame", "group", "options", "keytype", nullptr}; PyObject *pyoptions = nullptr; + char *keytype_name = nullptr; const char *path; /* NOTE: `parse_str` MUST start with `s|ifsO!`. */ @@ -244,7 +247,8 @@ static int pyrna_struct_keyframe_parse(PointerRNA *ptr, r_cfra, r_group_name, &PySet_Type, - &pyoptions)) + &pyoptions, + &keytype_name)) { return -1; } @@ -269,12 +273,24 @@ static int pyrna_struct_keyframe_parse(PointerRNA *ptr, *r_options |= INSERTKEY_NO_USERPREF; } + if (r_keytype) { + int keytype_as_int = 0; + if (keytype_name && pyrna_enum_value_from_id(rna_enum_beztriple_keyframe_type_items, + keytype_name, + &keytype_as_int, + error_prefix) == -1) + { + return -1; + } + *r_keytype = eBezTriple_KeyframeType(keytype_as_int); + } + return 0; /* success */ } char pyrna_struct_keyframe_insert_doc[] = ".. method:: keyframe_insert(data_path, index=-1, frame=bpy.context.scene.frame_current, " - "group=\"\", options=set())\n" + "group=\"\", options=set(), keytype='KEYFRAME')\n" "\n" " Insert a keyframe on the property given, adding fcurves and animation data when " "necessary.\n" @@ -304,6 +320,9 @@ char pyrna_struct_keyframe_insert_doc[] = " - ``INSERTKEY_CYCLE_AWARE`` Take cyclic extrapolation into account " "(Cycle-Aware Keying option).\n" " :type flag: set\n" + " :arg keytype: Type of the key: 'KEYFRAME', 'BREAKDOWN', 'MOVING_HOLD', 'EXTREME', " + "'JITTER', or 'GENERATED'\n" + " :type keytype: string\n" " :return: Success of keyframe insertion.\n" " :rtype: boolean\n"; PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyObject *kw) @@ -313,7 +332,7 @@ PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyOb int index = -1; float cfra = FLT_MAX; const char *group_name = nullptr; - const char keytype = BEZT_KEYTYPE_KEYFRAME; /* XXX: Expose this as a one-off option... */ + eBezTriple_KeyframeType keytype = BEZT_KEYTYPE_KEYFRAME; int options = 0; PYRNA_STRUCT_CHECK_OBJ(self); @@ -321,13 +340,14 @@ PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyOb if (pyrna_struct_keyframe_parse(&self->ptr, args, kw, - "s|$ifsO!:bpy_struct.keyframe_insert()", + "s|$ifsO!s:bpy_struct.keyframe_insert()", "bpy_struct.keyframe_insert()", &path_full, &index, &cfra, &group_name, - &options) == -1) + &options, + &keytype) == -1) { return nullptr; } @@ -440,12 +460,13 @@ PyObject *pyrna_struct_keyframe_delete(BPy_StructRNA *self, PyObject *args, PyOb if (pyrna_struct_keyframe_parse(&self->ptr, args, kw, - "s|$ifsO!:bpy_struct.keyframe_delete()", + "s|$ifsOs!:bpy_struct.keyframe_delete()", "bpy_struct.keyframe_insert()", &path_full, &index, &cfra, &group_name, + nullptr, nullptr) == -1) { return nullptr; diff --git a/tests/python/bl_animation_fcurves.py b/tests/python/bl_animation_fcurves.py index 94de7e7090d..8a49ad9e54b 100644 --- a/tests/python/bl_animation_fcurves.py +++ b/tests/python/bl_animation_fcurves.py @@ -188,6 +188,21 @@ class KeyframeInsertTest(AbstractAnimationTest, unittest.TestCase): bpy.ops.object.delete(use_global=False) + def test_keyframe_insert_keytype(self): + key_object = bpy.context.active_object + + # Inserting a key with a specific type should work. + key_object.keyframe_insert("location", keytype='GENERATED') + + # Unsupported/unknown types should be rejected. + with self.assertRaises(ValueError): + key_object.keyframe_insert("rotation_euler", keytype='UNSUPPORTED') + + # Only a single key should have been inserted. + keys = key_object.animation_data.action.fcurves[0].keyframe_points + self.assertEqual(len(keys), 1) + self.assertEqual(keys[0].type, 'GENERATED') + def test_keyframe_insertion_high_frame_number(self): bpy.ops.mesh.primitive_monkey_add() key_count = 100