Anim: Deselect Keys before inserting new keys
This commit changes the keying code to deselect keyframes when inserting new keys. This has been discussed in the Animation & Rigging module meeting [1]. There is also an RCS post about that [2]. Doing this brings key creation in line with object creation, where only the newly created object is selected. There has been a previous attempt [3] to do a similar thing. ### Changes When inserting keys by pressing `I` in the viewport or choosing a keying set, all keys of the `Action` get deselected before inserting new keys. New keys are selected by default. Python RNA functions are **NOT** affected, meaning addons using those functions will not deselect any keys by default. The developer has to choose to do so. To make that easier, there is a new RNA function on the action `deselect_keys` [1]: https://devtalk.blender.org/t/2024-05-02-animation-rigging-module-meeting/34493#patches-review-decision-time-5 [2]: https://blender.community/c/rightclickselect/K0hbbc [3]: https://archive.blender.org/developer/D11623 Pull Request: https://projects.blender.org/blender/blender/pulls/121908
This commit is contained in:
committed by
Christoph Lendenfeld
parent
c7ecaf67fd
commit
6ef77a0d22
@@ -921,6 +921,16 @@ void assert_baklava_phase_1_invariants(const Strip &strip);
|
|||||||
*/
|
*/
|
||||||
Action *convert_to_layered_action(Main &bmain, const Action &action);
|
Action *convert_to_layered_action(Main &bmain, const Action &action);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deselect the keys of all actions in the Span. Duplicate entries are only visited once.
|
||||||
|
*/
|
||||||
|
void deselect_keys_actions(blender::Span<bAction *> actions);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deselect all keys within the action.
|
||||||
|
*/
|
||||||
|
void action_deselect_keys(Action &action);
|
||||||
|
|
||||||
} // namespace blender::animrig
|
} // namespace blender::animrig
|
||||||
|
|
||||||
/* Wrap functions for the DNA structs. */
|
/* Wrap functions for the DNA structs. */
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ set(INC_SYS
|
|||||||
set(SRC
|
set(SRC
|
||||||
intern/action.cc
|
intern/action.cc
|
||||||
intern/action_runtime.cc
|
intern/action_runtime.cc
|
||||||
|
intern/action_selection.cc
|
||||||
intern/anim_rna.cc
|
intern/anim_rna.cc
|
||||||
intern/animdata.cc
|
intern/animdata.cc
|
||||||
intern/bone_collections.cc
|
intern/bone_collections.cc
|
||||||
|
|||||||
33
source/blender/animrig/intern/action_selection.cc
Normal file
33
source/blender/animrig/intern/action_selection.cc
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#include "DNA_action_types.h"
|
||||||
|
#include "DNA_anim_types.h"
|
||||||
|
|
||||||
|
#include "BLI_listbase.h"
|
||||||
|
#include "BLI_set.hh"
|
||||||
|
|
||||||
|
#include "BKE_anim_data.hh"
|
||||||
|
#include "BKE_fcurve.hh"
|
||||||
|
|
||||||
|
#include "ANIM_action.hh"
|
||||||
|
#include "ANIM_fcurve.hh"
|
||||||
|
|
||||||
|
namespace blender::animrig {
|
||||||
|
|
||||||
|
void action_deselect_keys(Action &action)
|
||||||
|
{
|
||||||
|
for (FCurve *fcu : fcurves_all(action)) {
|
||||||
|
BKE_fcurve_deselect_all_keys(*fcu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void deselect_keys_actions(Span<bAction *> actions)
|
||||||
|
{
|
||||||
|
Set<bAction *> visited_actions;
|
||||||
|
for (bAction *action : actions) {
|
||||||
|
if (!visited_actions.add(action)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
action_deselect_keys(action->wrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace blender::animrig
|
||||||
@@ -442,6 +442,11 @@ bool BKE_fcurve_is_protected(const FCurve *fcu);
|
|||||||
*/
|
*/
|
||||||
bool BKE_fcurve_has_selected_control_points(const FCurve *fcu);
|
bool BKE_fcurve_has_selected_control_points(const FCurve *fcu);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deselect all keyframes within that FCurve.
|
||||||
|
*/
|
||||||
|
void BKE_fcurve_deselect_all_keys(FCurve &fcu);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the F-Curve has a Cycles modifier with simple settings
|
* Checks if the F-Curve has a Cycles modifier with simple settings
|
||||||
* that warrant transition smoothing.
|
* that warrant transition smoothing.
|
||||||
|
|||||||
@@ -1018,6 +1018,16 @@ bool BKE_fcurve_has_selected_control_points(const FCurve *fcu)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BKE_fcurve_deselect_all_keys(FCurve &fcu)
|
||||||
|
{
|
||||||
|
if (!fcu.bezt) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < fcu.totvert; i++) {
|
||||||
|
BEZT_DESEL_ALL(&fcu.bezt[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool BKE_fcurve_is_keyframable(const FCurve *fcu)
|
bool BKE_fcurve_is_keyframable(const FCurve *fcu)
|
||||||
{
|
{
|
||||||
/* F-Curve's keyframes must be "usable" (i.e. visible + have an effect on final result) */
|
/* F-Curve's keyframes must be "usable" (i.e. visible + have an effect on final result) */
|
||||||
|
|||||||
@@ -18,15 +18,21 @@
|
|||||||
#include "DNA_object_types.h"
|
#include "DNA_object_types.h"
|
||||||
#include "DNA_scene_types.h"
|
#include "DNA_scene_types.h"
|
||||||
#include "DNA_sequence_types.h"
|
#include "DNA_sequence_types.h"
|
||||||
|
#include "DNA_space_types.h"
|
||||||
|
#include "DNA_windowmanager_types.h"
|
||||||
|
|
||||||
#include "BLI_blenlib.h"
|
#include "BLI_blenlib.h"
|
||||||
|
#include "BLI_set.hh"
|
||||||
#include "BLI_utildefines.h"
|
#include "BLI_utildefines.h"
|
||||||
|
|
||||||
#include "BKE_action.h"
|
#include "BKE_action.h"
|
||||||
#include "BKE_anim_data.hh"
|
#include "BKE_anim_data.hh"
|
||||||
|
#include "BKE_context.hh"
|
||||||
#include "BKE_fcurve.hh"
|
#include "BKE_fcurve.hh"
|
||||||
#include "BKE_gpencil_legacy.h"
|
#include "BKE_gpencil_legacy.h"
|
||||||
#include "BKE_grease_pencil.hh"
|
#include "BKE_grease_pencil.hh"
|
||||||
|
#include "BKE_screen.hh"
|
||||||
|
#include "BKE_workspace.hh"
|
||||||
|
|
||||||
#include "DEG_depsgraph.hh"
|
#include "DEG_depsgraph.hh"
|
||||||
|
|
||||||
@@ -38,6 +44,8 @@
|
|||||||
|
|
||||||
#include "ED_anim_api.hh"
|
#include "ED_anim_api.hh"
|
||||||
|
|
||||||
|
#include "ANIM_action.hh"
|
||||||
|
|
||||||
/* **************************** depsgraph tagging ******************************** */
|
/* **************************** depsgraph tagging ******************************** */
|
||||||
|
|
||||||
void ANIM_list_elem_update(Main *bmain, Scene *scene, bAnimListElem *ale)
|
void ANIM_list_elem_update(Main *bmain, Scene *scene, bAnimListElem *ale)
|
||||||
@@ -460,3 +468,64 @@ void ANIM_animdata_freelist(ListBase *anim_data)
|
|||||||
BLI_freelistN(anim_data);
|
BLI_freelistN(anim_data);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ANIM_deselect_keys_in_animation_editors(bContext *C)
|
||||||
|
{
|
||||||
|
using namespace blender;
|
||||||
|
|
||||||
|
wmWindow *ctx_window = CTX_wm_window(C);
|
||||||
|
ScrArea *ctx_area = CTX_wm_area(C);
|
||||||
|
ARegion *ctx_region = CTX_wm_region(C);
|
||||||
|
|
||||||
|
Set<bAction *> dna_actions;
|
||||||
|
LISTBASE_FOREACH (wmWindow *, win, &CTX_wm_manager(C)->windows) {
|
||||||
|
bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
|
||||||
|
|
||||||
|
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
|
||||||
|
if (!ELEM(area->spacetype, SPACE_GRAPH, SPACE_ACTION)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ARegion *window_region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
|
||||||
|
|
||||||
|
if (!window_region) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
CTX_wm_window_set(C, win);
|
||||||
|
CTX_wm_area_set(C, area);
|
||||||
|
CTX_wm_region_set(C, window_region);
|
||||||
|
bAnimContext ac;
|
||||||
|
if (!ANIM_animdata_get_context(C, &ac)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ListBase anim_data = {nullptr, nullptr};
|
||||||
|
int filter = 0;
|
||||||
|
if (ac.spacetype == SPACE_GRAPH) {
|
||||||
|
SpaceGraph *graph_editor = (SpaceGraph *)ac.sl;
|
||||||
|
filter = graph_editor->ads->filterflag;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BLI_assert(ac.spacetype == SPACE_ACTION);
|
||||||
|
SpaceAction *action_editor = (SpaceAction *)ac.sl;
|
||||||
|
filter = action_editor->ads.filterflag;
|
||||||
|
}
|
||||||
|
ANIM_animdata_filter(
|
||||||
|
&ac, &anim_data, eAnimFilter_Flags(filter), ac.data, eAnimCont_Types(ac.datatype));
|
||||||
|
LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
|
||||||
|
if (!ale->adt || !ale->adt->action) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
dna_actions.add(ale->adt->action);
|
||||||
|
}
|
||||||
|
ANIM_animdata_freelist(&anim_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CTX_wm_window_set(C, ctx_window);
|
||||||
|
CTX_wm_area_set(C, ctx_area);
|
||||||
|
CTX_wm_region_set(C, ctx_region);
|
||||||
|
|
||||||
|
for (bAction *dna_action : dna_actions) {
|
||||||
|
animrig::action_deselect_keys(dna_action->wrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -40,6 +40,7 @@
|
|||||||
#include "DEG_depsgraph.hh"
|
#include "DEG_depsgraph.hh"
|
||||||
#include "DEG_depsgraph_query.hh"
|
#include "DEG_depsgraph_query.hh"
|
||||||
|
|
||||||
|
#include "ED_anim_api.hh"
|
||||||
#include "ED_keyframing.hh"
|
#include "ED_keyframing.hh"
|
||||||
#include "ED_object.hh"
|
#include "ED_object.hh"
|
||||||
#include "ED_screen.hh"
|
#include "ED_screen.hh"
|
||||||
@@ -433,6 +434,8 @@ static int insert_key(bContext *C, wmOperator *op)
|
|||||||
|
|
||||||
static int insert_key_exec(bContext *C, wmOperator *op)
|
static int insert_key_exec(bContext *C, wmOperator *op)
|
||||||
{
|
{
|
||||||
|
ANIM_deselect_keys_in_animation_editors(C);
|
||||||
|
|
||||||
Scene *scene = CTX_data_scene(C);
|
Scene *scene = CTX_data_scene(C);
|
||||||
/* Use the active keying set if there is one. */
|
/* Use the active keying set if there is one. */
|
||||||
const int type = RNA_enum_get(op->ptr, "type");
|
const int type = RNA_enum_get(op->ptr, "type");
|
||||||
@@ -469,6 +472,8 @@ void ANIM_OT_keyframe_insert(wmOperatorType *ot)
|
|||||||
|
|
||||||
static int keyframe_insert_with_keyingset_exec(bContext *C, wmOperator *op)
|
static int keyframe_insert_with_keyingset_exec(bContext *C, wmOperator *op)
|
||||||
{
|
{
|
||||||
|
ANIM_deselect_keys_in_animation_editors(C);
|
||||||
|
|
||||||
Scene *scene = CTX_data_scene(C);
|
Scene *scene = CTX_data_scene(C);
|
||||||
KeyingSet *ks = keyingset_get_from_op_with_error(op, op->type->prop, scene);
|
KeyingSet *ks = keyingset_get_from_op_with_error(op, op->type->prop, scene);
|
||||||
if (ks == nullptr) {
|
if (ks == nullptr) {
|
||||||
@@ -1062,6 +1067,8 @@ static int insert_key_button_exec(bContext *C, wmOperator *op)
|
|||||||
const std::optional<blender::StringRefNull> group = default_channel_group_for_path(
|
const std::optional<blender::StringRefNull> group = default_channel_group_for_path(
|
||||||
&ptr, identifier);
|
&ptr, identifier);
|
||||||
|
|
||||||
|
ANIM_deselect_keys_in_animation_editors(C);
|
||||||
|
|
||||||
/* NOTE: `index == -1` is a magic number, meaning either "operate on all
|
/* NOTE: `index == -1` is a magic number, meaning either "operate on all
|
||||||
* elements" or "not an array property". */
|
* elements" or "not an array property". */
|
||||||
const std::optional<int> array_index = (all || index < 0) ? std::nullopt :
|
const std::optional<int> array_index = (all || index < 0) ? std::nullopt :
|
||||||
|
|||||||
@@ -45,6 +45,7 @@
|
|||||||
#include "ED_screen.hh"
|
#include "ED_screen.hh"
|
||||||
#include "ED_util.hh"
|
#include "ED_util.hh"
|
||||||
|
|
||||||
|
#include "ANIM_action.hh"
|
||||||
#include "ANIM_bone_collections.hh"
|
#include "ANIM_bone_collections.hh"
|
||||||
#include "ANIM_keyframing.hh"
|
#include "ANIM_keyframing.hh"
|
||||||
#include "ANIM_keyingsets.hh"
|
#include "ANIM_keyingsets.hh"
|
||||||
@@ -155,6 +156,10 @@ static void poselib_keytag_pose(bContext *C, Scene *scene, PoseBlendData *pbd)
|
|||||||
ANIM_relative_keyingset_add_source(sources, &pbd->ob->id, &RNA_PoseBone, pchan);
|
ANIM_relative_keyingset_add_source(sources, &pbd->ob->id, &RNA_PoseBone, pchan);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (adt->action) {
|
||||||
|
blender::animrig::action_deselect_keys(adt->action->wrap());
|
||||||
|
}
|
||||||
|
|
||||||
/* Perform actual auto-keying. */
|
/* Perform actual auto-keying. */
|
||||||
ANIM_apply_keyingset(
|
ANIM_apply_keyingset(
|
||||||
C, &sources, ks, blender::animrig::ModifyKeyMode::INSERT, float(scene->r.cfra));
|
C, &sources, ks, blender::animrig::ModifyKeyMode::INSERT, float(scene->r.cfra));
|
||||||
|
|||||||
@@ -753,6 +753,12 @@ void ANIM_set_active_channel(bAnimContext *ac,
|
|||||||
*/
|
*/
|
||||||
bool ANIM_is_active_channel(bAnimListElem *ale);
|
bool ANIM_is_active_channel(bAnimListElem *ale);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deselects the keys displayed within the open animation editors. Depending on the display
|
||||||
|
* settings of those editors, the keys may not be from an action of the selected objects.
|
||||||
|
*/
|
||||||
|
void ANIM_deselect_keys_in_animation_editors(bContext *C);
|
||||||
|
|
||||||
/* ************************************************ */
|
/* ************************************************ */
|
||||||
/* DRAWING API */
|
/* DRAWING API */
|
||||||
/* `anim_draw.cc` */
|
/* `anim_draw.cc` */
|
||||||
|
|||||||
@@ -67,8 +67,10 @@
|
|||||||
#include "WM_api.hh"
|
#include "WM_api.hh"
|
||||||
#include "WM_types.hh"
|
#include "WM_types.hh"
|
||||||
|
|
||||||
|
#include "ANIM_action.hh"
|
||||||
#include "ANIM_keyframing.hh"
|
#include "ANIM_keyframing.hh"
|
||||||
|
|
||||||
|
#include "ED_anim_api.hh"
|
||||||
#include "ED_armature.hh"
|
#include "ED_armature.hh"
|
||||||
#include "ED_keyframing.hh"
|
#include "ED_keyframing.hh"
|
||||||
#include "ED_mesh.hh"
|
#include "ED_mesh.hh"
|
||||||
@@ -341,6 +343,10 @@ static int object_clear_transform_generic_exec(bContext *C,
|
|||||||
/* get KeyingSet to use */
|
/* get KeyingSet to use */
|
||||||
ks = ANIM_get_keyingset_for_autokeying(scene, default_ksName);
|
ks = ANIM_get_keyingset_for_autokeying(scene, default_ksName);
|
||||||
|
|
||||||
|
if (blender::animrig::is_autokey_on(scene)) {
|
||||||
|
ANIM_deselect_keys_in_animation_editors(C);
|
||||||
|
}
|
||||||
|
|
||||||
for (Object *ob : objects) {
|
for (Object *ob : objects) {
|
||||||
if (use_transform_data_origin) {
|
if (use_transform_data_origin) {
|
||||||
data_xform_container_item_ensure(xds, ob);
|
data_xform_container_item_ensure(xds, ob);
|
||||||
|
|||||||
@@ -975,6 +975,8 @@ static int actkeys_insertkey_exec(bContext *C, wmOperator *op)
|
|||||||
/* what channels to affect? */
|
/* what channels to affect? */
|
||||||
mode = RNA_enum_get(op->ptr, "type");
|
mode = RNA_enum_get(op->ptr, "type");
|
||||||
|
|
||||||
|
ANIM_deselect_keys_in_animation_editors(C);
|
||||||
|
|
||||||
/* insert keyframes */
|
/* insert keyframes */
|
||||||
insert_action_keys(&ac, mode);
|
insert_action_keys(&ac, mode);
|
||||||
|
|
||||||
|
|||||||
@@ -258,6 +258,8 @@ static int graphkeys_insertkey_exec(bContext *C, wmOperator *op)
|
|||||||
return OPERATOR_CANCELLED;
|
return OPERATOR_CANCELLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ANIM_deselect_keys_in_animation_editors(C);
|
||||||
|
|
||||||
/* Which channels to affect? */
|
/* Which channels to affect? */
|
||||||
mode = eGraphKeys_InsertKey_Types(RNA_enum_get(op->ptr, "type"));
|
mode = eGraphKeys_InsertKey_Types(RNA_enum_get(op->ptr, "type"));
|
||||||
|
|
||||||
|
|||||||
@@ -41,12 +41,14 @@
|
|||||||
#include "RNA_access.hh"
|
#include "RNA_access.hh"
|
||||||
#include "RNA_define.hh"
|
#include "RNA_define.hh"
|
||||||
|
|
||||||
|
#include "ED_anim_api.hh"
|
||||||
#include "ED_curves.hh"
|
#include "ED_curves.hh"
|
||||||
#include "ED_keyframing.hh"
|
#include "ED_keyframing.hh"
|
||||||
#include "ED_object.hh"
|
#include "ED_object.hh"
|
||||||
#include "ED_screen.hh"
|
#include "ED_screen.hh"
|
||||||
#include "ED_transverts.hh"
|
#include "ED_transverts.hh"
|
||||||
|
|
||||||
|
#include "ANIM_action.hh"
|
||||||
#include "ANIM_bone_collections.hh"
|
#include "ANIM_bone_collections.hh"
|
||||||
#include "ANIM_keyframing.hh"
|
#include "ANIM_keyframing.hh"
|
||||||
|
|
||||||
@@ -190,9 +192,11 @@ static int snap_sel_to_grid_exec(bContext *C, wmOperator *op)
|
|||||||
|
|
||||||
/* Build object array. */
|
/* Build object array. */
|
||||||
Vector<Object *> objects_eval;
|
Vector<Object *> objects_eval;
|
||||||
|
Vector<Object *> objects_orig;
|
||||||
{
|
{
|
||||||
FOREACH_SELECTED_EDITABLE_OBJECT_BEGIN (view_layer_eval, v3d, ob_eval) {
|
FOREACH_SELECTED_EDITABLE_OBJECT_BEGIN (view_layer_eval, v3d, ob_eval) {
|
||||||
objects_eval.append(ob_eval);
|
objects_eval.append(ob_eval);
|
||||||
|
objects_orig.append(DEG_get_original_object(ob_eval));
|
||||||
}
|
}
|
||||||
FOREACH_SELECTED_EDITABLE_OBJECT_END;
|
FOREACH_SELECTED_EDITABLE_OBJECT_END;
|
||||||
}
|
}
|
||||||
@@ -214,6 +218,10 @@ static int snap_sel_to_grid_exec(bContext *C, wmOperator *op)
|
|||||||
xds = object::data_xform_container_create();
|
xds = object::data_xform_container_create();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (blender::animrig::is_autokey_on(scene)) {
|
||||||
|
ANIM_deselect_keys_in_animation_editors(C);
|
||||||
|
}
|
||||||
|
|
||||||
for (Object *ob_eval : objects_eval) {
|
for (Object *ob_eval : objects_eval) {
|
||||||
Object *ob = DEG_get_original_object(ob_eval);
|
Object *ob = DEG_get_original_object(ob_eval);
|
||||||
vec[0] = -ob_eval->object_to_world().location()[0] +
|
vec[0] = -ob_eval->object_to_world().location()[0] +
|
||||||
@@ -502,6 +510,10 @@ static bool snap_selected_to_location(bContext *C,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (blender::animrig::is_autokey_on(scene)) {
|
||||||
|
ANIM_deselect_keys_in_animation_editors(C);
|
||||||
|
}
|
||||||
|
|
||||||
for (Object *ob : objects) {
|
for (Object *ob : objects) {
|
||||||
if (ob->parent && BKE_object_flag_test_recursive(ob->parent, OB_DONE)) {
|
if (ob->parent && BKE_object_flag_test_recursive(ob->parent, OB_DONE)) {
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -25,11 +25,13 @@
|
|||||||
|
|
||||||
#include "BIK_api.h"
|
#include "BIK_api.h"
|
||||||
|
|
||||||
|
#include "ED_anim_api.hh"
|
||||||
#include "ED_armature.hh"
|
#include "ED_armature.hh"
|
||||||
|
|
||||||
#include "DEG_depsgraph.hh"
|
#include "DEG_depsgraph.hh"
|
||||||
#include "DEG_depsgraph_query.hh"
|
#include "DEG_depsgraph_query.hh"
|
||||||
|
|
||||||
|
#include "ANIM_action.hh"
|
||||||
#include "ANIM_bone_collections.hh"
|
#include "ANIM_bone_collections.hh"
|
||||||
#include "ANIM_keyframing.hh"
|
#include "ANIM_keyframing.hh"
|
||||||
#include "ANIM_rna.hh"
|
#include "ANIM_rna.hh"
|
||||||
@@ -1660,6 +1662,18 @@ static void special_aftertrans_update__pose(bContext *C, TransInfo *t)
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const bool canceled = (t->state == TRANS_CANCEL);
|
const bool canceled = (t->state == TRANS_CANCEL);
|
||||||
|
|
||||||
|
if (blender::animrig::is_autokey_on(t->scene) && !canceled) {
|
||||||
|
blender::Vector<Object *> objects;
|
||||||
|
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
|
||||||
|
for (int i = 0; i < tc->data_len; i++) {
|
||||||
|
const TransData *td = &tc->data[i];
|
||||||
|
objects.append(td->ob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ANIM_deselect_keys_in_animation_editors(C);
|
||||||
|
}
|
||||||
|
|
||||||
GSet *motionpath_updates = BLI_gset_ptr_new("motionpath updates");
|
GSet *motionpath_updates = BLI_gset_ptr_new("motionpath updates");
|
||||||
|
|
||||||
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
|
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
|
||||||
|
|||||||
@@ -21,8 +21,11 @@
|
|||||||
#include "BKE_rigidbody.h"
|
#include "BKE_rigidbody.h"
|
||||||
#include "BKE_scene.hh"
|
#include "BKE_scene.hh"
|
||||||
|
|
||||||
|
#include "ANIM_action.hh"
|
||||||
#include "ANIM_keyframing.hh"
|
#include "ANIM_keyframing.hh"
|
||||||
#include "ANIM_rna.hh"
|
#include "ANIM_rna.hh"
|
||||||
|
|
||||||
|
#include "ED_anim_api.hh"
|
||||||
#include "ED_object.hh"
|
#include "ED_object.hh"
|
||||||
|
|
||||||
#include "DEG_depsgraph_query.hh"
|
#include "DEG_depsgraph_query.hh"
|
||||||
@@ -904,6 +907,15 @@ static void special_aftertrans_update__object(bContext *C, TransInfo *t)
|
|||||||
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
|
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
|
||||||
bool motionpath_update = false;
|
bool motionpath_update = false;
|
||||||
|
|
||||||
|
if (blender::animrig::is_autokey_on(t->scene) && !canceled) {
|
||||||
|
blender::Vector<Object *> objects;
|
||||||
|
for (int i = 0; i < tc->data_len; i++) {
|
||||||
|
const TransData *td = &tc->data[i];
|
||||||
|
objects.append(td->ob);
|
||||||
|
}
|
||||||
|
ANIM_deselect_keys_in_animation_editors(C);
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < tc->data_len; i++) {
|
for (int i = 0; i < tc->data_len; i++) {
|
||||||
TransData *td = tc->data + i;
|
TransData *td = tc->data + i;
|
||||||
ListBase pidlist;
|
ListBase pidlist;
|
||||||
|
|||||||
@@ -859,6 +859,12 @@ static void rna_Action_end_frame_set(PointerRNA *ptr, float value)
|
|||||||
CLAMP_MAX(data->frame_start, data->frame_end);
|
CLAMP_MAX(data->frame_start, data->frame_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void rna_Action_deselect_keys(bAction *act)
|
||||||
|
{
|
||||||
|
animrig::action_deselect_keys(act->wrap());
|
||||||
|
WM_main_add_notifier(NC_ANIMATION | ND_KEYFRAME | NA_EDITED, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
/* Used to check if an action (value pointer)
|
/* Used to check if an action (value pointer)
|
||||||
* is suitable to be assigned to the ID-block that is ptr. */
|
* is suitable to be assigned to the ID-block that is ptr. */
|
||||||
bool rna_Action_id_poll(PointerRNA *ptr, PointerRNA value)
|
bool rna_Action_id_poll(PointerRNA *ptr, PointerRNA value)
|
||||||
@@ -2092,6 +2098,10 @@ static void rna_def_action(BlenderRNA *brna)
|
|||||||
RNA_def_property_float_funcs(prop, "rna_Action_curve_frame_range_get", nullptr, nullptr);
|
RNA_def_property_float_funcs(prop, "rna_Action_curve_frame_range_get", nullptr, nullptr);
|
||||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||||
|
|
||||||
|
FunctionRNA *func = RNA_def_function(srna, "deselect_keys", "rna_Action_deselect_keys");
|
||||||
|
RNA_def_function_ui_description(
|
||||||
|
func, "Deselects all keys of the Action. The selection status of F-Curves is unchanged");
|
||||||
|
|
||||||
rna_def_action_legacy(brna, srna);
|
rna_def_action_legacy(brna, srna);
|
||||||
|
|
||||||
/* API calls */
|
/* API calls */
|
||||||
|
|||||||
@@ -178,6 +178,19 @@ class InsertKeyTest(AbstractKeyframingTest, unittest.TestCase):
|
|||||||
_fcurve_paths_match(keyed_object.animation_data.action.fcurves, keyed_rna_paths)
|
_fcurve_paths_match(keyed_object.animation_data.action.fcurves, keyed_rna_paths)
|
||||||
bpy.data.objects.remove(keyed_object, do_unlink=True)
|
bpy.data.objects.remove(keyed_object, do_unlink=True)
|
||||||
|
|
||||||
|
def test_key_selection_state(self):
|
||||||
|
keyed_object = _create_animation_object()
|
||||||
|
bpy.context.preferences.edit.key_insert_channels = {"LOCATION"}
|
||||||
|
with bpy.context.temp_override(**_get_view3d_context()):
|
||||||
|
bpy.ops.anim.keyframe_insert()
|
||||||
|
bpy.context.scene.frame_set(5)
|
||||||
|
bpy.ops.anim.keyframe_insert()
|
||||||
|
|
||||||
|
for fcurve in keyed_object.animation_data.action.fcurves:
|
||||||
|
self.assertEqual(len(fcurve.keyframe_points), 2)
|
||||||
|
self.assertFalse(fcurve.keyframe_points[0].select_control_point)
|
||||||
|
self.assertTrue(fcurve.keyframe_points[1].select_control_point)
|
||||||
|
|
||||||
|
|
||||||
class VisualKeyingTest(AbstractKeyframingTest, unittest.TestCase):
|
class VisualKeyingTest(AbstractKeyframingTest, unittest.TestCase):
|
||||||
""" Check if visual keying produces the correct keyframe values. """
|
""" Check if visual keying produces the correct keyframe values. """
|
||||||
@@ -368,6 +381,20 @@ class AutoKeyframingTest(AbstractKeyframingTest, unittest.TestCase):
|
|||||||
expected_paths = [f"{bone_path}.location", f"{bone_path}.rotation_euler", f"{bone_path}.scale"]
|
expected_paths = [f"{bone_path}.location", f"{bone_path}.rotation_euler", f"{bone_path}.scale"]
|
||||||
_fcurve_paths_match(action.fcurves, expected_paths)
|
_fcurve_paths_match(action.fcurves, expected_paths)
|
||||||
|
|
||||||
|
def test_key_selection_state(self):
|
||||||
|
armature_obj = _create_armature()
|
||||||
|
bpy.ops.object.mode_set(mode='POSE')
|
||||||
|
bpy.ops.transform.translate(value=(1, 0, 0))
|
||||||
|
bpy.context.scene.frame_set(5)
|
||||||
|
bpy.ops.transform.translate(value=(0, 1, 0))
|
||||||
|
bpy.ops.object.mode_set(mode='OBJECT')
|
||||||
|
|
||||||
|
action = armature_obj.animation_data.action
|
||||||
|
for fcurve in action.fcurves:
|
||||||
|
self.assertEqual(len(fcurve.keyframe_points), 2)
|
||||||
|
self.assertFalse(fcurve.keyframe_points[0].select_control_point)
|
||||||
|
self.assertTrue(fcurve.keyframe_points[1].select_control_point)
|
||||||
|
|
||||||
|
|
||||||
class InsertAvailableTest(AbstractKeyframingTest, unittest.TestCase):
|
class InsertAvailableTest(AbstractKeyframingTest, unittest.TestCase):
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user