Anim: When assigning an Action, auto-assign slot if it was never used
When assigning an Action, and it has only one slot that has never been assigned to anything before, auto-assign that slot. This is the last option for the slot auto-selection. It is in place mostly for backward compatibility in the following situation: - Python script creates a new Action, and adds F-Curves via the legacy API `action.fcurves.new(...)`. This automatically creates a slot with `id_type = 0`, indicating it is not yet bound to any ID type. - The script assigns the Action to a data-block. In this case the implicitly created slot is automatically assigned, and thus the data-block is animated by the F-Curves created through the legacy API. Pull Request: https://projects.blender.org/blender/blender/pulls/128892
This commit is contained in:
@@ -559,6 +559,10 @@ Slot *Action::find_suitable_slot_for(const ID &animated_id)
|
||||
{
|
||||
AnimData *adt = BKE_animdata_from_id(&animated_id);
|
||||
|
||||
/* The slot-finding code in assign_action_ensure_slot_for_keying() is very
|
||||
* similar to the code here (differences are documented there). It is very
|
||||
* likely that changes in the logic here should be applied there as well. */
|
||||
|
||||
/* The slot handle is only valid when this action has already been
|
||||
* assigned. Otherwise it's meaningless. */
|
||||
if (adt && adt->action == this) {
|
||||
@@ -576,10 +580,20 @@ Slot *Action::find_suitable_slot_for(const ID &animated_id)
|
||||
}
|
||||
}
|
||||
|
||||
/* As a last resort, search for the ID name. */
|
||||
Slot *slot = this->slot_find_by_name(animated_id.name);
|
||||
if (slot && slot->is_suitable_for(animated_id)) {
|
||||
return slot;
|
||||
/* Search for the ID name (which includes the ID type). */
|
||||
{
|
||||
Slot *slot = this->slot_find_by_name(animated_id.name);
|
||||
if (slot && slot->is_suitable_for(animated_id)) {
|
||||
return slot;
|
||||
}
|
||||
}
|
||||
|
||||
/* If there is only one slot, and it has never been assigned to anything, use that. */
|
||||
if (this->slots().size() == 1) {
|
||||
Slot *slot = this->slot(0);
|
||||
if (!slot->has_idtype()) {
|
||||
return slot;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
@@ -1199,13 +1213,12 @@ bool unassign_action(OwnedAnimData owned_adt)
|
||||
|
||||
Slot *assign_action_ensure_slot_for_keying(Action &action, ID &animated_id)
|
||||
{
|
||||
AnimData *adt = BKE_animdata_from_id(&animated_id);
|
||||
Slot *slot;
|
||||
|
||||
/* Find a suitable slot, but be stricter when to allow searching by name than
|
||||
* action.find_suitable_slot_for(animated_id). */
|
||||
{
|
||||
AnimData *adt = BKE_animdata_from_id(&animated_id);
|
||||
|
||||
if (adt && adt->action == &action) {
|
||||
/* The slot handle is only valid when this action is already assigned.
|
||||
* Otherwise it's meaningless. */
|
||||
@@ -1220,25 +1233,36 @@ Slot *assign_action_ensure_slot_for_keying(Action &action, ID &animated_id)
|
||||
slot = action.slot_find_by_name(adt->slot_name);
|
||||
}
|
||||
else {
|
||||
/* As a last resort, search for the ID name. */
|
||||
/* Search for the ID name (which includes the ID type). */
|
||||
slot = action.slot_find_by_name(animated_id.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* As a last resort, if there is only one slot and it has no ID type yet, use
|
||||
* that. This is what gets created for the backwards compatibility RNA API,
|
||||
* for example to allow `action.fcurves.new()`. Key insertion should use that
|
||||
* slot as well. */
|
||||
if (!slot && action.slots().size() == 1) {
|
||||
Slot *first_slot = action.slot(0);
|
||||
if (!first_slot->has_idtype()) {
|
||||
slot = first_slot;
|
||||
}
|
||||
}
|
||||
|
||||
/* If no suitable slot was found, create a new one. */
|
||||
if (!slot || !slot->is_suitable_for(animated_id)) {
|
||||
slot = &action.slot_add_for_id(animated_id);
|
||||
}
|
||||
|
||||
/* Only try to assign the Action to the ID if it is not already assigned.
|
||||
* Assignment can fail when the ID is in NLA Tweak mode. */
|
||||
const std::optional<std::pair<Action *, Slot *>> assigned = get_action_slot_pair(animated_id);
|
||||
const bool is_correct_action = assigned && assigned->first == &action;
|
||||
const bool is_correct_action = adt && adt->action == &action;
|
||||
if (!is_correct_action && !assign_action(&action, animated_id)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const bool is_correct_slot = assigned && assigned->second == slot;
|
||||
const bool is_correct_slot = adt && adt->slot_handle == slot->handle;
|
||||
if (!is_correct_slot && assign_action_slot(slot, animated_id) != ActionSlotAssignmentResult::OK)
|
||||
{
|
||||
/* This should never happen, as a few lines above a new slot is created for
|
||||
|
||||
Reference in New Issue
Block a user